<commit_before>//! Setup and control loop devices.
//!
//! Provides rust interface with similar functionality to the Linux utility `losetup`.
//!
//! # Examples
//!
//! ```rust
//! use loopdev::LoopControl;
//! let lc = LoopControl::open().unwrap();
//! let ld = lc.next_free().unwrap();
//!
//! println!("{}", ld.path().unwrap().display());
//!
//! ld.attach_file("test.img").unwrap();
//! // ...
//! ld.detach().unwrap();
//! ```

extern crate libc;

use std::fs::File;
use std::fs::OpenOptions;

use libc::{c_int, ioctl};
use std::default::Default;
use std::io;
use std::os::unix::prelude::*;
use std::path::{Path, PathBuf};

// TODO support missing operations
const LOOP_SET_FD: u16 = 0x4C00;
const LOOP_CLR_FD: u16 = 0x4C01;
const LOOP_SET_STATUS64: u16 = 0x4C04;
//const LOOP_GET_STATUS64: u16 = 0x4C05;
const LOOP_SET_CAPACITY: u16 = 0x4C07;
//const LOOP_SET_DIRECT_IO: u16 = 0x4C08;
//const LOOP_SET_BLOCK_SIZE: u16 = 0x4C09;

//const LOOP_CTL_ADD: u16 = 0x4C80;
//const LOOP_CTL_REMOVE: u16 = 0x4C81;
const LOOP_CTL_GET_FREE: u16 = 0x4C82;

const LOOP_CONTROL: &str = "/dev/loop-control";
const LOOP_PREFIX: &str = "/dev/loop";

/// Interface to the loop control device: `/dev/loop-control`.
#[derive(Debug)]
pub struct LoopControl {
    dev_file: File,
}

impl LoopControl {
    /// Opens the loop control device.
    pub fn open() -> io::Result<Self> {
        Ok(Self {
            dev_file: OpenOptions::new()
                .read(true)
                .write(true)
                .open(LOOP_CONTROL)?,
        })
    }

    /// Finds and opens the next available loop device.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use loopdev::LoopControl;
    /// let lc = LoopControl::open().unwrap();
    /// let ld = lc.next_free().unwrap();
    /// println!("{}", ld.path().unwrap().display());
    /// ```
    pub fn next_free(&self) -> io::Result<LoopDevice> {
        let dev_num = ioctl_to_error(unsafe {
            ioctl(self.dev_file.as_raw_fd() as c_int, LOOP_CTL_GET_FREE.into())
        })?;
        LoopDevice::open(&format!("{}{}", LOOP_PREFIX, dev_num))
    }
}

/// Interface to a loop device ie `/dev/loop0`.
#[derive(Debug)]
pub struct LoopDevice {
    device: File,
}

impl AsRawFd for LoopDevice {
    fn as_raw_fd(&self) -> RawFd {
        self.device.as_raw_fd()
    }
}

impl LoopDevice {
    /// Opens a loop device.
    pub fn open<P: AsRef<Path>>(dev: P) -> io::Result<Self> {
        // TODO create dev if it does not exist and begins with LOOP_PREFIX
        Ok(Self {
            device: OpenOptions::new().read(true).write(true).open(dev)?,
        })
    }

    /// Attach the loop device to a file starting at offset into the file.
    #[deprecated(
        since = "0.2.0",
        note = "use `attach_file` or `attach_with_offset` instead"
    )]
    pub fn attach<P: AsRef<Path>>(&self, backing_file: P, offset: u64) -> io::Result<()> {
        self.attach_with_sizelimit(backing_file, offset, 0)
    }

    /// Attach the loop device to a file that maps to the whole file.
    ///
    /// # Examples
    ///
    /// Attach the device to a file.
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop4").unwrap();
    /// ld.attach_file("test.img").unwrap();
    /// # ld.detach().unwrap();
    /// ```
    pub fn attach_file<P: AsRef<Path>>(&self, backing_file: P) -> io::Result<()> {
        self.attach_with_sizelimit(backing_file, 0, 0)
    }

    /// Attach the loop device to a file starting at offset into the file.
    ///
    /// # Examples
    ///
    /// Attach the device to the start of a file.
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop5").unwrap();
    /// ld.attach_with_offset("test.img", 0).unwrap();
    /// # ld.detach().unwrap();
    /// ```
    pub fn attach_with_offset<P: AsRef<Path>>(
        &self,
        backing_file: P,
        offset: u64,
    ) -> io::Result<()> {
        self.attach_with_sizelimit(backing_file, offset, 0)
    }

    /// Attach the loop device to a file starting at offset into the file and a the given sizelimit.
    ///
    /// # Examples
    ///
    /// Attach the device to the start of a file with a maximum size of 1024 bytes.
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop6").unwrap();
    /// ld.attach_with_sizelimit("test.img", 0, 1024).unwrap();
    /// # ld.detach().unwrap();
    /// ```
    pub fn attach_with_sizelimit<P: AsRef<Path>>(
        &self,
        backing_file: P,
        offset: u64,
        sizelimit: u64,
    ) -> io::Result<()> {
        let bf = OpenOptions::new()
            .read(true)
            .write(true)
            .open(backing_file)?;

        // Attach the file
        ioctl_to_error(unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_FD.into(),
                bf.as_raw_fd() as c_int,
            )
        })?;

        // Set offset for backing_file
        let mut info = loop_info64::default();
        info.lo_offset = offset;
        info.lo_sizelimit = sizelimit;

        if let Err(err) = ioctl_to_error(unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_STATUS64.into(),
                &mut info,
            )
        }) {
            // Ignore the error to preserve the original error
            let _ = self.detach();
            return Err(err);
        }
        Ok(())
    }

    /// Get the path of the loop device.
    #[deprecated(since = "0.2.0", note = "use `path` instead")]
    pub fn get_path(&self) -> Option<PathBuf> {
        self.path()
    }

    /// Get the path of the loop device.
    pub fn path(&self) -> Option<PathBuf> {
        let mut p = PathBuf::from("/proc/self/fd");
        p.push(self.device.as_raw_fd().to_string());
        std::fs::read_link(&p).ok()
    }

    /// Detach a loop device from its backing file.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop7").unwrap();
    /// # ld.attach_file("test.img").unwrap();
    /// ld.detach().unwrap();
    /// ```
    pub fn detach(&self) -> io::Result<()> {
        ioctl_to_error(unsafe { ioctl(self.device.as_raw_fd() as c_int, LOOP_CLR_FD.into(), 0) })?;
        Ok(())
    }

    /// Resize a live loop device. If the size of the backing file changes this can be called to
    /// inform the loop driver about the new size.
    pub fn set_capacity(&self) -> io::Result<()> {
        ioctl_to_error(unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_CAPACITY.into(),
                0,
            )
        })?;
        Ok(())
    }
}

#[repr(C)]
struct loop_info64 {
    pub lo_device: u64,
    pub lo_inode: u64,
    pub lo_rdevice: u64,
    pub lo_offset: u64,
    pub lo_sizelimit: u64,
    pub lo_number: u32,
    pub lo_encrypt_type: u32,
    pub lo_encrypt_key_size: u32,
    pub lo_flags: u32,
    pub lo_file_name: [u8; 64],
    pub lo_crypt_name: [u8; 64],
    pub lo_encrypt_key: [u8; 32],
    pub lo_init: [u64; 2],
}

impl Default for loop_info64 {
    fn default() -> Self {
        Self {
            lo_device: 0,
            lo_inode: 0,
            lo_rdevice: 0,
            lo_offset: 0,
            lo_sizelimit: 0,
            lo_number: 0,
            lo_encrypt_type: 0,
            lo_encrypt_key_size: 0,
            lo_flags: 0,
            lo_file_name: [0; 64],
            lo_crypt_name: [0; 64],
            lo_encrypt_key: [0; 32],
            lo_init: [0; 2],
        }
    }
}

fn ioctl_to_error(ret: i32) -> io::Result<i32> {
    if ret < 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(ret)
    }
}
<commit_msg>Adds a note to the detach doc block<commit_after>//! Setup and control loop devices.
//!
//! Provides rust interface with similar functionality to the Linux utility `losetup`.
//!
//! # Examples
//!
//! ```rust
//! use loopdev::LoopControl;
//! let lc = LoopControl::open().unwrap();
//! let ld = lc.next_free().unwrap();
//!
//! println!("{}", ld.path().unwrap().display());
//!
//! ld.attach_file("test.img").unwrap();
//! // ...
//! ld.detach().unwrap();
//! ```

extern crate libc;

use std::fs::File;
use std::fs::OpenOptions;

use libc::{c_int, ioctl};
use std::default::Default;
use std::io;
use std::os::unix::prelude::*;
use std::path::{Path, PathBuf};

// TODO support missing operations
const LOOP_SET_FD: u16 = 0x4C00;
const LOOP_CLR_FD: u16 = 0x4C01;
const LOOP_SET_STATUS64: u16 = 0x4C04;
//const LOOP_GET_STATUS64: u16 = 0x4C05;
const LOOP_SET_CAPACITY: u16 = 0x4C07;
//const LOOP_SET_DIRECT_IO: u16 = 0x4C08;
//const LOOP_SET_BLOCK_SIZE: u16 = 0x4C09;

//const LOOP_CTL_ADD: u16 = 0x4C80;
//const LOOP_CTL_REMOVE: u16 = 0x4C81;
const LOOP_CTL_GET_FREE: u16 = 0x4C82;

const LOOP_CONTROL: &str = "/dev/loop-control";
const LOOP_PREFIX: &str = "/dev/loop";

/// Interface to the loop control device: `/dev/loop-control`.
#[derive(Debug)]
pub struct LoopControl {
    dev_file: File,
}

impl LoopControl {
    /// Opens the loop control device.
    pub fn open() -> io::Result<Self> {
        Ok(Self {
            dev_file: OpenOptions::new()
                .read(true)
                .write(true)
                .open(LOOP_CONTROL)?,
        })
    }

    /// Finds and opens the next available loop device.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use loopdev::LoopControl;
    /// let lc = LoopControl::open().unwrap();
    /// let ld = lc.next_free().unwrap();
    /// println!("{}", ld.path().unwrap().display());
    /// ```
    pub fn next_free(&self) -> io::Result<LoopDevice> {
        let dev_num = ioctl_to_error(unsafe {
            ioctl(self.dev_file.as_raw_fd() as c_int, LOOP_CTL_GET_FREE.into())
        })?;
        LoopDevice::open(&format!("{}{}", LOOP_PREFIX, dev_num))
    }
}

/// Interface to a loop device ie `/dev/loop0`.
#[derive(Debug)]
pub struct LoopDevice {
    device: File,
}

impl AsRawFd for LoopDevice {
    fn as_raw_fd(&self) -> RawFd {
        self.device.as_raw_fd()
    }
}

impl LoopDevice {
    /// Opens a loop device.
    pub fn open<P: AsRef<Path>>(dev: P) -> io::Result<Self> {
        // TODO create dev if it does not exist and begins with LOOP_PREFIX
        Ok(Self {
            device: OpenOptions::new().read(true).write(true).open(dev)?,
        })
    }

    /// Attach the loop device to a file starting at offset into the file.
    #[deprecated(
        since = "0.2.0",
        note = "use `attach_file` or `attach_with_offset` instead"
    )]
    pub fn attach<P: AsRef<Path>>(&self, backing_file: P, offset: u64) -> io::Result<()> {
        self.attach_with_sizelimit(backing_file, offset, 0)
    }

    /// Attach the loop device to a file that maps to the whole file.
    ///
    /// # Examples
    ///
    /// Attach the device to a file.
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop4").unwrap();
    /// ld.attach_file("test.img").unwrap();
    /// # ld.detach().unwrap();
    /// ```
    pub fn attach_file<P: AsRef<Path>>(&self, backing_file: P) -> io::Result<()> {
        self.attach_with_sizelimit(backing_file, 0, 0)
    }

    /// Attach the loop device to a file starting at offset into the file.
    ///
    /// # Examples
    ///
    /// Attach the device to the start of a file.
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop5").unwrap();
    /// ld.attach_with_offset("test.img", 0).unwrap();
    /// # ld.detach().unwrap();
    /// ```
    pub fn attach_with_offset<P: AsRef<Path>>(
        &self,
        backing_file: P,
        offset: u64,
    ) -> io::Result<()> {
        self.attach_with_sizelimit(backing_file, offset, 0)
    }

    /// Attach the loop device to a file starting at offset into the file and a the given sizelimit.
    ///
    /// # Examples
    ///
    /// Attach the device to the start of a file with a maximum size of 1024 bytes.
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop6").unwrap();
    /// ld.attach_with_sizelimit("test.img", 0, 1024).unwrap();
    /// # ld.detach().unwrap();
    /// ```
    pub fn attach_with_sizelimit<P: AsRef<Path>>(
        &self,
        backing_file: P,
        offset: u64,
        sizelimit: u64,
    ) -> io::Result<()> {
        let bf = OpenOptions::new()
            .read(true)
            .write(true)
            .open(backing_file)?;

        // Attach the file
        ioctl_to_error(unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_FD.into(),
                bf.as_raw_fd() as c_int,
            )
        })?;

        // Set offset for backing_file
        let mut info = loop_info64::default();
        info.lo_offset = offset;
        info.lo_sizelimit = sizelimit;

        if let Err(err) = ioctl_to_error(unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_STATUS64.into(),
                &mut info,
            )
        }) {
            // Ignore the error to preserve the original error
            let _ = self.detach();
            return Err(err);
        }
        Ok(())
    }

    /// Get the path of the loop device.
    #[deprecated(since = "0.2.0", note = "use `path` instead")]
    pub fn get_path(&self) -> Option<PathBuf> {
        self.path()
    }

    /// Get the path of the loop device.
    pub fn path(&self) -> Option<PathBuf> {
        let mut p = PathBuf::from("/proc/self/fd");
        p.push(self.device.as_raw_fd().to_string());
        std::fs::read_link(&p).ok()
    }

    /// Detach a loop device from its backing file.
    ///
    /// Note that the device won't fully detach until a short delay after the underling device file
    /// gets closed. This happens when LoopDev goes out of scope so you should ensure the LoopDev
    /// lives for a short a time as possible.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop7").unwrap();
    /// # ld.attach_file("test.img").unwrap();
    /// ld.detach().unwrap();
    /// ```
    pub fn detach(&self) -> io::Result<()> {
        ioctl_to_error(unsafe { ioctl(self.device.as_raw_fd() as c_int, LOOP_CLR_FD.into(), 0) })?;
        Ok(())
    }

    /// Resize a live loop device. If the size of the backing file changes this can be called to
    /// inform the loop driver about the new size.
    pub fn set_capacity(&self) -> io::Result<()> {
        ioctl_to_error(unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_CAPACITY.into(),
                0,
            )
        })?;
        Ok(())
    }
}

#[repr(C)]
struct loop_info64 {
    pub lo_device: u64,
    pub lo_inode: u64,
    pub lo_rdevice: u64,
    pub lo_offset: u64,
    pub lo_sizelimit: u64,
    pub lo_number: u32,
    pub lo_encrypt_type: u32,
    pub lo_encrypt_key_size: u32,
    pub lo_flags: u32,
    pub lo_file_name: [u8; 64],
    pub lo_crypt_name: [u8; 64],
    pub lo_encrypt_key: [u8; 32],
    pub lo_init: [u64; 2],
}

impl Default for loop_info64 {
    fn default() -> Self {
        Self {
            lo_device: 0,
            lo_inode: 0,
            lo_rdevice: 0,
            lo_offset: 0,
            lo_sizelimit: 0,
            lo_number: 0,
            lo_encrypt_type: 0,
            lo_encrypt_key_size: 0,
            lo_flags: 0,
            lo_file_name: [0; 64],
            lo_crypt_name: [0; 64],
            lo_encrypt_key: [0; 32],
            lo_init: [0; 2],
        }
    }
}

fn ioctl_to_error(ret: i32) -> io::Result<i32> {
    if ret < 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(ret)
    }
}
<|endoftext|>


<commit_before>use std::cmp;

// 2 billion junctions is good enough for now
pub type JunctionIndex = usize;
pub type Time = i64;
pub type Level = bool;

pub enum GateBehavior {
	And,
	Not,
	Or,
	Xor,
}

// In the future, at time "time", junction "junction" will be set to level "level".
#[derive (Clone, Copy)]
pub struct Signal {
	junction: JunctionIndex,
	level: Level,
	time: Time,
}

#[derive (Clone, Copy)]
pub struct Wire {
	input: JunctionIndex,
	output: JunctionIndex,
	delay: Time,
}

pub struct Gate {
	inputs: Vec <JunctionIndex>,
	output: JunctionIndex,
	behavior: GateBehavior,
}

pub struct World {
	// These don't change at runtime
	wires: Vec <Wire>,
	gates: Vec <Gate>,

	junctions: Vec <Level>,
	time: Time,
	signals: Vec <Signal>,
}

pub enum WorldCreationErr {
	// Two elements point to the same junction, this is illegal
	FanIn,
}

impl Wire {
	fn new (input: JunctionIndex, output: JunctionIndex, delay: Time) -> Wire {
		Wire {
			input: input,
			output: output,
			delay: delay,
		}
	}
}

impl World {
	pub fn new (wire_tuples: Vec <(JunctionIndex, JunctionIndex, Time)>, gates: Vec <Gate>) -> Result <World, WorldCreationErr> {
		let wires: Vec <Wire> = wire_tuples.iter ().map (|tuple| Wire::new (tuple.0, tuple.1, tuple.2)).collect ();

		let max_junction_wires = wires.iter ().fold (0, |max, wire| cmp::max (max, cmp::max (wire.input, wire.output)));
		let max_junction_gates = gates.iter ().fold (0, |max, gate| {
			let max_input = gate.inputs.iter ().max ();

			let max_junction_gate = match max_input {
				Option::Some (junction) => cmp::max (*junction, gate.output),
				Option::None => gate.output,
			};

			cmp::max (max, max_junction_gate)
		});

		let max_junction = cmp::max (max_junction_gates, max_junction_wires);
		let junction_count = max_junction + 1;

		let mut junction_has_input = vec! [false; junction_count];

		for wire in wires.iter () {
			if junction_has_input [wire.output] {
				return Err (WorldCreationErr::FanIn)
			}

			junction_has_input [wire.output] = true;
		}

		for gate in gates.iter () {
			if junction_has_input [gate.output] {
				return Err (WorldCreationErr::FanIn);
			}

			junction_has_input [gate.output] = true;
		}

		Ok (World {
			time: 0,
			signals: vec![],
			junctions: vec![false; junction_count],
			wires: wires,
			gates: gates,
		})
	}

	pub fn new_half_adder () -> World {
		World::new (
		vec![
			(0, 1, 4),
			(0, 5, 8),
			(2, 3, 4),
			(6, 7, 3),
			(8, 4, 8),
			(8, 9, 4),
		],
		vec![
			Gate {
				inputs: vec![1, 4],
				output: 2,
				behavior: GateBehavior::And,
			},
			Gate {
				inputs: vec![5, 9],
				output: 6,
				behavior: GateBehavior::Xor,
			},
		]).ok ().expect ("Half adder circuit is invalid")
	}

	pub fn new_full_adder () -> World {
		World::new (
		vec![
			(0, 3, 1),
			(0, 5, 1),
			(1, 4, 1),
			(1, 6, 1),
			(2, 11, 1),
			(2, 9, 1),
			(7, 10, 1),
			(7, 8, 1),
			(12, 14, 1),
			(13, 15, 1),
		],
		vec![
			Gate {
				inputs: vec![3, 4],
				output: 7,
				behavior: GateBehavior::Xor,
			},
			Gate {
				inputs: vec![10, 11],
				output: 16,
				behavior: GateBehavior::Xor,
			},
			Gate {
				inputs: vec![8, 9],
				output: 12,
				behavior: GateBehavior::And,
			},
			Gate {
				inputs: vec![5, 6],
				output: 13,
				behavior: GateBehavior::And,
			},
			Gate {
				inputs: vec![14, 15],
				output: 17,
				behavior: GateBehavior::Or,
			},
		]).ok ().expect ("Full adder circuit is invalid")
	}

	pub fn is_settled (& self) -> bool {
		self.signals.len () == 0
	}

	fn sort_signals (&mut self) {
		// This step is just a safety since we should be insertion sorting the delays already
		self.signals.sort_by (|a, b| a.time.cmp (&b.time));
	}

	fn step_gates (&mut self) {
		let mut new_signals = Vec::<Signal>::new ();

		// TODO: Optimize to only touch gates whose inputs have changed
		for gate in self.gates.iter () {
			let inputs: Vec <bool> = gate.inputs.iter ().map (|i| self.junctions [*i]).collect ();

			let output = match gate.behavior {
				GateBehavior::And => inputs.iter ().fold (true, |sum, a| sum && *a),
				GateBehavior::Not => ! inputs [0],
				GateBehavior::Or => inputs.iter ().fold (false, |sum, a| sum || *a),
				GateBehavior::Xor => inputs.iter ().fold (false, |sum, a| sum ^ *a),
			};

			let destiny_level = self.get_junction_destiny (gate.output);

			if destiny_level != output {
				new_signals.push (Signal {
					junction: gate.output,
					time: self.time,
					level: output,
				});
			}
		};

		// TODO: Proper insertion sorting
		// If the number of new signals is small compared to the number of
		// in-flight signals, I could do a few binary insertions sorts.
		// If the number is large, it might be better to do a mergesort.
		for signal in new_signals {
			self.signals.push (signal);
		}

		self.sort_signals ();
	}

	fn get_junction_destiny (& self, junction: JunctionIndex) -> Level {
		if self.signals.len () > 0 {
			// Find the last signal that was heading for that junction
			// Remember that junctions are not allowed to fan in
			for i in 0 .. self.signals.len () {
				let signals = self.signals [self.signals.len () - i - 1];

				if signals.junction == junction {
					return signals.level;
				}
			}
		}

		self.junctions [junction]
	}

	fn step_wires (&mut self) {
		for wire in self.wires.iter () {
			let input = self.junctions [wire.input];

			// Don't push redundant delays
			let destiny_level = self.get_junction_destiny (wire.output);

			if input != destiny_level {
				self.signals.push (Signal {
					junction: wire.output,
					time: self.time + wire.delay,
					level: input,
				});
			}
		};

		// TODO: Proper insertion sorting
		self.sort_signals ();
	}

	fn propagate_signals (&mut self) {
		let next_time = self.signals [0].time;

		for signal in self.signals.iter () {
			if signal.time == next_time {
				self.junctions [signal.junction] = signal.level;
			}
			else if signal.time > next_time {
				break;
			}
		}

		self.signals.retain (|signal| signal.time > next_time);

		self.time = next_time;
	}

	pub fn set_junction (&mut self, junction: JunctionIndex, level: Level) {
		self.signals.push (Signal {
			junction: junction,
			level: level,
			time: self.time,
		});
	}

	pub fn step (&mut self) {
		if self.is_settled () {
			return;
		}

		self.sort_signals ();

		self.propagate_signals ();

		self.step_gates ();
		self.step_wires ();
	}

	pub fn step_to_settled (&mut self) {
		while ! self.is_settled () {
			self.step ();
		}
	}
}

#[test]
pub fn test_fan_in () {
	let world_or_err = World::new (
		vec! [
		(0, 2, 1),
		(1, 2, 1),
		],
		vec! []
	);

	if let Err (WorldCreationErr::FanIn) = world_or_err {
		// Good
	}
	else {
		panic! ("World creation should have thrown a FanIn error");
	}
}

#[test]
pub fn test_half_adder () {
	let mut world = World::new_half_adder ();
	world.step_to_settled ();

	let assert_outputs = |world: &World, msb: Level, lsb: Level| {
		assert_eq! (world.junctions [3], msb);
		assert_eq! (world.junctions [7], lsb);
	};

	assert_outputs (&world, false, false);

	// Junctions 0 and 8 are the input bits

	world.set_junction (0, true);
	world.step_to_settled ();
	assert_outputs (&world, false, true);

	world.set_junction (8, true);
	world.step_to_settled ();
	assert_outputs (&world, true, false);

	world.set_junction (0, false);
	world.step_to_settled ();
	assert_outputs (&world, false, true);
}

#[test]
pub fn test_full_adder () {
	let mut world = World::new_full_adder ();
	world.step_to_settled ();

	let assert_outputs = |world: &mut World, a: Level, b: Level, c: Level, carry: Level, sum: Level| {
		world.set_junction (0, a);
		world.set_junction (1, b);
		world.set_junction (2, c);

		world.step_to_settled ();

		assert_eq! (world.junctions [17], carry);
		assert_eq! (world.junctions [16], sum);
	};

	// Truth table for a full adder
	assert_outputs (&mut world, false, false, false, false, false);
	assert_outputs (&mut world, false, false, true, false, true);
	assert_outputs (&mut world, false, true, true, true, false);
	assert_outputs (&mut world, false, true, false, false, true);

	assert_outputs (&mut world, true, true, false, true, false);
	assert_outputs (&mut world, true, true, true, true, true);
	assert_outputs (&mut world, true, false, true, true, false);
	assert_outputs (&mut world, true, false, false, false, true);
}
<commit_msg>Extracting a struct Circuit for static members of World<commit_after>use std::cmp;

// 2 billion junctions is good enough for now
pub type JunctionIndex = usize;
pub type Time = i64;
pub type Level = bool;

pub enum GateBehavior {
	And,
	Not,
	Or,
	Xor,
}

// In the future, at time "time", junction "junction" will be set to level "level".
#[derive (Clone, Copy)]
pub struct Signal {
	junction: JunctionIndex,
	level: Level,
	time: Time,
}

#[derive (Clone, Copy)]
pub struct Wire {
	input: JunctionIndex,
	output: JunctionIndex,
	delay: Time,
}

pub struct Gate {
	inputs: Vec <JunctionIndex>,
	output: JunctionIndex,
	behavior: GateBehavior,
}

pub struct Circuit {
	wires: Vec <Wire>,
	gates: Vec <Gate>,
}

pub struct World {
	// These don't change at runtime
	circuit: Circuit,

	junctions: Vec <Level>,
	time: Time,
	signals: Vec <Signal>,
}

pub enum WorldCreationErr {
	// Two elements point to the same junction, this is illegal
	FanIn,
}

impl Wire {
	fn new (input: JunctionIndex, output: JunctionIndex, delay: Time) -> Wire {
		Wire {
			input: input,
			output: output,
			delay: delay,
		}
	}
}

impl World {
	pub fn new (wire_tuples: Vec <(JunctionIndex, JunctionIndex, Time)>, gates: Vec <Gate>) -> Result <World, WorldCreationErr> {
		let wires: Vec <Wire> = wire_tuples.iter ().map (|tuple| Wire::new (tuple.0, tuple.1, tuple.2)).collect ();

		let max_junction_wires = wires.iter ().fold (0, |max, wire| cmp::max (max, cmp::max (wire.input, wire.output)));
		let max_junction_gates = gates.iter ().fold (0, |max, gate| {
			let max_input = gate.inputs.iter ().max ();

			let max_junction_gate = match max_input {
				Option::Some (junction) => cmp::max (*junction, gate.output),
				Option::None => gate.output,
			};

			cmp::max (max, max_junction_gate)
		});

		let max_junction = cmp::max (max_junction_gates, max_junction_wires);
		let junction_count = max_junction + 1;

		let mut junction_has_input = vec! [false; junction_count];

		for wire in wires.iter () {
			if junction_has_input [wire.output] {
				return Err (WorldCreationErr::FanIn)
			}

			junction_has_input [wire.output] = true;
		}

		for gate in gates.iter () {
			if junction_has_input [gate.output] {
				return Err (WorldCreationErr::FanIn);
			}

			junction_has_input [gate.output] = true;
		}

		Ok (World {
			time: 0,
			signals: vec![],
			junctions: vec![false; junction_count],
			circuit: Circuit {
				wires: wires,
				gates: gates,
			},
		})
	}

	pub fn new_half_adder () -> World {
		World::new (
		vec![
			(0, 1, 4),
			(0, 5, 8),
			(2, 3, 4),
			(6, 7, 3),
			(8, 4, 8),
			(8, 9, 4),
		],
		vec![
			Gate {
				inputs: vec![1, 4],
				output: 2,
				behavior: GateBehavior::And,
			},
			Gate {
				inputs: vec![5, 9],
				output: 6,
				behavior: GateBehavior::Xor,
			},
		]).ok ().expect ("Half adder circuit is invalid")
	}

	pub fn new_full_adder () -> World {
		World::new (
		vec![
			(0, 3, 1),
			(0, 5, 1),
			(1, 4, 1),
			(1, 6, 1),
			(2, 11, 1),
			(2, 9, 1),
			(7, 10, 1),
			(7, 8, 1),
			(12, 14, 1),
			(13, 15, 1),
		],
		vec![
			Gate {
				inputs: vec![3, 4],
				output: 7,
				behavior: GateBehavior::Xor,
			},
			Gate {
				inputs: vec![10, 11],
				output: 16,
				behavior: GateBehavior::Xor,
			},
			Gate {
				inputs: vec![8, 9],
				output: 12,
				behavior: GateBehavior::And,
			},
			Gate {
				inputs: vec![5, 6],
				output: 13,
				behavior: GateBehavior::And,
			},
			Gate {
				inputs: vec![14, 15],
				output: 17,
				behavior: GateBehavior::Or,
			},
		]).ok ().expect ("Full adder circuit is invalid")
	}

	pub fn is_settled (& self) -> bool {
		self.signals.len () == 0
	}

	fn sort_signals (&mut self) {
		// This step is just a safety since we should be insertion sorting the delays already
		self.signals.sort_by (|a, b| a.time.cmp (&b.time));
	}

	fn step_gates (&mut self) {
		let mut new_signals = Vec::<Signal>::new ();

		// TODO: Optimize to only touch gates whose inputs have changed
		for gate in self.circuit.gates.iter () {
			let inputs: Vec <bool> = gate.inputs.iter ().map (|i| self.junctions [*i]).collect ();

			let output = match gate.behavior {
				GateBehavior::And => inputs.iter ().fold (true, |sum, a| sum && *a),
				GateBehavior::Not => ! inputs [0],
				GateBehavior::Or => inputs.iter ().fold (false, |sum, a| sum || *a),
				GateBehavior::Xor => inputs.iter ().fold (false, |sum, a| sum ^ *a),
			};

			let destiny_level = self.get_junction_destiny (gate.output);

			if destiny_level != output {
				new_signals.push (Signal {
					junction: gate.output,
					time: self.time,
					level: output,
				});
			}
		};

		// TODO: Proper insertion sorting
		// If the number of new signals is small compared to the number of
		// in-flight signals, I could do a few binary insertions sorts.
		// If the number is large, it might be better to do a mergesort.
		for signal in new_signals {
			self.signals.push (signal);
		}

		self.sort_signals ();
	}

	fn get_junction_destiny (& self, junction: JunctionIndex) -> Level {
		if self.signals.len () > 0 {
			// Find the last signal that was heading for that junction
			// Remember that junctions are not allowed to fan in
			for i in 0 .. self.signals.len () {
				let signals = self.signals [self.signals.len () - i - 1];

				if signals.junction == junction {
					return signals.level;
				}
			}
		}

		self.junctions [junction]
	}

	fn step_wires (&mut self) {
		for wire in self.circuit.wires.iter () {
			let input = self.junctions [wire.input];

			// Don't push redundant delays
			let destiny_level = self.get_junction_destiny (wire.output);

			if input != destiny_level {
				self.signals.push (Signal {
					junction: wire.output,
					time: self.time + wire.delay,
					level: input,
				});
			}
		};

		// TODO: Proper insertion sorting
		self.sort_signals ();
	}

	fn propagate_signals (&mut self) {
		let next_time = self.signals [0].time;

		for signal in self.signals.iter () {
			if signal.time == next_time {
				self.junctions [signal.junction] = signal.level;
			}
			else if signal.time > next_time {
				break;
			}
		}

		self.signals.retain (|signal| signal.time > next_time);

		self.time = next_time;
	}

	pub fn set_junction (&mut self, junction: JunctionIndex, level: Level) {
		self.signals.push (Signal {
			junction: junction,
			level: level,
			time: self.time,
		});
	}

	pub fn step (&mut self) {
		if self.is_settled () {
			return;
		}

		self.sort_signals ();

		self.propagate_signals ();

		self.step_gates ();
		self.step_wires ();
	}

	pub fn step_to_settled (&mut self) {
		while ! self.is_settled () {
			self.step ();
		}
	}
}

#[test]
pub fn test_fan_in () {
	let world_or_err = World::new (
		vec! [
		(0, 2, 1),
		(1, 2, 1),
		],
		vec! []
	);

	if let Err (WorldCreationErr::FanIn) = world_or_err {
		// Good
	}
	else {
		panic! ("World creation should have thrown a FanIn error");
	}
}

#[test]
pub fn test_half_adder () {
	let mut world = World::new_half_adder ();
	world.step_to_settled ();

	let assert_outputs = |world: &World, msb: Level, lsb: Level| {
		assert_eq! (world.junctions [3], msb);
		assert_eq! (world.junctions [7], lsb);
	};

	assert_outputs (&world, false, false);

	// Junctions 0 and 8 are the input bits

	world.set_junction (0, true);
	world.step_to_settled ();
	assert_outputs (&world, false, true);

	world.set_junction (8, true);
	world.step_to_settled ();
	assert_outputs (&world, true, false);

	world.set_junction (0, false);
	world.step_to_settled ();
	assert_outputs (&world, false, true);
}

#[test]
pub fn test_full_adder () {
	let mut world = World::new_full_adder ();
	world.step_to_settled ();

	let assert_outputs = |world: &mut World, a: Level, b: Level, c: Level, carry: Level, sum: Level| {
		world.set_junction (0, a);
		world.set_junction (1, b);
		world.set_junction (2, c);

		world.step_to_settled ();

		assert_eq! (world.junctions [17], carry);
		assert_eq! (world.junctions [16], sum);
	};

	// Truth table for a full adder
	assert_outputs (&mut world, false, false, false, false, false);
	assert_outputs (&mut world, false, false, true, false, true);
	assert_outputs (&mut world, false, true, true, true, false);
	assert_outputs (&mut world, false, true, false, false, true);

	assert_outputs (&mut world, true, true, false, true, false);
	assert_outputs (&mut world, true, true, true, true, true);
	assert_outputs (&mut world, true, false, true, true, false);
	assert_outputs (&mut world, true, false, false, false, true);
}
<|endoftext|>


<commit_before>// Copyright 2015, Paul Osborne <osbpau@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/license/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option.  This file may not be copied, modified, or distributed
// except according to those terms.
//
// Portions of this implementation are based on work by Nat Pryce:
// https://github.com/npryce/rusty-pi/blob/master/src/pi/gpio.rs

#![crate_type = "lib"]
#![crate_name = "sysfs_gpio"]

//! GPIO access under Linux using the GPIO sysfs interface
//!
//! The methods exposed by this library are centered around
//! the `Pin` struct and map pretty directly the API exposed
//! by the kernel in syfs (https://www.kernel.org/doc/Documentation/gpio/sysfs.txt).
//!
//! # Examples
//!
//! Typical usage for systems where one wants to ensure that
//! the pins in use are unexported upon completion looks like
//! the following:
//!
//! ```no_run
//! extern crate sysfs_gpio;
//!
//! use sysfs_gpio::{Direction, Pin};
//! use std::thread::sleep_ms;
//!
//! fn main() {
//!     let my_led = Pin::new(127); // number depends on chip, etc.
//!     my_led.with_exported(|| {
//!         loop {
//!             my_led.set_value(0).unwrap();
//!             sleep_ms(200);
//!             my_led.set_value(1).unwrap();
//!             sleep_ms(200);
//!         }
//!     }).unwrap();
//! }
//! ```

extern crate nix;

use nix::sys::epoll::*;
use nix::unistd::close;

use std::io::prelude::*;
use std::os::unix::prelude::*;
use std::io::{self, SeekFrom};
use std::fs;
use std::fs::File;

mod error;
pub use error::Error;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Pin {
    pin_num: u64,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Direction {
    In,
    Out,
    High,
    Low,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Edge {
    NoInterrupt,
    RisingEdge,
    FallingEdge,
    BothEdges,
}

#[macro_export]
macro_rules! try_unexport {
    ($gpio:ident, $e:expr) => (match $e {
        Ok(res) => res,
        Err(e) => { try!($gpio.unexport()); return Err(e) },
    });
}

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

/// Flush up to max bytes from the provided files input buffer
///
/// Typically, one would just use seek() for this sort of thing,
/// but for certain files (e.g. in sysfs), you need to actually
/// read it.
fn flush_input_from_file(dev_file: &mut File, max: usize) -> io::Result<usize> {
    let mut s = String::with_capacity(max);
    dev_file.read_to_string(&mut s)
}

/// Get the pin value from the provided file
fn get_value_from_file(dev_file: &mut File) -> Result<u8> {
    let mut s = String::with_capacity(10);
    try!(dev_file.seek(SeekFrom::Start(0)));
    try!(dev_file.read_to_string(&mut s));
    match s[..1].parse::<u8>() {
        Ok(n) => Ok(n),
        Err(_) => Err(Error::Unexpected(format!("Unexpected value file contents: {:?}", s))),
    }
}

impl Pin {
    /// Write all of the provided contents to the specified devFile
    fn write_to_device_file(&self, dev_file_name: &str, value: &str) -> io::Result<()> {
        let gpio_path = format!("/sys/class/gpio/gpio{}/{}", self.pin_num, dev_file_name);
        let mut dev_file = try!(File::create(&gpio_path));
        try!(dev_file.write_all(value.as_bytes()));
        Ok(())
    }

    fn read_from_device_file(&self, dev_file_name: &str) -> io::Result<String> {
        let gpio_path = format!("/sys/class/gpio/gpio{}/{}", self.pin_num, dev_file_name);
        let mut dev_file = try!(File::open(&gpio_path));
        let mut s = String::new();
        try!(dev_file.read_to_string(&mut s));
        Ok(s)
    }

    /// Create a new Pin with the provided `pin_num`
    ///
    /// This function does not export the provided pin_num.
    pub fn new(pin_num: u64) -> Pin {
        Pin { pin_num: pin_num }
    }

    /// Run a closure with the GPIO exported
    ///
    /// Prior to the provided closure being executed, the GPIO
    /// will be exported.  After the closure execution is complete,
    /// the GPIO will be unexported.
    ///
    /// # Example
    ///
    /// ```no_run
    /// use sysfs_gpio::{Pin, Direction};
    ///
    /// let gpio = Pin::new(24);
    /// let res = gpio.with_exported(|| {
    ///     println!("At this point, the Pin is exported");
    ///     try!(gpio.set_direction(Direction::Low));
    ///     try!(gpio.set_value(1));
    ///     // ...
    ///     Ok(())
    /// });
    /// ```
    #[inline]
    pub fn with_exported<F: FnOnce() -> Result<()>>(&self, closure: F) -> Result<()> {

        try!(self.export());
        match closure() {
            Ok(()) => {
                try!(self.unexport());
                Ok(())
            }
            Err(err) => {
                try!(self.unexport());
                Err(err)
            }
        }
    }

    /// Export the GPIO
    ///
    /// This is equivalent to `echo N > /sys/class/gpio/export` with
    /// the exception that the case where the GPIO is already exported
    /// is not an error.
    ///
    /// # Errors
    ///
    /// The main cases in which this function will fail and return an
    /// error are the following:
    /// 1. The system does not support the GPIO sysfs interface
    /// 2. The requested GPIO is out of range and cannot be exported
    /// 3. The requested GPIO is in use by the kernel and cannot
    ///    be exported by use in userspace
    ///
    /// # Example
    /// ```no_run
    /// use sysfs_gpio::Pin;
    ///
    /// let gpio = Pin::new(24);
    /// match gpio.export() {
    ///     Ok(()) => println!("Gpio {} exported!", gpio.get_pin()),
    ///     Err(err) => println!("Gpio {} could not be exported: {}", gpio.get_pin(), err),
    /// }
    /// ```
    pub fn export(&self) -> Result<()> {
        if let Err(_) = fs::metadata(&format!("/sys/class/gpio/gpio{}", self.pin_num)) {
            let mut export_file = try!(File::create("/sys/class/gpio/export"));
            try!(export_file.write_all(format!("{}", self.pin_num).as_bytes()));
        }
        Ok(())
    }

    /// Unexport the GPIO
    ///
    /// This function will unexport the provided by from syfs if
    /// it is currently exported.  If the pin is not currently
    /// exported, it will return without error.  That is, whenever
    /// this function returns Ok, the GPIO is not exported.
    pub fn unexport(&self) -> Result<()> {
        if let Ok(_) = fs::metadata(&format!("/sys/class/gpio/gpio{}", self.pin_num)) {
            let mut unexport_file = try!(File::create("/sys/class/gpio/unexport"));
            try!(unexport_file.write_all(format!("{}", self.pin_num).as_bytes()));
        }
        Ok(())
    }

    /// Get the pin number for the Pin
    pub fn get_pin(&self) -> u64 {
        self.pin_num
    }

    /// Get the direction of the Pin
    pub fn get_direction(&self) -> Result<Direction> {
        match self.read_from_device_file("direction") {
            Ok(s) => {
                match s.trim() {
                    "in" => Ok(Direction::In),
                    "out" => Ok(Direction::Out),
                    "high" => Ok(Direction::High),
                    "low" => Ok(Direction::Low),
                    other => Err(Error::Unexpected(format!("direction file contents {}", other))),
                }
            }
            Err(e) => Err(::std::convert::From::from(e)),
        }
    }

    /// Set this GPIO as either an input or an output
    ///
    /// The basic values allowed here are `Direction::In` and
    /// `Direction::Out` which set the Pin as either an input
    /// or output respectively.  In addition to those, two
    /// additional settings of `Direction::High` and
    /// `Direction::Low`.  These both set the Pin as an output
    /// but do so with an initial value of high or low respectively.
    /// This allows for glitch-free operation.
    ///
    /// Note that this entry may not exist if the kernel does
    /// not support changing the direction of a pin in userspace.  If
    /// this is the case, you will get an error.
    pub fn set_direction(&self, dir: Direction) -> Result<()> {
        try!(self.write_to_device_file("direction",
                                       match dir {
                                           Direction::In => "in",
                                           Direction::Out => "out",
                                           Direction::High => "high",
                                           Direction::Low => "low",
                                       }));

        Ok(())
    }

    /// Get the value of the Pin (0 or 1)
    ///
    /// If successful, 1 will be returned if the pin is high
    /// and 0 will be returned if the pin is low (this may or may
    /// not match the signal level of the actual signal depending
    /// on the GPIO "active_low" entry).
    pub fn get_value(&self) -> Result<u8> {
        match self.read_from_device_file("value") {
            Ok(s) => {
                match s.trim() {
                    "1" => Ok(1),
                    "0" => Ok(0),
                    other => Err(Error::Unexpected(format!("value file contents {}", other))),
                }
            }
            Err(e) => Err(::std::convert::From::from(e)),
        }
    }

    /// Set the value of the Pin
    ///
    /// This will set the value of the pin either high or low.
    /// A 0 value will set the pin low and any other value will
    /// set the pin high (1 is typical).
    pub fn set_value(&self, value: u8) -> Result<()> {
        try!(self.write_to_device_file("value",
                                       match value {
                                           0 => "0",
                                           _ => "1",
                                       }));

        Ok(())
    }

    /// Get the currently configured edge for this pin
    ///
    /// This value will only be present if the Pin allows
    /// for interrupts.
    pub fn get_edge(&self) -> Result<Edge> {
        match self.read_from_device_file("edge") {
            Ok(s) => {
                match s.trim() {
                    "none" => Ok(Edge::NoInterrupt),
                    "rising" => Ok(Edge::RisingEdge),
                    "falling" => Ok(Edge::FallingEdge),
                    "both" => Ok(Edge::BothEdges),
                    other => Err(Error::Unexpected(format!("Unexpected file contents {}", other))),
                }
            }
            Err(e) => Err(::std::convert::From::from(e)),
        }
    }

    /// Set the edge on which this GPIO will trigger when polled
    ///
    /// The configured edge determines what changes to the Pin will
    /// result in `poll()` returning.  This call will return an Error
    /// if the pin does not allow interrupts.
    pub fn set_edge(&self, edge: Edge) -> Result<()> {
        try!(self.write_to_device_file("edge",
                                       match edge {
                                           Edge::NoInterrupt => "none",
                                           Edge::RisingEdge => "rising",
                                           Edge::FallingEdge => "falling",
                                           Edge::BothEdges => "both",
                                       }));

        Ok(())
    }

    /// Get a PinPoller object for this pin
    ///
    /// This pin poller object will register an interrupt with the
    /// kernel and allow you to poll() on it and receive notifications
    /// that an interrupt has occured with minimal delay.
    pub fn get_poller(&self) -> Result<PinPoller> {
        PinPoller::new(self.pin_num)
    }
}

#[derive(Debug)]
pub struct PinPoller {
    pin_num: u64,
    epoll_fd: RawFd,
    devfile: File,
}

impl PinPoller {
    /// Get the pin associated with this PinPoller
    ///
    /// Note that this will be a new Pin object with the
    /// proper pin number.
    pub fn get_pin(&self) -> Pin {
        Pin::new(self.pin_num)
    }

    /// Create a new PinPoller for the provided pin number
    pub fn new(pin_num: u64) -> Result<PinPoller> {
        let devfile: File = try!(File::open(&format!("/sys/class/gpio/gpio{}/value", pin_num)));
        let devfile_fd = devfile.as_raw_fd();
        let epoll_fd = try!(epoll_create());
        let events = EPOLLPRI | EPOLLET;
        let info = EpollEvent {
            events: events,
            data: 0u64,
        };

        match epoll_ctl(epoll_fd, EpollOp::EpollCtlAdd, devfile_fd, &info) {
            Ok(_) => {
                Ok(PinPoller {
                    pin_num: pin_num,
                    devfile: devfile,
                    epoll_fd: epoll_fd,
                })
            }
            Err(err) => {
                let _ = close(epoll_fd); // cleanup
                Err(::std::convert::From::from(err))
            }
        }
    }

    /// Block until an interrupt occurs
    ///
    /// This call will block until an interrupt occurs.  The types
    /// of interrupts which may result in this call returning
    /// may be configured by calling `set_edge()` prior to
    /// making this call.  This call makes use of epoll under the
    /// covers.  If it is desirable to poll on multiple GPIOs or
    /// other event source, you will need to implement that logic
    /// yourself.
    ///
    /// This function will return Some(value) of the pin if a change is
    /// detected or None if a timeout occurs.  Note that the value provided
    /// is the value of the pin as soon as we get to handling the interrupt
    /// in userspace.  Each time this function returns with a value, a change
    /// has occurred, but you could end up reading the same value multiple
    /// times as the value has changed back between when the interrupt
    /// occurred and the current time.
    pub fn poll(&mut self, timeout_ms: isize) -> Result<Option<u8>> {
        try!(flush_input_from_file(&mut self.devfile, 255));
        let dummy_event = EpollEvent {
            events: EPOLLPRI | EPOLLET,
            data: 0u64,
        };
        let mut events: [EpollEvent; 1] = [dummy_event];
        let cnt = try!(epoll_wait(self.epoll_fd, &mut events, timeout_ms));
        Ok(match cnt {
            0 => None, // timeout
            _ => Some(try!(get_value_from_file(&mut self.devfile))),
        })
    }
}

impl Drop for PinPoller {
    fn drop(&mut self) {
        // we implement drop to close the underlying epoll fd as
        // it does not implement drop itself.  This is similar to
        // how mio works
        close(self.epoll_fd).unwrap();  // panic! if close files
    }
}
<commit_msg>add pin.is_exported()<commit_after>// Copyright 2015, Paul Osborne <osbpau@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/license/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option.  This file may not be copied, modified, or distributed
// except according to those terms.
//
// Portions of this implementation are based on work by Nat Pryce:
// https://github.com/npryce/rusty-pi/blob/master/src/pi/gpio.rs

#![crate_type = "lib"]
#![crate_name = "sysfs_gpio"]

//! GPIO access under Linux using the GPIO sysfs interface
//!
//! The methods exposed by this library are centered around
//! the `Pin` struct and map pretty directly the API exposed
//! by the kernel in syfs (https://www.kernel.org/doc/Documentation/gpio/sysfs.txt).
//!
//! # Examples
//!
//! Typical usage for systems where one wants to ensure that
//! the pins in use are unexported upon completion looks like
//! the following:
//!
//! ```no_run
//! extern crate sysfs_gpio;
//!
//! use sysfs_gpio::{Direction, Pin};
//! use std::thread::sleep_ms;
//!
//! fn main() {
//!     let my_led = Pin::new(127); // number depends on chip, etc.
//!     my_led.with_exported(|| {
//!         loop {
//!             my_led.set_value(0).unwrap();
//!             sleep_ms(200);
//!             my_led.set_value(1).unwrap();
//!             sleep_ms(200);
//!         }
//!     }).unwrap();
//! }
//! ```

extern crate nix;

use nix::sys::epoll::*;
use nix::unistd::close;

use std::io::prelude::*;
use std::os::unix::prelude::*;
use std::io::{self, SeekFrom};
use std::fs;
use std::fs::File;

mod error;
pub use error::Error;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Pin {
    pin_num: u64,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Direction {
    In,
    Out,
    High,
    Low,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Edge {
    NoInterrupt,
    RisingEdge,
    FallingEdge,
    BothEdges,
}

#[macro_export]
macro_rules! try_unexport {
    ($gpio:ident, $e:expr) => (match $e {
        Ok(res) => res,
        Err(e) => { try!($gpio.unexport()); return Err(e) },
    });
}

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

/// Flush up to max bytes from the provided files input buffer
///
/// Typically, one would just use seek() for this sort of thing,
/// but for certain files (e.g. in sysfs), you need to actually
/// read it.
fn flush_input_from_file(dev_file: &mut File, max: usize) -> io::Result<usize> {
    let mut s = String::with_capacity(max);
    dev_file.read_to_string(&mut s)
}

/// Get the pin value from the provided file
fn get_value_from_file(dev_file: &mut File) -> Result<u8> {
    let mut s = String::with_capacity(10);
    try!(dev_file.seek(SeekFrom::Start(0)));
    try!(dev_file.read_to_string(&mut s));
    match s[..1].parse::<u8>() {
        Ok(n) => Ok(n),
        Err(_) => Err(Error::Unexpected(format!("Unexpected value file contents: {:?}", s))),
    }
}

impl Pin {
    /// Write all of the provided contents to the specified devFile
    fn write_to_device_file(&self, dev_file_name: &str, value: &str) -> io::Result<()> {
        let gpio_path = format!("/sys/class/gpio/gpio{}/{}", self.pin_num, dev_file_name);
        let mut dev_file = try!(File::create(&gpio_path));
        try!(dev_file.write_all(value.as_bytes()));
        Ok(())
    }

    fn read_from_device_file(&self, dev_file_name: &str) -> io::Result<String> {
        let gpio_path = format!("/sys/class/gpio/gpio{}/{}", self.pin_num, dev_file_name);
        let mut dev_file = try!(File::open(&gpio_path));
        let mut s = String::new();
        try!(dev_file.read_to_string(&mut s));
        Ok(s)
    }

    /// Create a new Pin with the provided `pin_num`
    ///
    /// This function does not export the provided pin_num.
    pub fn new(pin_num: u64) -> Pin {
        Pin { pin_num: pin_num }
    }

    /// Run a closure with the GPIO exported
    ///
    /// Prior to the provided closure being executed, the GPIO
    /// will be exported.  After the closure execution is complete,
    /// the GPIO will be unexported.
    ///
    /// # Example
    ///
    /// ```no_run
    /// use sysfs_gpio::{Pin, Direction};
    ///
    /// let gpio = Pin::new(24);
    /// let res = gpio.with_exported(|| {
    ///     println!("At this point, the Pin is exported");
    ///     try!(gpio.set_direction(Direction::Low));
    ///     try!(gpio.set_value(1));
    ///     // ...
    ///     Ok(())
    /// });
    /// ```
    #[inline]
    pub fn with_exported<F: FnOnce() -> Result<()>>(&self, closure: F) -> Result<()> {

        try!(self.export());
        match closure() {
            Ok(()) => {
                try!(self.unexport());
                Ok(())
            }
            Err(err) => {
                try!(self.unexport());
                Err(err)
            }
        }
    }

    /// Determines whether the GPIO is exported
    ///
    /// This function will error out if the kernel does not support the GPIO
    /// sysfs interface (i.e. `/sys/class/gpio` does not exist).
    pub fn is_exported(&self) -> bool {
        fs::metadata(&format!("/sys/class/gpio/gpio{}", self.pin_num)).is_ok()
    }

    /// Export the GPIO
    ///
    /// This is equivalent to `echo N > /sys/class/gpio/export` with
    /// the exception that the case where the GPIO is already exported
    /// is not an error.
    ///
    /// # Errors
    ///
    /// The main cases in which this function will fail and return an
    /// error are the following:
    /// 1. The system does not support the GPIO sysfs interface
    /// 2. The requested GPIO is out of range and cannot be exported
    /// 3. The requested GPIO is in use by the kernel and cannot
    ///    be exported by use in userspace
    ///
    /// # Example
    /// ```no_run
    /// use sysfs_gpio::Pin;
    ///
    /// let gpio = Pin::new(24);
    /// match gpio.export() {
    ///     Ok(()) => println!("Gpio {} exported!", gpio.get_pin()),
    ///     Err(err) => println!("Gpio {} could not be exported: {}", gpio.get_pin(), err),
    /// }
    /// ```
    pub fn export(&self) -> Result<()> {
        if let Err(_) = fs::metadata(&format!("/sys/class/gpio/gpio{}", self.pin_num)) {
            let mut export_file = try!(File::create("/sys/class/gpio/export"));
            try!(export_file.write_all(format!("{}", self.pin_num).as_bytes()));
        }
        Ok(())
    }

    /// Unexport the GPIO
    ///
    /// This function will unexport the provided by from syfs if
    /// it is currently exported.  If the pin is not currently
    /// exported, it will return without error.  That is, whenever
    /// this function returns Ok, the GPIO is not exported.
    pub fn unexport(&self) -> Result<()> {
        if let Ok(_) = fs::metadata(&format!("/sys/class/gpio/gpio{}", self.pin_num)) {
            let mut unexport_file = try!(File::create("/sys/class/gpio/unexport"));
            try!(unexport_file.write_all(format!("{}", self.pin_num).as_bytes()));
        }
        Ok(())
    }

    /// Get the pin number for the Pin
    pub fn get_pin(&self) -> u64 {
        self.pin_num
    }

    /// Get the direction of the Pin
    pub fn get_direction(&self) -> Result<Direction> {
        match self.read_from_device_file("direction") {
            Ok(s) => {
                match s.trim() {
                    "in" => Ok(Direction::In),
                    "out" => Ok(Direction::Out),
                    "high" => Ok(Direction::High),
                    "low" => Ok(Direction::Low),
                    other => Err(Error::Unexpected(format!("direction file contents {}", other))),
                }
            }
            Err(e) => Err(::std::convert::From::from(e)),
        }
    }

    /// Set this GPIO as either an input or an output
    ///
    /// The basic values allowed here are `Direction::In` and
    /// `Direction::Out` which set the Pin as either an input
    /// or output respectively.  In addition to those, two
    /// additional settings of `Direction::High` and
    /// `Direction::Low`.  These both set the Pin as an output
    /// but do so with an initial value of high or low respectively.
    /// This allows for glitch-free operation.
    ///
    /// Note that this entry may not exist if the kernel does
    /// not support changing the direction of a pin in userspace.  If
    /// this is the case, you will get an error.
    pub fn set_direction(&self, dir: Direction) -> Result<()> {
        try!(self.write_to_device_file("direction",
                                       match dir {
                                           Direction::In => "in",
                                           Direction::Out => "out",
                                           Direction::High => "high",
                                           Direction::Low => "low",
                                       }));

        Ok(())
    }

    /// Get the value of the Pin (0 or 1)
    ///
    /// If successful, 1 will be returned if the pin is high
    /// and 0 will be returned if the pin is low (this may or may
    /// not match the signal level of the actual signal depending
    /// on the GPIO "active_low" entry).
    pub fn get_value(&self) -> Result<u8> {
        match self.read_from_device_file("value") {
            Ok(s) => {
                match s.trim() {
                    "1" => Ok(1),
                    "0" => Ok(0),
                    other => Err(Error::Unexpected(format!("value file contents {}", other))),
                }
            }
            Err(e) => Err(::std::convert::From::from(e)),
        }
    }

    /// Set the value of the Pin
    ///
    /// This will set the value of the pin either high or low.
    /// A 0 value will set the pin low and any other value will
    /// set the pin high (1 is typical).
    pub fn set_value(&self, value: u8) -> Result<()> {
        try!(self.write_to_device_file("value",
                                       match value {
                                           0 => "0",
                                           _ => "1",
                                       }));

        Ok(())
    }

    /// Get the currently configured edge for this pin
    ///
    /// This value will only be present if the Pin allows
    /// for interrupts.
    pub fn get_edge(&self) -> Result<Edge> {
        match self.read_from_device_file("edge") {
            Ok(s) => {
                match s.trim() {
                    "none" => Ok(Edge::NoInterrupt),
                    "rising" => Ok(Edge::RisingEdge),
                    "falling" => Ok(Edge::FallingEdge),
                    "both" => Ok(Edge::BothEdges),
                    other => Err(Error::Unexpected(format!("Unexpected file contents {}", other))),
                }
            }
            Err(e) => Err(::std::convert::From::from(e)),
        }
    }

    /// Set the edge on which this GPIO will trigger when polled
    ///
    /// The configured edge determines what changes to the Pin will
    /// result in `poll()` returning.  This call will return an Error
    /// if the pin does not allow interrupts.
    pub fn set_edge(&self, edge: Edge) -> Result<()> {
        try!(self.write_to_device_file("edge",
                                       match edge {
                                           Edge::NoInterrupt => "none",
                                           Edge::RisingEdge => "rising",
                                           Edge::FallingEdge => "falling",
                                           Edge::BothEdges => "both",
                                       }));

        Ok(())
    }

    /// Get a PinPoller object for this pin
    ///
    /// This pin poller object will register an interrupt with the
    /// kernel and allow you to poll() on it and receive notifications
    /// that an interrupt has occured with minimal delay.
    pub fn get_poller(&self) -> Result<PinPoller> {
        PinPoller::new(self.pin_num)
    }
}

#[derive(Debug)]
pub struct PinPoller {
    pin_num: u64,
    epoll_fd: RawFd,
    devfile: File,
}

impl PinPoller {
    /// Get the pin associated with this PinPoller
    ///
    /// Note that this will be a new Pin object with the
    /// proper pin number.
    pub fn get_pin(&self) -> Pin {
        Pin::new(self.pin_num)
    }

    /// Create a new PinPoller for the provided pin number
    pub fn new(pin_num: u64) -> Result<PinPoller> {
        let devfile: File = try!(File::open(&format!("/sys/class/gpio/gpio{}/value", pin_num)));
        let devfile_fd = devfile.as_raw_fd();
        let epoll_fd = try!(epoll_create());
        let events = EPOLLPRI | EPOLLET;
        let info = EpollEvent {
            events: events,
            data: 0u64,
        };

        match epoll_ctl(epoll_fd, EpollOp::EpollCtlAdd, devfile_fd, &info) {
            Ok(_) => {
                Ok(PinPoller {
                    pin_num: pin_num,
                    devfile: devfile,
                    epoll_fd: epoll_fd,
                })
            }
            Err(err) => {
                let _ = close(epoll_fd); // cleanup
                Err(::std::convert::From::from(err))
            }
        }
    }

    /// Block until an interrupt occurs
    ///
    /// This call will block until an interrupt occurs.  The types
    /// of interrupts which may result in this call returning
    /// may be configured by calling `set_edge()` prior to
    /// making this call.  This call makes use of epoll under the
    /// covers.  If it is desirable to poll on multiple GPIOs or
    /// other event source, you will need to implement that logic
    /// yourself.
    ///
    /// This function will return Some(value) of the pin if a change is
    /// detected or None if a timeout occurs.  Note that the value provided
    /// is the value of the pin as soon as we get to handling the interrupt
    /// in userspace.  Each time this function returns with a value, a change
    /// has occurred, but you could end up reading the same value multiple
    /// times as the value has changed back between when the interrupt
    /// occurred and the current time.
    pub fn poll(&mut self, timeout_ms: isize) -> Result<Option<u8>> {
        try!(flush_input_from_file(&mut self.devfile, 255));
        let dummy_event = EpollEvent {
            events: EPOLLPRI | EPOLLET,
            data: 0u64,
        };
        let mut events: [EpollEvent; 1] = [dummy_event];
        let cnt = try!(epoll_wait(self.epoll_fd, &mut events, timeout_ms));
        Ok(match cnt {
            0 => None, // timeout
            _ => Some(try!(get_value_from_file(&mut self.devfile))),
        })
    }
}

impl Drop for PinPoller {
    fn drop(&mut self) {
        // we implement drop to close the underlying epoll fd as
        // it does not implement drop itself.  This is similar to
        // how mio works
        close(self.epoll_fd).unwrap();  // panic! if close files
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]

//! termsize is a tiny crate that provides a simple
//! interface for setting and retrieving the current
//! terminal interface size

extern crate libc;

use libc::{ c_ulong, c_ushort, STDOUT_FILENO };
use libc::funcs::bsd44::ioctl;

const TIOCGWINSZ: c_ulong = 0x40087468;
const TIOCSWINSZ: c_ulong = 2148037735;

/// A representation of the size of the current terminal
#[repr(C)]
#[derive(Debug)]
pub struct Size {
  height: c_ushort,
  width: c_ushort,
  x: c_ushort,
  y: c_ushort
}

impl Size {
  /// creates a new empty Size
  pub fn new() -> Size {
    Size { height: 0, width: 0, x: 0, y: 0 }
  }

  /// sets size height
  pub fn height(&mut self, h: u16) {
    self.height = h
  }

  /// sets size width
  pub fn width(&mut self, w: u16) {
    self.width = w;
  }
}

/// Sets the current terminal size
pub fn set(s: &Size) -> bool {
  let r = unsafe { ioctl(STDOUT_FILENO, TIOCSWINSZ, s) };
  r == 0
}

/// Gets the current terminal size
pub fn get() -> Option<Size> {
  let s = Size::new();
  let r = unsafe { ioctl(STDOUT_FILENO, TIOCGWINSZ, &s) };
  if r == 0 { Some(s) } else { None }
}
<commit_msg>make height and width public and provide an example<commit_after>#![deny(missing_docs)]

//! termsize is a tiny crate that provides a simple
//! interface for setting and retrieving the current
//! terminal interface size
//!
//! ```rust
//!  extern crate termsize;
//!  termsize::get().map(|size| println!("width {} height {}", size.width, size.height));
//! ```
extern crate libc;

use libc::{ c_ulong, c_ushort, STDOUT_FILENO };
use libc::funcs::bsd44::ioctl;

const TIOCGWINSZ: c_ulong = 0x40087468;
const TIOCSWINSZ: c_ulong = 2148037735;

/// A representation of the size of the current terminal
#[repr(C)]
#[derive(Debug)]
pub struct Size {
  /// height of size in rows
  pub height: c_ushort,
  /// width of size in columns
  pub width: c_ushort,
  x: c_ushort,
  y: c_ushort
}

impl Size {
  /// creates a new empty Size
  pub fn new() -> Size {
    Size { height: 0, width: 0, x: 0, y: 0 }
  }

  /// sets size height
  pub fn height(&mut self, h: u16) {
    self.height = h
  }

  /// sets size width
  pub fn width(&mut self, w: u16) {
    self.width = w;
  }
}

/// Sets the current terminal size
pub fn set(s: &Size) -> bool {
  let r = unsafe { ioctl(STDOUT_FILENO, TIOCSWINSZ, s) };
  r == 0
}

/// Gets the current terminal size
pub fn get() -> Option<Size> {
  let s = Size::new();
  let r = unsafe { ioctl(STDOUT_FILENO, TIOCGWINSZ, &s) };
  if r == 0 { Some(s) } else { None }
}
<|endoftext|>


<commit_before>#![deny(warnings)]
#![deny(missing_docs)]
#![doc(html_root_url = "https://docs.rs/reqwest/0.6.2")]

//! # reqwest
//!
//! The `reqwest` crate provides a convenient, higher-level HTTP Client.
//!
//! It handles many of the things that most people just expect an HTTP client
//! to do for them.
//!
//! - Uses system-native TLS
//! - Plain bodies, JSON, urlencoded, (TODO: multipart)
//! - Customizable redirect policy
//! - (TODO: Cookies)
//!
//! The `reqwest::Client` is synchronous, making it a great fit for
//! applications that only require a few HTTP requests, and wish to handle
//! them synchronously. When [hyper][] releases with asynchronous support,
//! `reqwest` will be updated to use it internally, but still provide a
//! synchronous Client, for convenience. A `reqwest::async::Client` will also
//! be added.
//!
//! ## Making a GET request
//!
//! For a single request, you can use the [`get`][get] shortcut method.
//!
//! ```rust
//! use std::io::Read;
//! # use reqwest::{Error, Response};
//!
//! # fn run() -> Result<Response, Error> {
//! let mut resp = reqwest::get("https://www.rust-lang.org")?;
//! assert!(resp.status().is_success());
//!
//! let mut content = String::new();
//! resp.read_to_string(&mut content);
//! # Ok(resp)
//! # }
//! ```
//!
//! As you can see, reqwest's [`Response`][response] struct implements Rust's
//! `Read` trait, so many useful standard library and third party crates will
//! have convenience methods that take a `Response` anywhere `T: Read` is
//! acceptable.
//!
//! If you plan to perform multiple requests, it is best to create a [`Client`][client]
//! and reuse it, taking advantage of keep-alive connection pooling.
//!
//! ## Making POST requests (or setting request bodies)
//!
//! There are several ways you can set the body of a request. The basic one is
//! by using the `body()` method of a [`RequestBuilder`][builder]. This lets you set the
//! exact raw bytes of what the body should be. It accepts various types,
//! including `String`, `Vec<u8>`, and `File`. If you wish to pass a custom
//! Reader, you can use the `reqwest::Body::new()` constructor.
//!
//! ```rust
//! # use reqwest::Error;
//! #
//! # fn run() -> Result<(), Error> {
//! let client = reqwest::Client::new()?;
//! let res = client.post("http://httpbin.org/post")?
//!     .body("the exact body that is sent")
//!     .send()?;
//! # Ok(())
//! # }
//! ```
//!
//! ### Forms
//!
//! It's very common to want to send form data in a request body. This can be
//! done with any type that can be serialized into form data.
//!
//! This can be an array of tuples, or a `HashMap`, or a custom type that
//! implements [`Serialize`][serde].
//!
//! ```rust
//! # use reqwest::Error;
//! #
//! # fn run() -> Result<(), Error> {
//! // This will POST a body of `foo=bar&baz=quux`
//! let params = [("foo", "bar"), ("baz", "quux")];
//! let client = reqwest::Client::new()?;
//! let res = client.post("http://httpbin.org/post")?
//!     .form(&params)?
//!     .send()?;
//! # Ok(())
//! # }
//! ```
//!
//! ### JSON
//!
//! There is also a `json` method helper on the [`RequestBuilder`][builder] that works in
//! a similar fashion the `form` method. It can take any value that can be
//! serialized into JSON.
//!
//! ```rust
//! # use reqwest::Error;
//! # use std::collections::HashMap;
//! #
//! # fn run() -> Result<(), Error> {
//! // This will POST a body of `{"lang":"rust","body":"json"}`
//! let mut map = HashMap::new();
//! map.insert("lang", "rust");
//! map.insert("body", "json");
//!
//! let client = reqwest::Client::new()?;
//! let res = client.post("http://httpbin.org/post")?
//!     .json(&map)?
//!     .send()?;
//! # Ok(())
//! # }
//! ```
//!
//! [hyper]: http://hyper.rs
//! [client]: ./struct.Client.html
//! [response]: ./struct.Response.html
//! [get]: ./fn.get.html
//! [builder]: ./client/struct.RequestBuilder.html
//! [serde]: http://serde.rs
extern crate hyper;

#[macro_use]
extern crate log;
extern crate libc;
extern crate libflate;
extern crate hyper_native_tls;
extern crate serde;
extern crate serde_json;
extern crate serde_urlencoded;
extern crate url;

pub use hyper::client::IntoUrl;
pub use hyper::Error as HyperError;
pub use hyper::header;
pub use hyper::mime;
pub use hyper::method::Method;
pub use hyper::status::StatusCode;
pub use hyper::Url;
pub use url::ParseError as UrlError;

pub use self::client::{Certificate, Client, ClientBuilder};
pub use self::error::{Error, Result};
pub use self::body::Body;
pub use self::redirect::{RedirectAction, RedirectAttempt, RedirectPolicy};
pub use self::request::{Request, RequestBuilder};
pub use self::response::Response;

#[macro_use]
mod error;
mod body;
mod client;
mod redirect;
mod request;
mod response;

/// Shortcut method to quickly make a `GET` request.
///
/// See also the methods on the [`reqwest::Response`](./struct.Response.html)
/// type.
///
/// # Examples
///
/// ```rust
/// # extern crate reqwest;
/// # #[macro_use] extern crate error_chain;
/// #
/// use std::io::Read;
///
/// # error_chain! {
/// #     foreign_links {
/// #         Reqwest(reqwest::Error);
/// #         Io(std::io::Error);
/// #     }
/// # }
/// #
/// # fn run() -> Result<()> {
/// let mut result = String::new();
/// reqwest::get("https://www.rust-lang.org")?
///     .read_to_string(&mut result)?;
/// # Ok(())
/// # }
/// #
/// # fn main() {
/// #    if let Err(error) = run() {
/// #        println!("Error: {:?}", error);
/// #    }
/// # }
/// ```
///
/// # Errors
///
/// This function fails if:
///
/// - native TLS backend cannot be initialized
/// - supplied `Url` cannot be parsed
/// - there was an error while sending request
/// - redirect loop was detected
/// - redirect limit was exhausted
pub fn get<T: IntoUrl>(url: T) -> ::Result<Response> {
    Client::new()?
        .get(url)?
        .send()
}

fn _assert_impls() {
    fn assert_send<T: Send>() {}
    fn assert_sync<T: Sync>() {}
    fn assert_clone<T: Clone>() {}

    assert_send::<Client>();
    assert_sync::<Client>();
    assert_clone::<Client>();

    assert_send::<Request>();
    assert_send::<RequestBuilder>();

    assert_send::<Response>();

    assert_send::<Error>();
    assert_sync::<Error>();
}
<commit_msg>remove network call from doc test<commit_after>#![deny(warnings)]
#![deny(missing_docs)]
#![doc(html_root_url = "https://docs.rs/reqwest/0.6.2")]

//! # reqwest
//!
//! The `reqwest` crate provides a convenient, higher-level HTTP Client.
//!
//! It handles many of the things that most people just expect an HTTP client
//! to do for them.
//!
//! - Uses system-native TLS
//! - Plain bodies, JSON, urlencoded, (TODO: multipart)
//! - Customizable redirect policy
//! - (TODO: Cookies)
//!
//! The `reqwest::Client` is synchronous, making it a great fit for
//! applications that only require a few HTTP requests, and wish to handle
//! them synchronously. When [hyper][] releases with asynchronous support,
//! `reqwest` will be updated to use it internally, but still provide a
//! synchronous Client, for convenience. A `reqwest::async::Client` will also
//! be added.
//!
//! ## Making a GET request
//!
//! For a single request, you can use the [`get`][get] shortcut method.
//!
//! ```rust
//! use std::io::Read;
//! # use reqwest::{Error, Response};
//!
//! # fn run() -> Result<Response, Error> {
//! let mut resp = reqwest::get("https://www.rust-lang.org")?;
//! assert!(resp.status().is_success());
//!
//! let mut content = String::new();
//! resp.read_to_string(&mut content);
//! # Ok(resp)
//! # }
//! ```
//!
//! As you can see, reqwest's [`Response`][response] struct implements Rust's
//! `Read` trait, so many useful standard library and third party crates will
//! have convenience methods that take a `Response` anywhere `T: Read` is
//! acceptable.
//!
//! If you plan to perform multiple requests, it is best to create a [`Client`][client]
//! and reuse it, taking advantage of keep-alive connection pooling.
//!
//! ## Making POST requests (or setting request bodies)
//!
//! There are several ways you can set the body of a request. The basic one is
//! by using the `body()` method of a [`RequestBuilder`][builder]. This lets you set the
//! exact raw bytes of what the body should be. It accepts various types,
//! including `String`, `Vec<u8>`, and `File`. If you wish to pass a custom
//! Reader, you can use the `reqwest::Body::new()` constructor.
//!
//! ```rust
//! # use reqwest::Error;
//! #
//! # fn run() -> Result<(), Error> {
//! let client = reqwest::Client::new()?;
//! let res = client.post("http://httpbin.org/post")?
//!     .body("the exact body that is sent")
//!     .send()?;
//! # Ok(())
//! # }
//! ```
//!
//! ### Forms
//!
//! It's very common to want to send form data in a request body. This can be
//! done with any type that can be serialized into form data.
//!
//! This can be an array of tuples, or a `HashMap`, or a custom type that
//! implements [`Serialize`][serde].
//!
//! ```rust
//! # use reqwest::Error;
//! #
//! # fn run() -> Result<(), Error> {
//! // This will POST a body of `foo=bar&baz=quux`
//! let params = [("foo", "bar"), ("baz", "quux")];
//! let client = reqwest::Client::new()?;
//! let res = client.post("http://httpbin.org/post")?
//!     .form(&params)?
//!     .send()?;
//! # Ok(())
//! # }
//! ```
//!
//! ### JSON
//!
//! There is also a `json` method helper on the [`RequestBuilder`][builder] that works in
//! a similar fashion the `form` method. It can take any value that can be
//! serialized into JSON.
//!
//! ```rust
//! # use reqwest::Error;
//! # use std::collections::HashMap;
//! #
//! # fn run() -> Result<(), Error> {
//! // This will POST a body of `{"lang":"rust","body":"json"}`
//! let mut map = HashMap::new();
//! map.insert("lang", "rust");
//! map.insert("body", "json");
//!
//! let client = reqwest::Client::new()?;
//! let res = client.post("http://httpbin.org/post")?
//!     .json(&map)?
//!     .send()?;
//! # Ok(())
//! # }
//! ```
//!
//! [hyper]: http://hyper.rs
//! [client]: ./struct.Client.html
//! [response]: ./struct.Response.html
//! [get]: ./fn.get.html
//! [builder]: ./client/struct.RequestBuilder.html
//! [serde]: http://serde.rs
extern crate hyper;

#[macro_use]
extern crate log;
extern crate libc;
extern crate libflate;
extern crate hyper_native_tls;
extern crate serde;
extern crate serde_json;
extern crate serde_urlencoded;
extern crate url;

pub use hyper::client::IntoUrl;
pub use hyper::Error as HyperError;
pub use hyper::header;
pub use hyper::mime;
pub use hyper::method::Method;
pub use hyper::status::StatusCode;
pub use hyper::Url;
pub use url::ParseError as UrlError;

pub use self::client::{Certificate, Client, ClientBuilder};
pub use self::error::{Error, Result};
pub use self::body::Body;
pub use self::redirect::{RedirectAction, RedirectAttempt, RedirectPolicy};
pub use self::request::{Request, RequestBuilder};
pub use self::response::Response;

#[macro_use]
mod error;
mod body;
mod client;
mod redirect;
mod request;
mod response;

/// Shortcut method to quickly make a `GET` request.
///
/// See also the methods on the [`reqwest::Response`](./struct.Response.html)
/// type.
///
/// # Examples
///
/// ```rust
/// use std::io::Read;
///
/// # fn run() -> Result<(), Box<::std::error::Error>> {
/// let mut result = String::new();
/// reqwest::get("https://www.rust-lang.org")?
///     .read_to_string(&mut result)?;
/// # Ok(())
/// # }
/// # fn main() { }
/// ```
///
/// # Errors
///
/// This function fails if:
///
/// - native TLS backend cannot be initialized
/// - supplied `Url` cannot be parsed
/// - there was an error while sending request
/// - redirect loop was detected
/// - redirect limit was exhausted
pub fn get<T: IntoUrl>(url: T) -> ::Result<Response> {
    Client::new()?
        .get(url)?
        .send()
}

fn _assert_impls() {
    fn assert_send<T: Send>() {}
    fn assert_sync<T: Sync>() {}
    fn assert_clone<T: Clone>() {}

    assert_send::<Client>();
    assert_sync::<Client>();
    assert_clone::<Client>();

    assert_send::<Request>();
    assert_send::<RequestBuilder>();

    assert_send::<Response>();

    assert_send::<Error>();
    assert_sync::<Error>();
}
<|endoftext|>


<commit_before>extern crate terminal_size;

use std::io::Write;

use terminal_size::{Width, Height, terminal_size};

pub mod builder;

/// Tracks progress of a task
pub struct Progress {
    current: usize,
    total: usize,

    caption: String,

    started: bool
}

impl Default for Progress {
    fn default() -> Progress {
        builder::ProgressBuilder::default().build()
    }
}

impl Progress {
    pub fn current(&self) -> usize {
        self.current
    }

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

    pub fn increment(&mut self) -> &Self {
        if self.current < self.total {
            self.current += 1;
        }
        print_bar(self);
        self
    }

    pub fn decrement(&mut self) -> &Self {
        if self.current > 0 {
            self.current -= 1;
        }
        self
    }

    pub fn finished(&self) -> bool {
        self.current >= self.total
    }

    pub fn process(&self) -> u8 {
        (self.current * 100 / self.total) as u8
    }

    pub fn start(&mut self) -> &Self {
        self.started = true;
        self
    }

    pub fn caption(&self) -> &String {
        &self.caption
    }
}

fn print_bar(p: &Progress) {
    let p_info = format!("{current} / {total} ({process})",
                         current = p.current(),
                         total   = p.total(),
                         process = p.process());
    let caption = p.caption();

    let (Width(terminal_width), _) = terminal_size()
        .unwrap_or((Width(79), Height(0)));

    let bar_width  = terminal_width as usize // Width of terminal
        - p_info.len()  // Width of right summary
        - caption.len() // Width of caption
        - 3  // Colon and spaces
        - 2; // vertical bars in the progress meter
    let done_width = (bar_width * p.process() as usize) / 100;
    let todo_width = bar_width - done_width;
    let done_bar   = std::iter::repeat("#").take(done_width).collect::<String>();
    let todo_bar   = std::iter::repeat("-").take(todo_width).collect::<String>();
    let bar = format!("|{}{}|", done_bar, todo_bar);

    print!("{caption}: {bar} {info}\r",
           caption = caption, bar = bar, info = p_info);
    std::io::stdout().flush().unwrap();
}
<commit_msg>document Progress<commit_after>extern crate terminal_size;

use std::io::Write;

use terminal_size::{Width, Height, terminal_size};

pub mod builder;

/// Tracks progress of a task.
///
/// There should be not more than a single instance started at a given point in
/// time, it will mangle your terminal output.
pub struct Progress {
    current: usize,
    total: usize,

    caption: String,

    started: bool
}

impl Default for Progress {
    fn default() -> Progress {
        builder::ProgressBuilder::default().build()
    }
}

impl Progress {
    /// Returns the current progress absolute value.
    ///
    /// # Example
    ///
    /// ```
    /// use progress::Progress;
    /// let p = Progress::default();
    /// assert_eq!(0, p.current());
    /// ```
    pub fn current(&self) -> usize {
        self.current
    }

    /// Returns the total value.
    ///
    /// # Example
    ///
    /// ```
    /// use progress::Progress;
    /// let p = Progress::default();
    /// assert_eq!(100, p.total());
    /// ```
    pub fn total(&self) -> usize {
        self.total
    }

    /// Advances the Progress by exactly one.
    pub fn increment(&mut self) -> &Self {
        if self.current < self.total {
            self.current += 1;
        }
        print_bar(self);
        self
    }

    /// Does a step backwards at the Progress.
    pub fn decrement(&mut self) -> &Self {
        if self.current > 0 {
            self.current -= 1;
        }
        self
    }

    /// Determines wheter a Progress has finished (reached the total) or not.
    pub fn finished(&self) -> bool {
        self.current >= self.total
    }

    /// Returns the relative value of the Progress.
    pub fn process(&self) -> u8 {
        (self.current * 100 / self.total) as u8
    }

    /// Activates the Progress.
    pub fn start(&mut self) -> &Self {
        self.started = true;
        self
    }

    /// Returns the current caption.
    pub fn caption(&self) -> &String {
        &self.caption
    }
}

fn print_bar(p: &Progress) {
    let p_info = format!("{current} / {total} ({process})",
                         current = p.current(),
                         total   = p.total(),
                         process = p.process());
    let caption = p.caption();

    let (Width(terminal_width), _) = terminal_size()
        .unwrap_or((Width(79), Height(0)));

    let bar_width  = terminal_width as usize // Width of terminal
        - p_info.len()  // Width of right summary
        - caption.len() // Width of caption
        - 3  // Colon and spaces
        - 2; // vertical bars in the progress meter
    let done_width = (bar_width * p.process() as usize) / 100;
    let todo_width = bar_width - done_width;
    let done_bar   = std::iter::repeat("#").take(done_width).collect::<String>();
    let todo_bar   = std::iter::repeat("-").take(todo_width).collect::<String>();
    let bar = format!("|{}{}|", done_bar, todo_bar);

    print!("{caption}: {bar} {info}\r",
           caption = caption, bar = bar, info = p_info);
    std::io::stdout().flush().unwrap();
}
<|endoftext|>


<commit_before>//! This crate allows to communicate with usbmuxd (USB multiplexer daemon) which is used to
//! communicate with iOS devices.

extern crate unix_socket;
extern crate byteorder;
extern crate plist;
#[cfg(test)]
#[macro_use(expect)]
extern crate expectest;

use std::io;
use std::fmt;
use std::error;
use std::time::Duration;
use unix_socket::UnixStream;
use plist::Plist;

pub mod requests;

/// Represents connection to usbmuxd.
pub struct Stream {
    inner: UnixStream,
}

impl Stream {
    /// Tries to connect to usbmuxd.
    pub fn connect() -> io::Result<Self> {
        Ok(Stream {
            inner: try!(UnixStream::connect("/var/run/usbmuxd")),
        })
    }

    /// Sets the send timeout for the stream.
    ///
    /// If the provided value is `None`, then `send` calls will block indefinitely.
    /// It is an error to pass the zero `Duration` to this method.
    pub fn set_send_tymeout(&mut self, timeout: Option<Duration>) -> Result<()> {
        Ok(try!(self.inner.set_write_timeout(timeout)))
    }

    /// Sets the receive timeout for the stream.
    ///
    /// If the provided value is `None`, then `receive` calls will block indefinitely.
    /// It is an error to pass the zero `Duration` to this method.
    pub fn set_receive_timeout(&mut self, timeout: Option<Duration>) -> Result<()> {
        Ok(try!(self.inner.set_read_timeout(timeout)))
    }

    /// Tries to send `plist` data to usbmuxd.
    ///
    /// After this call you should call `receive` method to get a response from usbmuxd.
    pub fn send(&mut self, plist: Plist) -> Result<()> {
        send(&mut self.inner, plist)
    }

    /// Tries to receive `plist` data from usbmuxd.
    ///
    /// Typically this method should be called after `send` method.
    pub fn receive(&mut self) -> Result<Plist> {
        receive(&mut self.inner)
    }
}

/// A Result type alias.
pub type Result<T> = ::std::result::Result<T, Error>;

/// An Error type.
#[derive(Debug)]
pub enum Error {
    /// Denotes I/O error.
    Io(io::Error),
    /// Denotes error that produces plist crate.
    Plist(plist::Error),
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Io(ref e) => e.description(),
            Error::Plist(ref e) => e.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Io(ref e) => Some(e),
            Error::Plist(ref e) => Some(e),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Io(ref e) => e.fmt(f),
            Error::Plist(ref e) => e.fmt(f),
        }
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::Io(e)
    }
}

impl From<plist::Error> for Error {
    fn from(e: plist::Error) -> Self {
        Error::Plist(e)
    }
}

fn send<W>(stream: &mut W, plist: Plist) -> Result<()> where W: io::Write {
    let data = prepare_request_data(&plist_to_data(plist));
    Ok(try!(stream.write_all(&data)))
}

fn receive<R>(stream: &mut R) -> Result<Plist> where R: io::Read {
    use byteorder::{LittleEndian, ByteOrder};

    // Read header and get length of the data.
    // Don't bother to check version and message type. Deserialization
    // from plist will fail anyway if message will have wrong format.
    let mut header = [0; 16];
    try!(stream.read_exact(&mut header));
    let length = LittleEndian::read_u32(&header) as usize - header.len();

    let mut data = vec![0; length];
    try!(stream.read_exact(&mut data));

    Ok(try!(Plist::read(io::Cursor::new(data))))
}

/// Converts the `plist` to the raw xml data.
fn plist_to_data(plist: Plist) -> Vec<u8> {
    use plist::xml::EventWriter;
    let mut buffer = Vec::new();
    {
        let mut writer = EventWriter::new(&mut buffer);
        for event in plist.into_events() {
            writer.write(&event).unwrap();
        }
    }
    buffer
}

/// Prepares request data for usbmuxd by adding a header info.
fn prepare_request_data(data: &[u8]) -> Vec<u8> {
    use byteorder::{WriteBytesExt, LittleEndian};
    use std::io::{Write, Cursor};

    let mut cursor = Cursor::new(Vec::new());
    cursor.write_u32::<LittleEndian>(data.len() as u32 + 16).unwrap(); // total length
    cursor.write_u32::<LittleEndian>(1).unwrap(); // version
    cursor.write_u32::<LittleEndian>(8).unwrap(); // message type (plist)
    cursor.write_u32::<LittleEndian>(1).unwrap(); // tag
    cursor.write_all(data).unwrap();
    cursor.into_inner()
}

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

    #[test]
    fn test_prepare_data() {
        expect!(prepare_request_data(&[1, 2, 3, 4]).iter()).to(have_count(20));
    }
}
<commit_msg>Add send/receive message test.<commit_after>//! This crate allows to communicate with usbmuxd (USB multiplexer daemon) which is used to
//! communicate with iOS devices.

extern crate unix_socket;
extern crate byteorder;
extern crate plist;
#[cfg(test)]
#[macro_use(expect)]
extern crate expectest;

use std::io;
use std::fmt;
use std::error;
use std::time::Duration;
use unix_socket::UnixStream;
use plist::Plist;

pub mod requests;

/// Represents connection to usbmuxd.
pub struct Stream {
    inner: UnixStream,
}

impl Stream {
    /// Tries to connect to usbmuxd.
    pub fn connect() -> io::Result<Self> {
        Ok(Stream {
            inner: try!(UnixStream::connect("/var/run/usbmuxd")),
        })
    }

    /// Sets the send timeout for the stream.
    ///
    /// If the provided value is `None`, then `send` calls will block indefinitely.
    /// It is an error to pass the zero `Duration` to this method.
    pub fn set_send_tymeout(&mut self, timeout: Option<Duration>) -> Result<()> {
        Ok(try!(self.inner.set_write_timeout(timeout)))
    }

    /// Sets the receive timeout for the stream.
    ///
    /// If the provided value is `None`, then `receive` calls will block indefinitely.
    /// It is an error to pass the zero `Duration` to this method.
    pub fn set_receive_timeout(&mut self, timeout: Option<Duration>) -> Result<()> {
        Ok(try!(self.inner.set_read_timeout(timeout)))
    }

    /// Tries to send `plist` data to usbmuxd.
    ///
    /// After this call you should call `receive` method to get a response from usbmuxd.
    pub fn send(&mut self, plist: Plist) -> Result<()> {
        send(&mut self.inner, plist)
    }

    /// Tries to receive `plist` data from usbmuxd.
    ///
    /// Typically this method should be called after `send` method.
    pub fn receive(&mut self) -> Result<Plist> {
        receive(&mut self.inner)
    }
}

/// A Result type alias.
pub type Result<T> = ::std::result::Result<T, Error>;

/// An Error type.
#[derive(Debug)]
pub enum Error {
    /// Denotes I/O error.
    Io(io::Error),
    /// Denotes error that produces plist crate.
    Plist(plist::Error),
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Io(ref e) => e.description(),
            Error::Plist(ref e) => e.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Io(ref e) => Some(e),
            Error::Plist(ref e) => Some(e),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Io(ref e) => e.fmt(f),
            Error::Plist(ref e) => e.fmt(f),
        }
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::Io(e)
    }
}

impl From<plist::Error> for Error {
    fn from(e: plist::Error) -> Self {
        Error::Plist(e)
    }
}

fn send<W>(stream: &mut W, plist: Plist) -> Result<()> where W: io::Write {
    let data = prepare_request_data(&plist_to_data(plist));
    Ok(try!(stream.write_all(&data)))
}

fn receive<R>(stream: &mut R) -> Result<Plist> where R: io::Read {
    use byteorder::{LittleEndian, ByteOrder};

    // Read header and get length of the data.
    // Don't bother to check version and message type. Deserialization
    // from plist will fail anyway if message will have wrong format.
    let mut header = [0; 16];
    try!(stream.read_exact(&mut header));
    let length = LittleEndian::read_u32(&header) as usize - header.len();

    let mut data = vec![0; length];
    try!(stream.read_exact(&mut data));

    Ok(try!(Plist::read(io::Cursor::new(data))))
}

/// Converts the `plist` to the raw xml data.
fn plist_to_data(plist: Plist) -> Vec<u8> {
    use plist::xml::EventWriter;
    let mut buffer = Vec::new();
    {
        let mut writer = EventWriter::new(&mut buffer);
        for event in plist.into_events() {
            writer.write(&event).unwrap();
        }
    }
    buffer
}

/// Prepares request data for usbmuxd by adding a header info.
fn prepare_request_data(data: &[u8]) -> Vec<u8> {
    use byteorder::{WriteBytesExt, LittleEndian};
    use std::io::{Write, Cursor};

    let mut cursor = Cursor::new(Vec::new());
    cursor.write_u32::<LittleEndian>(data.len() as u32 + 16).unwrap(); // total length
    cursor.write_u32::<LittleEndian>(1).unwrap(); // version
    cursor.write_u32::<LittleEndian>(8).unwrap(); // message type (plist)
    cursor.write_u32::<LittleEndian>(1).unwrap(); // tag
    cursor.write_all(data).unwrap();
    cursor.into_inner()
}

#[cfg(test)]
mod tests {
    use super::prepare_request_data;
    use std::io;
    use expectest::prelude::*;

    #[test]
    fn test_prepare_data() {
        expect!(prepare_request_data(&[1, 2, 3, 4]).iter()).to(have_count(20));
    }

    #[test]
    fn test_send_receive_message() {
        let message = super::requests::listen();
        let mut buffer = Vec::new();
        expect!(super::send(&mut buffer, message.clone())).to(be_ok());
        let mut cursor = io::Cursor::new(buffer);
        expect!(super::receive(&mut cursor)).to(be_ok().value(message));
    }
}
<|endoftext|>