<commit_before>
use sound_stream_settings::SoundStreamSettings;
use std::rc::Rc;
use std::cell::RefCell;
use std::fmt::Formatter;
use std::fmt::Result;
use std::fmt::Show;

/// The mixer input for handling volume and
/// panning of incoming audio from inputs.
#[deriving(Clone)]
pub struct MixerInput {
    node: Rc<RefCell<Node>>,
    vol: f32,
    pan: f32
}

/// Need to explicitly implement Show due to
/// Rc pointer.
impl Show for MixerInput {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "node: {}, vol: {}, pan{}", self.node.borrow(), self.vol, self.pan)
    }
}

impl MixerInput {
    /// Constructor for a mixer input.
    pub fn new(node: Rc<RefCell<Node>>) -> MixerInput {
        MixerInput {
            node: node,
            vol: 1f32,
            pan: 0f32
        }
    }
}

/// The DSP Node contains a vector of children
/// nodes (within the `MixerInput`s from which
/// audio can be requested as well as the current
/// SoundStream settings.
#[deriving(Show, Clone)]
pub struct Node {
    inputs: Vec<MixerInput>,
    settings: SoundStreamSettings,
    master_vol: f32
}

/// DSP Node trait. Implement this for any audio
/// instrument or effects types. Be sure to add
/// the `Node` struct to a field as well, and
/// override the `get_node` and `get_node_mut`
/// methods by returning a ref (/mut) to it.
pub trait IsNode {

    /// Return a reference to the Node.
    fn get_node<'a>(&'a self) -> &'a Node;
    /// Return a mutable reference to the Node.
    fn get_node_mut<'a>(&'a mut self) -> &'a mut Node;

    /// Apply settings to self and all inputs.
    fn apply_settings(&mut self, settings: SoundStreamSettings) {
        for input in self.get_node_mut().inputs.mut_iter() {
            input.node.borrow_mut().apply_settings(settings);
        }
        self.get_node_mut().settings = settings;
    }

    /// Add a new input.
    fn add_input(&mut self, input: Rc<RefCell<Node>>) {
        self.get_node_mut().inputs.push(MixerInput::new(input))
    }

    /// Remove an input. Find the input by comparing
    /// the address of the given input to each of the
    /// inputs' addresses.
    fn remove_input(&mut self, to_remove: &Node) {
        for i in range(0, self.get_node_mut().inputs.len()) {
            if &(*self.get_node_mut().inputs.get(i).node.borrow()) as *_ == to_remove as *_ {
                self.get_node_mut().inputs.remove(i);
                break;
            }
        }
    }

    /// Remove all inputs from the `inputs` vector.
    fn remove_all_inputs(&mut self) {
        self.get_node_mut().inputs.clear();
    }

    /// Add all inputs held by another node.
    fn add_inputs_from(&mut self, other: &Node) {
        self.get_node_mut().inputs.push_all(other.inputs.as_slice());
    }

    /// Receive incoming audio (override this
    /// to do something with the input).
    fn audio_received(&mut self, input: &Vec<f32>) {}

    /// Request audio from inputs, process and
    /// pass back to the output! Override this
    /// method for any synthesis or generative
    /// types.
    fn audio_requested(&mut self, output: &mut Vec<f32>) {
        let master_vol = self.get_node_mut().master_vol;
        let frames = self.get_node_mut().settings.frames as uint;
        let channels = self.get_node_mut().settings.channels as uint;
        let mut vol_per_channel: Vec<f32> = Vec::from_elem(channels, 1f32);
        for i in range(0, self.get_node_mut().inputs.len()) {
            let input = self.get_node_mut().inputs.get(i);
            let mut working: Vec<f32> =
                Vec::from_elem((frames * channels) as uint, 0f32);

            // Call audio_requested for each input.
            input.node.borrow_mut().audio_requested(&mut working);

            // Construct precalculated volume and
            // pan array (for efficiency).
            let vol_l: f32 = input.vol * (1f32 - input.pan);
            let vol_r: f32 = input.vol * input.pan;
            for j in range(0, vol_per_channel.len()) {
                *vol_per_channel.get_mut(j) = if j == 0 { vol_l } else { vol_r } * master_vol;
            }

            // Sum all input nodes to output (considering
            // pan, vol and interleaving).
            for j in range(0, frames) {
                for k in range(0, channels) {
                    *output.get_mut(j * channels + k) +=
                        *working.get_mut(j * channels + k) * *vol_per_channel.get_mut(k);
                }
            }
        }
        // Custom buffer processing.
        self.get_node_mut().process_buffer(output);
    }

    /// Override for custom processing of audio per
    /// buffer. This is mainly for audio effects. Get's
    /// called at the end of audio_requested.
    fn process_buffer(&mut self, output: &mut Vec<f32>) {}

}

/// We only have to implement these two methods
/// for any of our types that derive from our
/// `IsNode` DSP node trait.
impl IsNode for Node {
    fn get_node<'a>(&'a self) -> &'a Node { self }
    fn get_node_mut<'a>(&'a mut self) -> &'a mut Node { self }
}

impl Node {
    /// Constructor for the DSP Node.
    pub fn new(settings: SoundStreamSettings) -> Node {
        Node {
            inputs: Vec::new(),
            settings: settings,
            master_vol: 1f32
        }
    }
}

<commit_msg>fixed docs<commit_after>
use sound_stream_settings::SoundStreamSettings;
use std::rc::Rc;
use std::cell::RefCell;
use std::fmt::Formatter;
use std::fmt::Result;
use std::fmt::Show;

/// The mixer input for handling volume and
/// panning of incoming audio from inputs.
#[deriving(Clone)]
pub struct MixerInput {
    node: Rc<RefCell<Node>>,
    vol: f32,
    pan: f32
}

/// Need to explicitly implement Show due to
/// Rc pointer.
impl Show for MixerInput {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "node: {}, vol: {}, pan{}", self.node.borrow(), self.vol, self.pan)
    }
}

impl MixerInput {
    /// Constructor for a mixer input.
    pub fn new(node: Rc<RefCell<Node>>) -> MixerInput {
        MixerInput {
            node: node,
            vol: 1f32,
            pan: 0f32
        }
    }
}

/// The DSP Node contains a vector of children
/// nodes (within the `MixerInput`s), from which
/// audio can be requested as well as the current
/// SoundStream settings.
#[deriving(Show, Clone)]
pub struct Node {
    inputs: Vec<MixerInput>,
    settings: SoundStreamSettings,
    master_vol: f32
}

/// DSP Node trait. Implement this for any audio
/// instrument or effects types. Be sure to add
/// the `Node` struct to a field as well, and
/// override the `get_node` and `get_node_mut`
/// methods by returning a ref (/mut) to it.
pub trait IsNode {

    /// Return a reference to the Node.
    fn get_node<'a>(&'a self) -> &'a Node;
    /// Return a mutable reference to the Node.
    fn get_node_mut<'a>(&'a mut self) -> &'a mut Node;

    /// Apply settings to self and all inputs.
    fn apply_settings(&mut self, settings: SoundStreamSettings) {
        for input in self.get_node_mut().inputs.mut_iter() {
            input.node.borrow_mut().apply_settings(settings);
        }
        self.get_node_mut().settings = settings;
    }

    /// Add a new input.
    fn add_input(&mut self, input: Rc<RefCell<Node>>) {
        self.get_node_mut().inputs.push(MixerInput::new(input))
    }

    /// Remove an input. Find the input by comparing
    /// the address of the given input to each of the
    /// inputs' addresses.
    fn remove_input(&mut self, to_remove: &Node) {
        for i in range(0, self.get_node_mut().inputs.len()) {
            if &(*self.get_node_mut().inputs.get(i).node.borrow()) as *_ == to_remove as *_ {
                self.get_node_mut().inputs.remove(i);
                break;
            }
        }
    }

    /// Remove all inputs from the `inputs` vector.
    fn remove_all_inputs(&mut self) {
        self.get_node_mut().inputs.clear();
    }

    /// Add all inputs held by another node.
    fn add_inputs_from(&mut self, other: &Node) {
        self.get_node_mut().inputs.push_all(other.inputs.as_slice());
    }

    /// Receive incoming audio (override this
    /// to do something with the input).
    fn audio_received(&mut self, input: &Vec<f32>) {}

    /// Request audio from inputs, process and
    /// pass back to the output! Override this
    /// method for any synthesis or generative
    /// types.
    fn audio_requested(&mut self, output: &mut Vec<f32>) {
        let master_vol = self.get_node_mut().master_vol;
        let frames = self.get_node_mut().settings.frames as uint;
        let channels = self.get_node_mut().settings.channels as uint;
        let mut vol_per_channel: Vec<f32> = Vec::from_elem(channels, 1f32);
        for i in range(0, self.get_node_mut().inputs.len()) {
            let input = self.get_node_mut().inputs.get(i);
            let mut working: Vec<f32> =
                Vec::from_elem((frames * channels) as uint, 0f32);

            // Call audio_requested for each input.
            input.node.borrow_mut().audio_requested(&mut working);

            // Construct precalculated volume and
            // pan array (for efficiency).
            let vol_l: f32 = input.vol * (1f32 - input.pan);
            let vol_r: f32 = input.vol * input.pan;
            for j in range(0, vol_per_channel.len()) {
                *vol_per_channel.get_mut(j) = if j == 0 { vol_l } else { vol_r } * master_vol;
            }

            // Sum all input nodes to output (considering
            // pan, vol and interleaving).
            for j in range(0, frames) {
                for k in range(0, channels) {
                    *output.get_mut(j * channels + k) +=
                        *working.get(j * channels + k) * *vol_per_channel.get(k);
                }
            }
        }
        // Custom buffer processing.
        self.get_node_mut().process_buffer(output);
    }

    /// Override for custom processing of audio per
    /// buffer. This is mainly for audio effects. Get's
    /// called at the end of audio_requested.
    fn process_buffer(&mut self, output: &mut Vec<f32>) {}

}

/// We only have to implement these two methods
/// for any of our types that derive from our
/// `IsNode` DSP node trait.
impl IsNode for Node {
    fn get_node<'a>(&'a self) -> &'a Node { self }
    fn get_node_mut<'a>(&'a mut self) -> &'a mut Node { self }
}

impl Node {
    /// Constructor for the DSP Node.
    pub fn new(settings: SoundStreamSettings) -> Node {
        Node {
            inputs: Vec::new(),
            settings: settings,
            master_vol: 1f32
        }
    }
}

<|endoftext|>


<commit_before>use std::io::Read;
use std::net::{self, SocketAddr};
#[cfg(unix)]
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
use std::sync::{Arc, Barrier};
use std::thread;

use mio::net::TcpListener;
use mio::{Interests, Poll, Token};

mod util;

use util::{
    any_local_address, any_local_ipv6_address, assert_send, assert_sync, assert_would_block,
    expect_events, expect_no_events, init, init_with_poll, ExpectEvent,
};

const ID1: Token = Token(0);
const ID2: Token = Token(1);

#[test]
fn is_send_and_sync() {
    assert_send::<TcpListener>();
    assert_sync::<TcpListener>();
}

#[test]
fn tcp_listener() {
    smoke_test_tcp_listener(any_local_address());
}

#[test]
fn tcp_listener_ipv6() {
    smoke_test_tcp_listener(any_local_ipv6_address());
}

fn smoke_test_tcp_listener(addr: SocketAddr) {
    let (mut poll, mut events) = init_with_poll();

    let listener = TcpListener::bind(addr).unwrap();
    let address = listener.local_addr().unwrap();

    poll.registry()
        .register(&listener, ID1, Interests::READABLE)
        .expect("unable to register TCP listener");

    let barrier = Arc::new(Barrier::new(2));
    let thread_handle = start_connections(address, 1, barrier.clone());

    expect_events(
        &mut poll,
        &mut events,
        vec![ExpectEvent::new(ID1, Interests::READABLE)],
    );

    // Expect a single connection.
    let (mut stream, peer_address) = listener.accept().expect("unable to accept connection");
    assert!(peer_address.ip().is_loopback());
    assert_eq!(stream.peer_addr().unwrap(), peer_address);
    assert_eq!(stream.local_addr().unwrap(), address);

    // Expect the stream to be non-blocking.
    let mut buf = [0; 20];
    assert_would_block(stream.read(&mut buf));

    // Expect no more connections.
    assert_would_block(listener.accept());

    assert!(listener.take_error().unwrap().is_none());

    barrier.wait();
    thread_handle.join().expect("unable to join thread");
}

#[test]
fn ttl() {
    init();

    let listener = TcpListener::bind(any_local_address()).unwrap();

    const TTL: u32 = 10;
    listener.set_ttl(TTL).unwrap();
    assert_eq!(listener.ttl().unwrap(), TTL);
    assert!(listener.take_error().unwrap().is_none());
}

#[test]
#[cfg(unix)]
fn raw_fd() {
    init();

    let listener = TcpListener::bind(any_local_address()).unwrap();
    let address = listener.local_addr().unwrap();

    let raw_fd1 = listener.as_raw_fd();
    let raw_fd2 = listener.into_raw_fd();
    assert_eq!(raw_fd1, raw_fd2);

    let listener = unsafe { TcpListener::from_raw_fd(raw_fd2) };
    assert_eq!(listener.as_raw_fd(), raw_fd1);
    assert_eq!(listener.local_addr().unwrap(), address);
}

#[test]
fn registering() {
    let (mut poll, mut events) = init_with_poll();

    let stream = TcpListener::bind(any_local_address()).unwrap();

    poll.registry()
        .register(&stream, ID1, Interests::READABLE)
        .expect("unable to register TCP listener");

    expect_no_events(&mut poll, &mut events);

    // NOTE: more tests are done in the smoke tests above.
}

#[test]
fn reregister() {
    let (mut poll, mut events) = init_with_poll();

    let listener = TcpListener::bind(any_local_address()).unwrap();
    let address = listener.local_addr().unwrap();

    poll.registry()
        .register(&listener, ID1, Interests::READABLE)
        .unwrap();
    poll.registry()
        .reregister(&listener, ID2, Interests::READABLE)
        .unwrap();

    let barrier = Arc::new(Barrier::new(2));
    let thread_handle = start_connections(address, 1, barrier.clone());

    expect_events(
        &mut poll,
        &mut events,
        vec![ExpectEvent::new(ID2, Interests::READABLE)],
    );

    let (stream, peer_address) = listener.accept().expect("unable to accept connection");
    assert!(peer_address.ip().is_loopback());
    assert_eq!(stream.peer_addr().unwrap(), peer_address);
    assert_eq!(stream.local_addr().unwrap(), address);

    assert_would_block(listener.accept());

    assert!(listener.take_error().unwrap().is_none());

    barrier.wait();
    thread_handle.join().expect("unable to join thread");
}

#[test]
fn deregister() {
    let (mut poll, mut events) = init_with_poll();

    let listener = TcpListener::bind(any_local_address()).unwrap();
    let address = listener.local_addr().unwrap();

    poll.registry()
        .register(&listener, ID1, Interests::READABLE)
        .unwrap();

    let barrier = Arc::new(Barrier::new(2));
    let thread_handle = start_connections(address, 1, barrier.clone());

    poll.registry().deregister(&listener).unwrap();

    expect_no_events(&mut poll, &mut events);

    // Should still be able to accept the connection.
    let (stream, peer_address) = listener.accept().expect("unable to accept connection");
    assert!(peer_address.ip().is_loopback());
    assert_eq!(stream.peer_addr().unwrap(), peer_address);
    assert_eq!(stream.local_addr().unwrap(), address);

    assert_would_block(listener.accept());

    assert!(listener.take_error().unwrap().is_none());

    barrier.wait();
    thread_handle.join().expect("unable to join thread");
}

#[test]
fn try_clone_same_poll() {
    let (mut poll, mut events) = init_with_poll();

    let listener1 = TcpListener::bind(any_local_address()).unwrap();
    let listener2 = listener1.try_clone().expect("unable to clone TCP listener");
    #[cfg(unix)]
    assert_ne!(listener1.as_raw_fd(), listener2.as_raw_fd());
    let address = listener1.local_addr().unwrap();
    assert_eq!(address, listener2.local_addr().unwrap());

    let barrier = Arc::new(Barrier::new(3));
    let thread_handle1 = start_connections(address, 1, barrier.clone());
    let thread_handle2 = start_connections(address, 1, barrier.clone());

    poll.registry()
        .register(&listener1, ID1, Interests::READABLE)
        .unwrap();
    poll.registry()
        .register(&listener2, ID2, Interests::READABLE)
        .unwrap();

    expect_events(
        &mut poll,
        &mut events,
        vec![
            ExpectEvent::new(ID1, Interests::READABLE),
            ExpectEvent::new(ID2, Interests::READABLE),
        ],
    );

    let (stream, peer_address) = listener1.accept().expect("unable to accept connection");
    assert!(peer_address.ip().is_loopback());
    assert_eq!(stream.peer_addr().unwrap(), peer_address);
    assert_eq!(stream.local_addr().unwrap(), address);

    let (stream, peer_address) = listener2.accept().expect("unable to accept connection");
    assert!(peer_address.ip().is_loopback());
    assert_eq!(stream.peer_addr().unwrap(), peer_address);
    assert_eq!(stream.local_addr().unwrap(), address);

    assert_would_block(listener1.accept());
    assert_would_block(listener2.accept());

    assert!(listener1.take_error().unwrap().is_none());
    assert!(listener2.take_error().unwrap().is_none());

    barrier.wait();
    thread_handle1.join().expect("unable to join thread");
    thread_handle2.join().expect("unable to join thread");
}

#[test]
fn try_clone_different_poll() {
    let (mut poll1, mut events) = init_with_poll();
    let mut poll2 = Poll::new().unwrap();

    let listener1 = TcpListener::bind(any_local_address()).unwrap();
    let listener2 = listener1.try_clone().expect("unable to clone TCP listener");
    #[cfg(unix)]
    assert_ne!(listener1.as_raw_fd(), listener2.as_raw_fd());
    let address = listener1.local_addr().unwrap();
    assert_eq!(address, listener2.local_addr().unwrap());

    let barrier = Arc::new(Barrier::new(3));
    let thread_handle1 = start_connections(address, 1, barrier.clone());
    let thread_handle2 = start_connections(address, 1, barrier.clone());

    poll1
        .registry()
        .register(&listener1, ID1, Interests::READABLE)
        .unwrap();
    poll2
        .registry()
        .register(&listener2, ID2, Interests::READABLE)
        .unwrap();

    expect_events(
        &mut poll1,
        &mut events,
        vec![ExpectEvent::new(ID1, Interests::READABLE)],
    );
    expect_events(
        &mut poll2,
        &mut events,
        vec![ExpectEvent::new(ID2, Interests::READABLE)],
    );

    let (stream, peer_address) = listener1.accept().expect("unable to accept connection");
    assert!(peer_address.ip().is_loopback());
    assert_eq!(stream.peer_addr().unwrap(), peer_address);
    assert_eq!(stream.local_addr().unwrap(), address);

    let (stream, peer_address) = listener2.accept().expect("unable to accept connection");
    assert!(peer_address.ip().is_loopback());
    assert_eq!(stream.peer_addr().unwrap(), peer_address);
    assert_eq!(stream.local_addr().unwrap(), address);

    assert_would_block(listener1.accept());
    assert_would_block(listener2.accept());

    assert!(listener1.take_error().unwrap().is_none());
    assert!(listener2.take_error().unwrap().is_none());

    barrier.wait();
    thread_handle1.join().expect("unable to join thread");
    thread_handle2.join().expect("unable to join thread");
}

/// Start `n_connections` connections to `address`. If a `barrier` is provided
/// it will wait on it after each connection is made before it is dropped.
fn start_connections(
    address: SocketAddr,
    n_connections: usize,
    barrier: Arc<Barrier>,
) -> thread::JoinHandle<()> {
    thread::spawn(move || {
        for _ in 0..n_connections {
            let conn = net::TcpStream::connect(address).unwrap();
            barrier.wait();
            drop(conn);
        }
    })
}
<commit_msg>Disable TcpListener deregister test on Windows<commit_after>use std::io::Read;
use std::net::{self, SocketAddr};
#[cfg(unix)]
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
use std::sync::{Arc, Barrier};
use std::thread;

use mio::net::TcpListener;
use mio::{Interests, Poll, Token};

mod util;

use util::{
    any_local_address, any_local_ipv6_address, assert_send, assert_sync, assert_would_block,
    expect_events, expect_no_events, init, init_with_poll, ExpectEvent,
};

const ID1: Token = Token(0);
const ID2: Token = Token(1);

#[test]
fn is_send_and_sync() {
    assert_send::<TcpListener>();
    assert_sync::<TcpListener>();
}

#[test]
fn tcp_listener() {
    smoke_test_tcp_listener(any_local_address());
}

#[test]
fn tcp_listener_ipv6() {
    smoke_test_tcp_listener(any_local_ipv6_address());
}

fn smoke_test_tcp_listener(addr: SocketAddr) {
    let (mut poll, mut events) = init_with_poll();

    let listener = TcpListener::bind(addr).unwrap();
    let address = listener.local_addr().unwrap();

    poll.registry()
        .register(&listener, ID1, Interests::READABLE)
        .expect("unable to register TCP listener");

    let barrier = Arc::new(Barrier::new(2));
    let thread_handle = start_connections(address, 1, barrier.clone());

    expect_events(
        &mut poll,
        &mut events,
        vec![ExpectEvent::new(ID1, Interests::READABLE)],
    );

    // Expect a single connection.
    let (mut stream, peer_address) = listener.accept().expect("unable to accept connection");
    assert!(peer_address.ip().is_loopback());
    assert_eq!(stream.peer_addr().unwrap(), peer_address);
    assert_eq!(stream.local_addr().unwrap(), address);

    // Expect the stream to be non-blocking.
    let mut buf = [0; 20];
    assert_would_block(stream.read(&mut buf));

    // Expect no more connections.
    assert_would_block(listener.accept());

    assert!(listener.take_error().unwrap().is_none());

    barrier.wait();
    thread_handle.join().expect("unable to join thread");
}

#[test]
fn ttl() {
    init();

    let listener = TcpListener::bind(any_local_address()).unwrap();

    const TTL: u32 = 10;
    listener.set_ttl(TTL).unwrap();
    assert_eq!(listener.ttl().unwrap(), TTL);
    assert!(listener.take_error().unwrap().is_none());
}

#[test]
#[cfg(unix)]
fn raw_fd() {
    init();

    let listener = TcpListener::bind(any_local_address()).unwrap();
    let address = listener.local_addr().unwrap();

    let raw_fd1 = listener.as_raw_fd();
    let raw_fd2 = listener.into_raw_fd();
    assert_eq!(raw_fd1, raw_fd2);

    let listener = unsafe { TcpListener::from_raw_fd(raw_fd2) };
    assert_eq!(listener.as_raw_fd(), raw_fd1);
    assert_eq!(listener.local_addr().unwrap(), address);
}

#[test]
fn registering() {
    let (mut poll, mut events) = init_with_poll();

    let stream = TcpListener::bind(any_local_address()).unwrap();

    poll.registry()
        .register(&stream, ID1, Interests::READABLE)
        .expect("unable to register TCP listener");

    expect_no_events(&mut poll, &mut events);

    // NOTE: more tests are done in the smoke tests above.
}

#[test]
fn reregister() {
    let (mut poll, mut events) = init_with_poll();

    let listener = TcpListener::bind(any_local_address()).unwrap();
    let address = listener.local_addr().unwrap();

    poll.registry()
        .register(&listener, ID1, Interests::READABLE)
        .unwrap();
    poll.registry()
        .reregister(&listener, ID2, Interests::READABLE)
        .unwrap();

    let barrier = Arc::new(Barrier::new(2));
    let thread_handle = start_connections(address, 1, barrier.clone());

    expect_events(
        &mut poll,
        &mut events,
        vec![ExpectEvent::new(ID2, Interests::READABLE)],
    );

    let (stream, peer_address) = listener.accept().expect("unable to accept connection");
    assert!(peer_address.ip().is_loopback());
    assert_eq!(stream.peer_addr().unwrap(), peer_address);
    assert_eq!(stream.local_addr().unwrap(), address);

    assert_would_block(listener.accept());

    assert!(listener.take_error().unwrap().is_none());

    barrier.wait();
    thread_handle.join().expect("unable to join thread");
}

#[test]
#[cfg_attr(windows, ignore = "deregister doesn't work, see #1073")]
fn deregister() {
    let (mut poll, mut events) = init_with_poll();

    let listener = TcpListener::bind(any_local_address()).unwrap();
    let address = listener.local_addr().unwrap();

    poll.registry()
        .register(&listener, ID1, Interests::READABLE)
        .unwrap();

    let barrier = Arc::new(Barrier::new(2));
    let thread_handle = start_connections(address, 1, barrier.clone());

    poll.registry().deregister(&listener).unwrap();

    expect_no_events(&mut poll, &mut events);

    // Should still be able to accept the connection.
    let (stream, peer_address) = listener.accept().expect("unable to accept connection");
    assert!(peer_address.ip().is_loopback());
    assert_eq!(stream.peer_addr().unwrap(), peer_address);
    assert_eq!(stream.local_addr().unwrap(), address);

    assert_would_block(listener.accept());

    assert!(listener.take_error().unwrap().is_none());

    barrier.wait();
    thread_handle.join().expect("unable to join thread");
}

#[test]
fn try_clone_same_poll() {
    let (mut poll, mut events) = init_with_poll();

    let listener1 = TcpListener::bind(any_local_address()).unwrap();
    let listener2 = listener1.try_clone().expect("unable to clone TCP listener");
    #[cfg(unix)]
    assert_ne!(listener1.as_raw_fd(), listener2.as_raw_fd());
    let address = listener1.local_addr().unwrap();
    assert_eq!(address, listener2.local_addr().unwrap());

    let barrier = Arc::new(Barrier::new(3));
    let thread_handle1 = start_connections(address, 1, barrier.clone());
    let thread_handle2 = start_connections(address, 1, barrier.clone());

    poll.registry()
        .register(&listener1, ID1, Interests::READABLE)
        .unwrap();
    poll.registry()
        .register(&listener2, ID2, Interests::READABLE)
        .unwrap();

    expect_events(
        &mut poll,
        &mut events,
        vec![
            ExpectEvent::new(ID1, Interests::READABLE),
            ExpectEvent::new(ID2, Interests::READABLE),
        ],
    );

    let (stream, peer_address) = listener1.accept().expect("unable to accept connection");
    assert!(peer_address.ip().is_loopback());
    assert_eq!(stream.peer_addr().unwrap(), peer_address);
    assert_eq!(stream.local_addr().unwrap(), address);

    let (stream, peer_address) = listener2.accept().expect("unable to accept connection");
    assert!(peer_address.ip().is_loopback());
    assert_eq!(stream.peer_addr().unwrap(), peer_address);
    assert_eq!(stream.local_addr().unwrap(), address);

    assert_would_block(listener1.accept());
    assert_would_block(listener2.accept());

    assert!(listener1.take_error().unwrap().is_none());
    assert!(listener2.take_error().unwrap().is_none());

    barrier.wait();
    thread_handle1.join().expect("unable to join thread");
    thread_handle2.join().expect("unable to join thread");
}

#[test]
fn try_clone_different_poll() {
    let (mut poll1, mut events) = init_with_poll();
    let mut poll2 = Poll::new().unwrap();

    let listener1 = TcpListener::bind(any_local_address()).unwrap();
    let listener2 = listener1.try_clone().expect("unable to clone TCP listener");
    #[cfg(unix)]
    assert_ne!(listener1.as_raw_fd(), listener2.as_raw_fd());
    let address = listener1.local_addr().unwrap();
    assert_eq!(address, listener2.local_addr().unwrap());

    let barrier = Arc::new(Barrier::new(3));
    let thread_handle1 = start_connections(address, 1, barrier.clone());
    let thread_handle2 = start_connections(address, 1, barrier.clone());

    poll1
        .registry()
        .register(&listener1, ID1, Interests::READABLE)
        .unwrap();
    poll2
        .registry()
        .register(&listener2, ID2, Interests::READABLE)
        .unwrap();

    expect_events(
        &mut poll1,
        &mut events,
        vec![ExpectEvent::new(ID1, Interests::READABLE)],
    );
    expect_events(
        &mut poll2,
        &mut events,
        vec![ExpectEvent::new(ID2, Interests::READABLE)],
    );

    let (stream, peer_address) = listener1.accept().expect("unable to accept connection");
    assert!(peer_address.ip().is_loopback());
    assert_eq!(stream.peer_addr().unwrap(), peer_address);
    assert_eq!(stream.local_addr().unwrap(), address);

    let (stream, peer_address) = listener2.accept().expect("unable to accept connection");
    assert!(peer_address.ip().is_loopback());
    assert_eq!(stream.peer_addr().unwrap(), peer_address);
    assert_eq!(stream.local_addr().unwrap(), address);

    assert_would_block(listener1.accept());
    assert_would_block(listener2.accept());

    assert!(listener1.take_error().unwrap().is_none());
    assert!(listener2.take_error().unwrap().is_none());

    barrier.wait();
    thread_handle1.join().expect("unable to join thread");
    thread_handle2.join().expect("unable to join thread");
}

/// Start `n_connections` connections to `address`. If a `barrier` is provided
/// it will wait on it after each connection is made before it is dropped.
fn start_connections(
    address: SocketAddr,
    n_connections: usize,
    barrier: Arc<Barrier>,
) -> thread::JoinHandle<()> {
    thread::spawn(move || {
        for _ in 0..n_connections {
            let conn = net::TcpStream::connect(address).unwrap();
            barrier.wait();
            drop(conn);
        }
    })
}
<|endoftext|>


<commit_before>//! The Ref object is a helper over the link functionality, so one is able to create references to
//! files outside of the imag store.

use std::path::PathBuf;
use std::ops::Deref;
use std::ops::DerefMut;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::Read;

use libimagstore::store::FileLockEntry;
use libimagstore::storeid::StoreId;
use libimagstore::storeid::IntoStoreId;
use libimagstore::store::Store;
use libimagerror::into::IntoError;

use toml::Value;
use crypto::sha1::Sha1;
use crypto::digest::Digest;

use error::RefErrorKind as REK;
use flags::RefFlags;
use result::Result;
use module_path::ModuleEntryPath;

pub struct Ref<'a>(FileLockEntry<'a>);

impl<'a> Ref<'a> {

    /// Try to get `si` as Ref object from the store
    pub fn get(store: &'a Store, si: StoreId) -> Result<Ref<'a>> {
        match store.get(si) {
            Err(e) => return Err(REK::StoreReadError.into_error_with_cause(Box::new(e))),
            Ok(None) => return Err(REK::RefNotInStore.into_error()),
            Ok(Some(fle)) => Ref::read_reference(&fle).map(|_| Ref(fle)),
        }
    }

    fn read_reference(fle: &FileLockEntry<'a>) -> Result<PathBuf> {
        match fle.get_header().read("ref.reference") {
            Ok(Some(Value::String(s))) => Ok(PathBuf::from(s)),
            Ok(Some(_)) => Err(REK::HeaderTypeError.into_error()),
            Ok(None)    => Err(REK::HeaderFieldMissingError.into_error()),
            Err(e)      => Err(REK::StoreReadError.into_error_with_cause(Box::new(e))),
        }
    }

    /// Create a Ref object which refers to `pb`
    pub fn create(store: &'a Store, pb: PathBuf, flags: RefFlags) -> Result<Ref<'a>> {
        if !pb.exists() {
            return Err(REK::RefTargetDoesNotExist.into_error());
        }
        if flags.get_content_hashing() && pb.is_dir() {
            return Err(REK::RefTargetCannotBeHashed.into_error());
        }

        let (mut fle, content_hash, permissions, canonical_path) = { // scope to be able to fold
            try!(File::open(pb.clone())
                .map_err(Box::new)
                .map_err(|e| REK::RefTargetFileCannotBeOpened.into_error_with_cause(e))

                // If we were able to open this file,
                // we hash the contents of the file and return (file, hash)
                .and_then(|mut file| {
                    let opt_contenthash = if flags.get_content_hashing() {
                        Some(hash_file_contents(&mut file))
                    } else {
                        None
                    };

                    Ok((file, opt_contenthash))
                })

                // and then we get the permissions if we have to
                // and return (file, content hash, permissions)
                .and_then(|(file, opt_contenthash)| {
                    let opt_permissions = if flags.get_permission_tracking() {
                        Some(try!(file
                                  .metadata()
                                  .map(|md| md.permissions())
                                  .map_err(Box::new)
                                  .map_err(|e| REK::RefTargetCannotReadPermissions.into_error_with_cause(e))
                        ))
                    } else {
                        None
                    };

                    Ok((file, opt_contenthash, opt_permissions))
                })

                // and then we try to canonicalize the PathBuf, because we want to store a
                // canonicalized path
                // and return (file, content hash, permissions, canonicalized path)
                .and_then(|(file, opt_contenthash, opt_permissions)| {
                    pb.canonicalize()
                        .map(|can| (file, opt_contenthash, opt_permissions, can))
                        // if PathBuf::canonicalize() failed, build an error from the return value
                        .map_err(|e| REK::PathCanonicalizationError.into_error_with_cause(Box::new(e)))
                })

                // and then we hash the canonicalized path
                // and return (file, content hash, permissions, canonicalized path, path hash)
                .and_then(|(file, opt_contenthash, opt_permissions, can)| {
                    let path_hash = try!(Ref::hash_path(&can)
                        .map_err(Box::new)
                        .map_err(|e| REK::PathHashingError.into_error_with_cause(e))
                    );

                    Ok((file, opt_contenthash, opt_permissions, can, path_hash))
                })

                // and then we convert the PathBuf of the canonicalized path to a String to be able
                // to save it in the Ref FileLockEntry obj
                // and return
                // (file, content hash, permissions, canonicalized path as String, path hash)
                .and_then(|(file, opt_conhash, opt_perm, can, path_hash)| {
                    match can.to_str().map(String::from) {
                        // UTF convert error in PathBuf::to_str(),
                        None      => Err(REK::PathUTF8Error.into_error()),
                        Some(can) => Ok((file, opt_conhash, opt_perm, can, path_hash))
                    }
                })

                // and then we create the FileLockEntry in the Store
                // and return (filelockentry, content hash, permissions, canonicalized path)
                .and_then(|(file, opt_conhash, opt_perm, can, path_hash)| {
                    let fle = try!(store
                                   .create(ModuleEntryPath::new(path_hash))
                                   .map_err(Box::new)
                                   .map_err(|e| REK::StoreWriteError.into_error_with_cause(e))
                    );

                    Ok((fle, opt_conhash, opt_perm, can))
                })
            )
        };

        for tpl in [
                Some(("ref",             Value::Table(BTreeMap::new()))),
                Some(("ref.permissions", Value::Table(BTreeMap::new()))),

                Some(("ref.path", Value::String(canonical_path))),

                content_hash.map(|h| ("ref.content_hash", Value::String(h))),
                permissions.map(|p| ("ref.permissions.ro", Value::Boolean(p.readonly()))),
            ].into_iter()
        {
            match tpl {
                &Some((ref s, ref v)) => {
                    match fle.get_header_mut().insert(s, v.clone()) {
                        Ok(false) => {
                            let e = REK::HeaderFieldAlreadyExistsError.into_error();
                            let e = Box::new(e);
                            let e = REK::HeaderFieldWriteError.into_error_with_cause(e);
                            return Err(e);
                        },
                        Err(e) => {
                            let e = Box::new(e);
                            let e = REK::HeaderFieldWriteError.into_error_with_cause(e);
                            return Err(e);
                        },
                        _ => (),
                    }
                }
                &None => {
                    debug!("Not going to insert.");
                }
            }
        }

        Ok(Ref(fle))
    }

    /// Creates a Hash from a PathBuf by making the PathBuf absolute and then running a hash
    /// algorithm on it
    fn hash_path(pb: &PathBuf) -> Result<String> {
        use std::io::Read;
        use crypto::sha1::Sha1;
        use crypto::digest::Digest;

        match pb.to_str() {
            Some(s) => {
                let mut hasher = Sha1::new();
                hasher.input_str(s);
                Ok(hasher.result_str())
            },
            None => return Err(REK::PathUTF8Error.into_error()),
        }
    }

    /// check whether the pointer the Ref represents still points to a file which exists
    pub fn fs_link_exists(&self) -> Result<bool> {
        self.fs_file().map(|pathbuf| pathbuf.exists())
    }

    /// Alias for `r.fs_link_exists() && r.deref().is_file()`
    pub fn is_ref_to_file(&self) -> Result<bool> {
        self.fs_file().map(|pathbuf| pathbuf.is_file())
    }

    /// Alias for `r.fs_link_exists() && r.deref().is_dir()`
    pub fn is_ref_to_dir(&self) -> Result<bool> {
        self.fs_file().map(|pathbuf| pathbuf.is_dir())
    }

    /// Alias for `!Ref::fs_link_exists()`
    pub fn is_dangling(&self) -> Result<bool> {
        self.fs_link_exists().map(|b| !b)
    }

    /// check whether the pointer the Ref represents is valid
    /// This includes:
    ///     - Hashsum of the file is still the same as stored in the Ref
    ///     - file permissions are still valid
    pub fn fs_link_valid(&self) -> bool {
        unimplemented!()
    }

    /// Check whether the file permissions of the referenced file are equal to the stored
    /// permissions
    pub fn fs_link_valid_permissions(&self) -> Result<bool> {
        self.0
            .get_header()
            .read("ref.permissions.ro")
            .map_err(Box::new)
            .map_err(|e| REK::HeaderFieldReadError.into_error_with_cause(e))
            .and_then(|ro| {
                match ro {
                    Some(Value::Boolean(b)) => Ok(b),
                    Some(_)                 => Err(REK::HeaderTypeError.into_error()),
                    None                    => Err(REK::HeaderFieldMissingError.into_error()),
                }
            })
            .and_then(|ro| self.fs_file().map(|pb| (ro, pb)))
            .and_then(|(ro, pb)| {
                File::open(pb)
                    .map(|file| (ro, file))
                    .map_err(Box::new)
                    .map_err(|e| REK::HeaderFieldReadError.into_error_with_cause(e))
            })
            .and_then(|(ro, file)| {
                file
                    .metadata()
                    .map(|md| md.permissions())
                    .map(|perm| perm.readonly() == ro)
                    .map_err(Box::new)
                    .map_err(|e| REK::RefTargetCannotReadPermissions.into_error_with_cause(e))
            })
            .map_err(Box::new)
            .map_err(|e| REK::RefTargetCannotReadPermissions.into_error_with_cause(e))
    }

    /// Check whether the Hashsum of the referenced file is equal to the stored hashsum
    pub fn fs_link_valid_hash(&self) -> Result<bool> {
        let stored_hash = try!(match self.0.get_header().read("ref.content_hash") {
            // content hash stored...
            Ok(Some(Value::String(s))) => Ok(s),

            // content hash header field has wrong type
            Ok(Some(_)) => Err(REK::HeaderTypeError.into_error()),

            // content hash not stored
            Ok(None) => Err(REK::HeaderFieldMissingError.into_error()),

            // Error
            Err(e) => Err(REK::StoreReadError.into_error_with_cause(Box::new(e))),
        });

        let current_hash = try!(self.fs_file()
            .and_then(|pb| {
                File::open(pb)
                    .map_err(Box::new)
                    .map_err(|e| REK::IOError.into_error_with_cause(e))
            })
            .map(|mut file| hash_file_contents(&mut file))
        );

        Ok(stored_hash == current_hash)
    }

    /// Update the Ref by re-checking the file from FS
    /// This errors if the file is not present or cannot be read()
    pub fn update_ref(&mut self) -> Result<()> {
        unimplemented!()
    }

    /// Get the path of the file which is reffered to by this Ref
    pub fn fs_file(&self) -> Result<PathBuf> {
        match self.0.get_header().read("ref.path") {
            Ok(Some(Value::String(ref s))) => Ok(PathBuf::from(s)),
            Ok(Some(_)) => Err(REK::HeaderTypeError.into_error()),
            Ok(None)    => Err(REK::HeaderFieldMissingError.into_error()),
            Err(e)      => Err(REK::StoreReadError.into_error_with_cause(Box::new(e))),
        }
    }

    /// Check whether there is a reference to the file at `pb`
    pub fn exists(store: &Store, pb: PathBuf) -> Result<bool> {
        pb.canonicalize()
            .map_err(Box::new)
            .map_err(|e| REK::PathCanonicalizationError.into_error_with_cause(e))
            .and_then(|can| {
                Ref::hash_path(&can)
                    .map_err(Box::new)
                    .map_err(|e| REK::PathHashingError.into_error_with_cause(e))
            })
            .and_then(|hash| {
                store.retrieve_for_module("ref").map(|iter| (hash, iter))
                    .map_err(Box::new)
                    .map_err(|e| REK::StoreReadError.into_error_with_cause(e))
            })
            .and_then(|(hash, possible_refs)| {
                // This is kind of a manual Iterator::filter() call what we do here, but with the
                // actual ::filter method we cannot return the error in a nice way, so we do it
                // manually here. If you can come up with a better version of this, feel free to
                // take this note as a todo.
                for r in possible_refs {
                    let contains_hash = match r.to_str() {
                        None => { // couldn't parse StoreId -> PathBuf -> &str
                            // TODO: How to report this?
                            return Err(REK::TypeConversionError.into_error());
                        },
                        Some(s) => s.contains(&hash[..]),
                    };

                    if !contains_hash {
                        continue;
                    }

                    match store.get(r) {
                        Ok(Some(fle)) => {
                            if Ref::read_reference(&fle).map(|path| path == pb).unwrap_or(false) {
                                return Ok(true)
                            }
                        },

                        Ok(None) => { // Something weird just happened
                            return Err(REK::StoreReadError.into_error());
                        },

                        Err(e) => {
                            return Err(REK::StoreReadError.into_error_with_cause(Box::new(e)));
                        },
                    }
                }

                Ok(false)
            })
    }

    /// Re-find a referenced file
    ///
    /// This function tries to re-find a ref by searching all directories in `search_roots` recursively
    /// for a file which matches the hash of the Ref `ref`.
    ///
    /// If `search_roots` is `None`, it starts at the filesystem root `/`.
    ///
    /// # Warning
    ///
    /// This option causes heavy I/O as it recursively searches the Filesystem.
    pub fn refind(&self, search_roots: Option<Vec<PathBuf>>) -> Option<PathBuf> {
        unimplemented!()
    }

}

impl<'a> Deref for Ref<'a> {
    type Target = FileLockEntry<'a>;

    fn deref(&self) -> &FileLockEntry<'a> {
        &self.0
    }

}

impl<'a> DerefMut for Ref<'a> {

    fn deref_mut(&mut self) -> &mut FileLockEntry<'a> {
        &mut self.0
    }

}

fn hash_file_contents(f: &mut File) -> String {
    let mut hasher = Sha1::new();
    let mut s = String::new();
    f.read_to_string(&mut s);
    hasher.input_str(&s[..]);
    hasher.result_str()
}

<commit_msg>Impl Ref::fs_link_valid()<commit_after>//! The Ref object is a helper over the link functionality, so one is able to create references to
//! files outside of the imag store.

use std::path::PathBuf;
use std::ops::Deref;
use std::ops::DerefMut;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::Read;

use libimagstore::store::FileLockEntry;
use libimagstore::storeid::StoreId;
use libimagstore::storeid::IntoStoreId;
use libimagstore::store::Store;
use libimagerror::into::IntoError;

use toml::Value;
use crypto::sha1::Sha1;
use crypto::digest::Digest;

use error::RefErrorKind as REK;
use flags::RefFlags;
use result::Result;
use module_path::ModuleEntryPath;

pub struct Ref<'a>(FileLockEntry<'a>);

impl<'a> Ref<'a> {

    /// Try to get `si` as Ref object from the store
    pub fn get(store: &'a Store, si: StoreId) -> Result<Ref<'a>> {
        match store.get(si) {
            Err(e) => return Err(REK::StoreReadError.into_error_with_cause(Box::new(e))),
            Ok(None) => return Err(REK::RefNotInStore.into_error()),
            Ok(Some(fle)) => Ref::read_reference(&fle).map(|_| Ref(fle)),
        }
    }

    fn read_reference(fle: &FileLockEntry<'a>) -> Result<PathBuf> {
        match fle.get_header().read("ref.reference") {
            Ok(Some(Value::String(s))) => Ok(PathBuf::from(s)),
            Ok(Some(_)) => Err(REK::HeaderTypeError.into_error()),
            Ok(None)    => Err(REK::HeaderFieldMissingError.into_error()),
            Err(e)      => Err(REK::StoreReadError.into_error_with_cause(Box::new(e))),
        }
    }

    /// Create a Ref object which refers to `pb`
    pub fn create(store: &'a Store, pb: PathBuf, flags: RefFlags) -> Result<Ref<'a>> {
        if !pb.exists() {
            return Err(REK::RefTargetDoesNotExist.into_error());
        }
        if flags.get_content_hashing() && pb.is_dir() {
            return Err(REK::RefTargetCannotBeHashed.into_error());
        }

        let (mut fle, content_hash, permissions, canonical_path) = { // scope to be able to fold
            try!(File::open(pb.clone())
                .map_err(Box::new)
                .map_err(|e| REK::RefTargetFileCannotBeOpened.into_error_with_cause(e))

                // If we were able to open this file,
                // we hash the contents of the file and return (file, hash)
                .and_then(|mut file| {
                    let opt_contenthash = if flags.get_content_hashing() {
                        Some(hash_file_contents(&mut file))
                    } else {
                        None
                    };

                    Ok((file, opt_contenthash))
                })

                // and then we get the permissions if we have to
                // and return (file, content hash, permissions)
                .and_then(|(file, opt_contenthash)| {
                    let opt_permissions = if flags.get_permission_tracking() {
                        Some(try!(file
                                  .metadata()
                                  .map(|md| md.permissions())
                                  .map_err(Box::new)
                                  .map_err(|e| REK::RefTargetCannotReadPermissions.into_error_with_cause(e))
                        ))
                    } else {
                        None
                    };

                    Ok((file, opt_contenthash, opt_permissions))
                })

                // and then we try to canonicalize the PathBuf, because we want to store a
                // canonicalized path
                // and return (file, content hash, permissions, canonicalized path)
                .and_then(|(file, opt_contenthash, opt_permissions)| {
                    pb.canonicalize()
                        .map(|can| (file, opt_contenthash, opt_permissions, can))
                        // if PathBuf::canonicalize() failed, build an error from the return value
                        .map_err(|e| REK::PathCanonicalizationError.into_error_with_cause(Box::new(e)))
                })

                // and then we hash the canonicalized path
                // and return (file, content hash, permissions, canonicalized path, path hash)
                .and_then(|(file, opt_contenthash, opt_permissions, can)| {
                    let path_hash = try!(Ref::hash_path(&can)
                        .map_err(Box::new)
                        .map_err(|e| REK::PathHashingError.into_error_with_cause(e))
                    );

                    Ok((file, opt_contenthash, opt_permissions, can, path_hash))
                })

                // and then we convert the PathBuf of the canonicalized path to a String to be able
                // to save it in the Ref FileLockEntry obj
                // and return
                // (file, content hash, permissions, canonicalized path as String, path hash)
                .and_then(|(file, opt_conhash, opt_perm, can, path_hash)| {
                    match can.to_str().map(String::from) {
                        // UTF convert error in PathBuf::to_str(),
                        None      => Err(REK::PathUTF8Error.into_error()),
                        Some(can) => Ok((file, opt_conhash, opt_perm, can, path_hash))
                    }
                })

                // and then we create the FileLockEntry in the Store
                // and return (filelockentry, content hash, permissions, canonicalized path)
                .and_then(|(file, opt_conhash, opt_perm, can, path_hash)| {
                    let fle = try!(store
                                   .create(ModuleEntryPath::new(path_hash))
                                   .map_err(Box::new)
                                   .map_err(|e| REK::StoreWriteError.into_error_with_cause(e))
                    );

                    Ok((fle, opt_conhash, opt_perm, can))
                })
            )
        };

        for tpl in [
                Some(("ref",             Value::Table(BTreeMap::new()))),
                Some(("ref.permissions", Value::Table(BTreeMap::new()))),

                Some(("ref.path", Value::String(canonical_path))),

                content_hash.map(|h| ("ref.content_hash", Value::String(h))),
                permissions.map(|p| ("ref.permissions.ro", Value::Boolean(p.readonly()))),
            ].into_iter()
        {
            match tpl {
                &Some((ref s, ref v)) => {
                    match fle.get_header_mut().insert(s, v.clone()) {
                        Ok(false) => {
                            let e = REK::HeaderFieldAlreadyExistsError.into_error();
                            let e = Box::new(e);
                            let e = REK::HeaderFieldWriteError.into_error_with_cause(e);
                            return Err(e);
                        },
                        Err(e) => {
                            let e = Box::new(e);
                            let e = REK::HeaderFieldWriteError.into_error_with_cause(e);
                            return Err(e);
                        },
                        _ => (),
                    }
                }
                &None => {
                    debug!("Not going to insert.");
                }
            }
        }

        Ok(Ref(fle))
    }

    /// Creates a Hash from a PathBuf by making the PathBuf absolute and then running a hash
    /// algorithm on it
    fn hash_path(pb: &PathBuf) -> Result<String> {
        use std::io::Read;
        use crypto::sha1::Sha1;
        use crypto::digest::Digest;

        match pb.to_str() {
            Some(s) => {
                let mut hasher = Sha1::new();
                hasher.input_str(s);
                Ok(hasher.result_str())
            },
            None => return Err(REK::PathUTF8Error.into_error()),
        }
    }

    /// check whether the pointer the Ref represents still points to a file which exists
    pub fn fs_link_exists(&self) -> Result<bool> {
        self.fs_file().map(|pathbuf| pathbuf.exists())
    }

    /// Alias for `r.fs_link_exists() && r.deref().is_file()`
    pub fn is_ref_to_file(&self) -> Result<bool> {
        self.fs_file().map(|pathbuf| pathbuf.is_file())
    }

    /// Alias for `r.fs_link_exists() && r.deref().is_dir()`
    pub fn is_ref_to_dir(&self) -> Result<bool> {
        self.fs_file().map(|pathbuf| pathbuf.is_dir())
    }

    /// Alias for `!Ref::fs_link_exists()`
    pub fn is_dangling(&self) -> Result<bool> {
        self.fs_link_exists().map(|b| !b)
    }

    /// check whether the pointer the Ref represents is valid
    /// This includes:
    ///     - Hashsum of the file is still the same as stored in the Ref
    ///     - file permissions are still valid
    pub fn fs_link_valid(&self) -> Result<bool> {
        match (self.fs_link_valid_permissions(), self.fs_link_valid_hash()) {
            (Ok(true) , Ok(true)) => Ok(true),
            (Ok(_)    , Ok(_))    => Ok(false),
            (Err(e)   , _)        => Err(e),
            (_        , Err(e))   => Err(e),
        }
    }

    /// Check whether the file permissions of the referenced file are equal to the stored
    /// permissions
    pub fn fs_link_valid_permissions(&self) -> Result<bool> {
        self.0
            .get_header()
            .read("ref.permissions.ro")
            .map_err(Box::new)
            .map_err(|e| REK::HeaderFieldReadError.into_error_with_cause(e))
            .and_then(|ro| {
                match ro {
                    Some(Value::Boolean(b)) => Ok(b),
                    Some(_)                 => Err(REK::HeaderTypeError.into_error()),
                    None                    => Err(REK::HeaderFieldMissingError.into_error()),
                }
            })
            .and_then(|ro| self.fs_file().map(|pb| (ro, pb)))
            .and_then(|(ro, pb)| {
                File::open(pb)
                    .map(|file| (ro, file))
                    .map_err(Box::new)
                    .map_err(|e| REK::HeaderFieldReadError.into_error_with_cause(e))
            })
            .and_then(|(ro, file)| {
                file
                    .metadata()
                    .map(|md| md.permissions())
                    .map(|perm| perm.readonly() == ro)
                    .map_err(Box::new)
                    .map_err(|e| REK::RefTargetCannotReadPermissions.into_error_with_cause(e))
            })
            .map_err(Box::new)
            .map_err(|e| REK::RefTargetCannotReadPermissions.into_error_with_cause(e))
    }

    /// Check whether the Hashsum of the referenced file is equal to the stored hashsum
    pub fn fs_link_valid_hash(&self) -> Result<bool> {
        let stored_hash = try!(match self.0.get_header().read("ref.content_hash") {
            // content hash stored...
            Ok(Some(Value::String(s))) => Ok(s),

            // content hash header field has wrong type
            Ok(Some(_)) => Err(REK::HeaderTypeError.into_error()),

            // content hash not stored
            Ok(None) => Err(REK::HeaderFieldMissingError.into_error()),

            // Error
            Err(e) => Err(REK::StoreReadError.into_error_with_cause(Box::new(e))),
        });

        let current_hash = try!(self.fs_file()
            .and_then(|pb| {
                File::open(pb)
                    .map_err(Box::new)
                    .map_err(|e| REK::IOError.into_error_with_cause(e))
            })
            .map(|mut file| hash_file_contents(&mut file))
        );

        Ok(stored_hash == current_hash)
    }

    /// Update the Ref by re-checking the file from FS
    /// This errors if the file is not present or cannot be read()
    pub fn update_ref(&mut self) -> Result<()> {
        unimplemented!()
    }

    /// Get the path of the file which is reffered to by this Ref
    pub fn fs_file(&self) -> Result<PathBuf> {
        match self.0.get_header().read("ref.path") {
            Ok(Some(Value::String(ref s))) => Ok(PathBuf::from(s)),
            Ok(Some(_)) => Err(REK::HeaderTypeError.into_error()),
            Ok(None)    => Err(REK::HeaderFieldMissingError.into_error()),
            Err(e)      => Err(REK::StoreReadError.into_error_with_cause(Box::new(e))),
        }
    }

    /// Check whether there is a reference to the file at `pb`
    pub fn exists(store: &Store, pb: PathBuf) -> Result<bool> {
        pb.canonicalize()
            .map_err(Box::new)
            .map_err(|e| REK::PathCanonicalizationError.into_error_with_cause(e))
            .and_then(|can| {
                Ref::hash_path(&can)
                    .map_err(Box::new)
                    .map_err(|e| REK::PathHashingError.into_error_with_cause(e))
            })
            .and_then(|hash| {
                store.retrieve_for_module("ref").map(|iter| (hash, iter))
                    .map_err(Box::new)
                    .map_err(|e| REK::StoreReadError.into_error_with_cause(e))
            })
            .and_then(|(hash, possible_refs)| {
                // This is kind of a manual Iterator::filter() call what we do here, but with the
                // actual ::filter method we cannot return the error in a nice way, so we do it
                // manually here. If you can come up with a better version of this, feel free to
                // take this note as a todo.
                for r in possible_refs {
                    let contains_hash = match r.to_str() {
                        None => { // couldn't parse StoreId -> PathBuf -> &str
                            // TODO: How to report this?
                            return Err(REK::TypeConversionError.into_error());
                        },
                        Some(s) => s.contains(&hash[..]),
                    };

                    if !contains_hash {
                        continue;
                    }

                    match store.get(r) {
                        Ok(Some(fle)) => {
                            if Ref::read_reference(&fle).map(|path| path == pb).unwrap_or(false) {
                                return Ok(true)
                            }
                        },

                        Ok(None) => { // Something weird just happened
                            return Err(REK::StoreReadError.into_error());
                        },

                        Err(e) => {
                            return Err(REK::StoreReadError.into_error_with_cause(Box::new(e)));
                        },
                    }
                }

                Ok(false)
            })
    }

    /// Re-find a referenced file
    ///
    /// This function tries to re-find a ref by searching all directories in `search_roots` recursively
    /// for a file which matches the hash of the Ref `ref`.
    ///
    /// If `search_roots` is `None`, it starts at the filesystem root `/`.
    ///
    /// # Warning
    ///
    /// This option causes heavy I/O as it recursively searches the Filesystem.
    pub fn refind(&self, search_roots: Option<Vec<PathBuf>>) -> Option<PathBuf> {
        unimplemented!()
    }

}

impl<'a> Deref for Ref<'a> {
    type Target = FileLockEntry<'a>;

    fn deref(&self) -> &FileLockEntry<'a> {
        &self.0
    }

}

impl<'a> DerefMut for Ref<'a> {

    fn deref_mut(&mut self) -> &mut FileLockEntry<'a> {
        &mut self.0
    }

}

fn hash_file_contents(f: &mut File) -> String {
    let mut hasher = Sha1::new();
    let mut s = String::new();
    f.read_to_string(&mut s);
    hasher.input_str(&s[..]);
    hasher.result_str()
}

<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::path::Path;
use std::borrow::Borrow;
use std::ops::Deref;

use semver::Version;
use std::fmt::{Display, Debug, Formatter};
use std::fmt::Error as FmtError;
use std::result::Result as RResult;

use error::StoreErrorKind as SEK;
use store::Result;
use store::Store;

/// The Index into the Store
#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
pub struct StoreId {
    base: Option<PathBuf>,
    id:   PathBuf,
}

impl StoreId {

    pub fn new(base: Option<PathBuf>, id: PathBuf) -> StoreId {
        StoreId { base: base, id: id }
    }

    pub fn storified(self, store: &Store) -> StoreId {
        StoreId {
            base: Some(store.path().clone()),
            id: self.id
        }
    }

    pub fn exists(&self) -> bool {
        let pb : PathBuf = self.clone().into();
        pb.exists()
    }

    pub fn is_file(&self) -> bool {
        true
    }

    pub fn is_dir(&self) -> bool {
        false
    }

}

impl Into<PathBuf> for StoreId {

    fn into(self) -> PathBuf {
        let mut base = self.base.unwrap_or(PathBuf::from("/"));
        base.push(self.id);
        base
    }

}

impl Display for StoreId {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        match self.id.to_str() {
            Some(s) => write!(fmt, "{}", s),
            None    => write!(fmt, "{}", self.id.to_string_lossy()),
        }
    }

}

/// This Trait allows you to convert various representations to a single one
/// suitable for usage in the Store
pub trait IntoStoreId {
    fn into_storeid(self) -> StoreId;
}

impl IntoStoreId for StoreId {
    fn into_storeid(self) -> StoreId {
        self
    }
}

pub fn build_entry_path(store: &Store, path_elem: &str) -> Result<PathBuf> {
    debug!("Checking path element for version");
    if path_elem.split('~').last().map_or(false, |v| Version::parse(v).is_err()) {
        debug!("Version cannot be parsed from {:?}", path_elem);
        debug!("Path does not contain version!");
        return Err(SEK::StorePathLacksVersion.into());
    }
    debug!("Version checking succeeded");

    debug!("Building path from {:?}", path_elem);
    let mut path = store.path().clone();

    if path_elem.starts_with('/') {
        path.push(&path_elem[1..]);
    } else {
        path.push(path_elem);
    }

    Ok(path)
}

#[macro_export]
macro_rules! module_entry_path_mod {
    ($name:expr, $version:expr) => (
        #[deny(missing_docs,
                missing_copy_implementations,
                trivial_casts, trivial_numeric_casts,
                unsafe_code,
                unstable_features,
                unused_import_braces, unused_qualifications,
                unused_imports)]
        /// A helper module to create valid module entry paths
        pub mod module_path {
            use semver::Version;
            use std::convert::AsRef;
            use std::path::Path;
            use std::path::PathBuf;

            use $crate::storeid::StoreId;

            /// A Struct giving you the ability to choose store entries assigned
            /// to it.
            ///
            /// It is created through a call to `new`.
            pub struct ModuleEntryPath(PathBuf);

            impl ModuleEntryPath {
                /// Path has to be a valid UTF-8 string or this will panic!
                pub fn new<P: AsRef<Path>>(pa: P) -> ModuleEntryPath {
                    let mut path = PathBuf::new();
                    path.push(format!("{}", $name));
                    path.push(pa.as_ref().clone());
                    let version = Version::parse($version).unwrap();
                    let name = pa.as_ref().file_name().unwrap()
                        .to_str().unwrap();
                    path.set_file_name(format!("{}~{}",
                                               name,
                                               version));
                    ModuleEntryPath(path)
                }
            }

            impl $crate::storeid::IntoStoreId for ModuleEntryPath {
                fn into_storeid(self) -> $crate::storeid::StoreId {
                    StoreId::new(None, self.0)
                }
            }
        }
    )
}

pub struct StoreIdIterator {
    iter: Box<Iterator<Item = StoreId>>,
}

impl Debug for StoreIdIterator {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        write!(fmt, "StoreIdIterator")
    }

}

impl StoreIdIterator {

    pub fn new(iter: Box<Iterator<Item = StoreId>>) -> StoreIdIterator {
        StoreIdIterator {
            iter: iter,
        }
    }

}

impl Iterator for StoreIdIterator {
    type Item = StoreId;

    fn next(&mut self) -> Option<StoreId> {
        self.iter.next()
    }

}

#[cfg(test)]
mod test {

    use storeid::IntoStoreId;

    module_entry_path_mod!("test", "0.2.0-alpha+leet1337");

    #[test]
    fn correct_path() {
        let p = module_path::ModuleEntryPath::new("test");

        assert_eq!(p.into_storeid().to_str().unwrap(), "test/test~0.2.0-alpha+leet1337");
    }

}
<commit_msg>Remove unused imports<commit_after>use std::path::PathBuf;

use semver::Version;
use std::fmt::{Display, Debug, Formatter};
use std::fmt::Error as FmtError;
use std::result::Result as RResult;

use error::StoreErrorKind as SEK;
use store::Result;
use store::Store;

/// The Index into the Store
#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
pub struct StoreId {
    base: Option<PathBuf>,
    id:   PathBuf,
}

impl StoreId {

    pub fn new(base: Option<PathBuf>, id: PathBuf) -> StoreId {
        StoreId { base: base, id: id }
    }

    pub fn storified(self, store: &Store) -> StoreId {
        StoreId {
            base: Some(store.path().clone()),
            id: self.id
        }
    }

    pub fn exists(&self) -> bool {
        let pb : PathBuf = self.clone().into();
        pb.exists()
    }

    pub fn is_file(&self) -> bool {
        true
    }

    pub fn is_dir(&self) -> bool {
        false
    }

}

impl Into<PathBuf> for StoreId {

    fn into(self) -> PathBuf {
        let mut base = self.base.unwrap_or(PathBuf::from("/"));
        base.push(self.id);
        base
    }

}

impl Display for StoreId {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        match self.id.to_str() {
            Some(s) => write!(fmt, "{}", s),
            None    => write!(fmt, "{}", self.id.to_string_lossy()),
        }
    }

}

/// This Trait allows you to convert various representations to a single one
/// suitable for usage in the Store
pub trait IntoStoreId {
    fn into_storeid(self) -> StoreId;
}

impl IntoStoreId for StoreId {
    fn into_storeid(self) -> StoreId {
        self
    }
}

pub fn build_entry_path(store: &Store, path_elem: &str) -> Result<PathBuf> {
    debug!("Checking path element for version");
    if path_elem.split('~').last().map_or(false, |v| Version::parse(v).is_err()) {
        debug!("Version cannot be parsed from {:?}", path_elem);
        debug!("Path does not contain version!");
        return Err(SEK::StorePathLacksVersion.into());
    }
    debug!("Version checking succeeded");

    debug!("Building path from {:?}", path_elem);
    let mut path = store.path().clone();

    if path_elem.starts_with('/') {
        path.push(&path_elem[1..]);
    } else {
        path.push(path_elem);
    }

    Ok(path)
}

#[macro_export]
macro_rules! module_entry_path_mod {
    ($name:expr, $version:expr) => (
        #[deny(missing_docs,
                missing_copy_implementations,
                trivial_casts, trivial_numeric_casts,
                unsafe_code,
                unstable_features,
                unused_import_braces, unused_qualifications,
                unused_imports)]
        /// A helper module to create valid module entry paths
        pub mod module_path {
            use semver::Version;
            use std::convert::AsRef;
            use std::path::Path;
            use std::path::PathBuf;

            use $crate::storeid::StoreId;

            /// A Struct giving you the ability to choose store entries assigned
            /// to it.
            ///
            /// It is created through a call to `new`.
            pub struct ModuleEntryPath(PathBuf);

            impl ModuleEntryPath {
                /// Path has to be a valid UTF-8 string or this will panic!
                pub fn new<P: AsRef<Path>>(pa: P) -> ModuleEntryPath {
                    let mut path = PathBuf::new();
                    path.push(format!("{}", $name));
                    path.push(pa.as_ref().clone());
                    let version = Version::parse($version).unwrap();
                    let name = pa.as_ref().file_name().unwrap()
                        .to_str().unwrap();
                    path.set_file_name(format!("{}~{}",
                                               name,
                                               version));
                    ModuleEntryPath(path)
                }
            }

            impl $crate::storeid::IntoStoreId for ModuleEntryPath {
                fn into_storeid(self) -> $crate::storeid::StoreId {
                    StoreId::new(None, self.0)
                }
            }
        }
    )
}

pub struct StoreIdIterator {
    iter: Box<Iterator<Item = StoreId>>,
}

impl Debug for StoreIdIterator {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        write!(fmt, "StoreIdIterator")
    }

}

impl StoreIdIterator {

    pub fn new(iter: Box<Iterator<Item = StoreId>>) -> StoreIdIterator {
        StoreIdIterator {
            iter: iter,
        }
    }

}

impl Iterator for StoreIdIterator {
    type Item = StoreId;

    fn next(&mut self) -> Option<StoreId> {
        self.iter.next()
    }

}

#[cfg(test)]
mod test {

    use storeid::IntoStoreId;

    module_entry_path_mod!("test", "0.2.0-alpha+leet1337");

    #[test]
    fn correct_path() {
        let p = module_path::ModuleEntryPath::new("test");

        assert_eq!(p.into_storeid().to_str().unwrap(), "test/test~0.2.0-alpha+leet1337");
    }

}
<|endoftext|>


<commit_before>//! Work wih Python capsules
//!
use super::object::PyObject;
use err::{self, PyErr, PyResult};
use ffi::{PyCapsule_GetPointer, PyCapsule_Import, PyCapsule_New};
use libc::c_void;
use python::{Python, ToPythonPointer};
use std::ffi::{CStr, CString, NulError};
use std::mem;

/// Represents a Python capsule object.
pub struct PyCapsule(PyObject);

pyobject_newtype!(PyCapsule, PyCapsule_CheckExact, PyCapsule_Type);

/// Capsules are the preferred way to export/import C APIs between extension modules,
/// see [Providing a C API for an Extension Module](https://docs.python.org/3/extending/extending.html#using-capsules).
///
/// In particular, capsules can be very useful to start adding Rust extensions besides
/// existing traditional C ones, be it for gradual rewrites or to extend with new functionality.
/// They can also be used for interaction between independently compiled Rust extensions if needed.
///
/// # Examples
/// ## Using a capsule defined in another extension module
/// This retrieves and use one of the simplest capsules in the Python standard library, found in
/// the `unicodedata` module. The C API enclosed in this capsule is the same for all Python
/// versions supported by this crate. This is not the case of all capsules from the standard
/// library. For instance the `struct` referenced by `datetime.datetime_CAPI` gets a new member
/// in version 3.7.
///
/// ```
/// #[macro_use] extern crate cpython;
/// extern crate libc;
///
/// use cpython::{Python, PyCapsule};
/// use libc::{c_char, c_int};
/// use std::ffi::{c_void, CStr, CString};
/// use std::mem;
/// use std::ptr::null_mut;
///
/// #[allow(non_camel_case_types)]
/// type Py_UCS4 = u32;
/// const UNICODE_NAME_MAXLEN: usize = 256;
///
/// #[repr(C)]
/// pub struct unicode_name_CAPI {
///     // the `ucd` signature arguments are actually optional (can be `NULL`) FFI PyObject
///     // pointers used to pass alternate (former) versions of Unicode data.
///     // We won't need to use them with an actual value in these examples, so it's enough to
///     // specify them as `*mut c_void`, and it spares us a direct reference to the lower
///     // level Python FFI bindings.
///     size: c_int,
///     getname: unsafe extern "C" fn(
///         ucd: *mut c_void,
///         code: Py_UCS4,
///         buffer: *mut c_char,
///         buflen: c_int,
///         with_alias_and_seq: c_int,
///     ) -> c_int,
///     getcode: unsafe extern "C" fn(
///         ucd: *mut c_void,
///         name: *const c_char,
///         namelen: c_int,
///         code: *mut Py_UCS4,
///     ) -> c_int,
/// }

/// #[derive(Debug, PartialEq)]
/// pub enum UnicodeDataError {
///     InvalidCode,
///     UnknownName,
/// }
/// impl unicode_name_CAPI {
///     pub fn get_name(&self, code: Py_UCS4) -> Result<CString, UnicodeDataError> {
///         let mut buf: Vec<c_char> = Vec::with_capacity(UNICODE_NAME_MAXLEN);
///         let buf_ptr = buf.as_mut_ptr();
///         if unsafe {
///           ((*self).getname)(null_mut(), code, buf_ptr, UNICODE_NAME_MAXLEN as c_int, 0)
///         } != 1 {
///             return Err(UnicodeDataError::InvalidCode);
///         }
///         mem::forget(buf);
///         Ok(unsafe { CString::from_raw(buf_ptr) })
///     }
///
///     pub fn get_code(&self, name: &CStr) -> Result<Py_UCS4, UnicodeDataError> {
///         let namelen = name.to_bytes().len() as c_int;
///         let mut code: [Py_UCS4; 1] = [0; 1];
///         if unsafe {
///             ((*self).getcode)(null_mut(), name.as_ptr(), namelen, code.as_mut_ptr())
///         } != 1 {
///             return Err(UnicodeDataError::UnknownName);
///         }
///         Ok(code[0])
///     }
/// }
///
/// let gil = Python::acquire_gil();
/// let py = gil.python();
///
/// let capi: &unicode_name_CAPI = unsafe {
///     PyCapsule::import_data(
///         py,
///         CStr::from_bytes_with_nul_unchecked(b"unicodedata.ucnhash_CAPI\0"),
///     )
/// }
/// .unwrap();
///
/// assert_eq!(capi.get_name(32).unwrap().to_str(), Ok("SPACE"));
/// assert_eq!(capi.get_name(0), Err(UnicodeDataError::InvalidCode));
///
/// assert_eq!(
///     capi.get_code(CStr::from_bytes_with_nul(b"COMMA\0").unwrap()),
///     Ok(44)
/// );
/// assert_eq!(
///     capi.get_code(CStr::from_bytes_with_nul(b"\0").unwrap()),
///     Err(UnicodeDataError::UnknownName)
/// );
/// ```
///
/// ## Creating a capsule from Rust
/// In this example, we enclose some data and a function in a capsule, using an intermediate
/// `struct` as enclosing type, then retrieve them back and use them.
///
/// ```
/// extern crate cpython;
/// extern crate libc;
///
/// use libc::c_int;
/// use cpython::{PyCapsule, Python};
/// use std::ffi::{c_void, CStr, CString};
///
/// #[repr(C)]
/// struct CapsData {
///     value: c_int,
///     fun: fn(c_int, c_int) -> c_int,
/// }
///
/// fn add(a: c_int, b: c_int) -> c_int {
///     a + b
/// }
///
/// const DATA: CapsData = CapsData{value: 1, fun: add};
///
/// let gil = Python::acquire_gil();
/// let py = gil.python();
/// let caps = PyCapsule::new_data(py, &mut DATA, "somemod.capsdata").unwrap();
///
/// let retrieved: &CapsData = unsafe {caps.data_ref("somemod.capsdata")}.unwrap();
/// assert_eq!(retrieved.value, 1);
/// assert_eq!((retrieved.fun)(2 as c_int, 3 as c_int), 5);
/// ```
///
/// Of course, a more realistic example would be to store the capsule in a Python module,
/// allowing another extension (possibly foreign) to retrieve and use it.
/// Note that in that case, the capsule `name` must be full dotted name of the capsule object,
/// as we're doing here.
/// ```
/// # #[macro_use] extern crate cpython;
/// # extern crate libc;
/// # use libc::c_int;
/// # use cpython::PyCapsule;
/// # #[repr(C)]
/// # struct CapsData {
/// #     value: c_int,
/// #     fun: fn(c_int, c_int) -> c_int,
/// # }
/// # fn add(a: c_int, b: c_int) -> c_int {
/// #     a + b
/// # }
/// # const DATA: CapsData = CapsData{value: 1, fun: add};
/// py_module_initializer!(somemod, initsomemod, PyInit_somemod, |py, m| {
///   m.add(py, "__doc__", "A module holding a capsule")?;
///   m.add(py, "capsdata", PyCapsule::new_data(py, &mut DATA, "somemod.capsdata").unwrap())?;
///   Ok(())
/// });
/// ```
/// Another Rust extension could then declare `CapsData` and use `PyCapsule::import_data` to
/// fetch it back.
impl PyCapsule {
    /// Retrieve the contents of a capsule pointing to some data as a reference.
    ///
    /// The retrieved data would typically be an array of static data and/or function pointers.
    /// This method doesn't work for standalone function pointers.
    ///
    /// # Safety
    /// This method is unsafe, because
    /// - nothing guarantees that the `T` type is appropriate for the data referenced by the capsule
    ///   pointer
    /// - the returned lifetime doesn't guarantee either to cover the actual lifetime of the data
    ///   (although capsule data is usually static)
    pub unsafe fn import_data<'a, T>(py: Python, name: &CStr) -> PyResult<&'a T> {
        Ok(&*(Self::import(py, name)? as *const T))
    }

    /// Retrieves the contents of a capsule as a void pointer by its name.
    ///
    /// This is suitable in particular for later conversion as a function pointer
    /// with `mem::transmute`, for architectures where data and function pointers have
    /// the same size (see details about this the documentation of the Rust standard library).
    pub fn import(py: Python, name: &CStr) -> PyResult<*mut c_void> {
        let caps_ptr = unsafe { PyCapsule_Import(name.as_ptr(), 0) };
        if caps_ptr.is_null() {
            return Err(PyErr::fetch(py));
        }
        Ok(caps_ptr)
    }

    /// Convenience method to create a capsule for some data
    ///
    /// The encapsuled data may be an array of functions, but it can't be itself a
    /// function directly.
    ///
    /// May panic when running out of memory.
    ///
    pub fn new_data<T>(
        py: Python,
        data: &mut T,
        name: impl Into<Vec<u8>>,
    ) -> Result<Self, NulError> {
        Self::new(py, data as *mut T as *mut c_void, name)
    }

    /// Creates a new capsule from a raw void pointer
    ///
    /// This is suitable in particular to store a function pointer in a capsule. These
    /// can be obtained simply by a simple cast:
    ///
    /// ```
    /// extern crate libc;
    /// use libc::c_void;
    ///
    /// extern "C" fn inc(a: i32) -> i32 {
    ///     a + 1
    /// }
    /// let ptr = inc as *mut c_void;
    /// ```
    ///
    /// # Errors
    /// This method returns `NulError` if `name` contains a 0 byte (see also `CString::new`)
    pub fn new(
        py: Python,
        pointer: *mut c_void,
        name: impl Into<Vec<u8>>,
    ) -> Result<Self, NulError> {
        let name = CString::new(name)?;
        let caps = unsafe {
            Ok(err::cast_from_owned_ptr_or_panic(
                py,
                PyCapsule_New(pointer, name.as_ptr(), None),
            ))
        };
        // it is required that the capsule name outlives the call as a char*
        // TODO implement a proper PyCapsule_Destructor to release it properly
        mem::forget(name);
        caps
    }

    /// Returns a reference to the capsule data.
    ///
    /// The name must match exactly the one given at capsule creation time (see `new_data`) and
    /// is converted to a C string under the hood. If that's too much overhead, consider using
    /// `data_ref_cstr()` or caching strategies.
    ///
    /// This is unsafe, because
    /// - nothing guarantees that the `T` type is appropriate for the data referenced by the capsule
    ///   pointer
    /// - the returned lifetime doesn't guarantee either to cover the actual lifetime of the data
    ///   (although capsule data is usually static)
    ///
    /// # Errors
    /// This method returns `NulError` if `name` contains a 0 byte (see also `CString::new`)
    pub unsafe fn data_ref<'a, T>(&self, name: impl Into<Vec<u8>>) -> Result<&'a T, NulError> {
        Ok(self.data_ref_cstr(&CString::new(name)?))
    }

    /// Returns a reference to the capsule data.
    ///
    /// This is identical to `data_ref`, except for the name passing. This allows to use
    /// lower level constructs without overhead, such as `CStr::from_bytes_with_nul_unchecked`
    /// or the `cstr!` macro of `rust-cpython`
    pub unsafe fn data_ref_cstr<'a, T>(&self, name: &CStr) -> &'a T {
        &*(PyCapsule_GetPointer(self.as_ptr(), name.as_ptr()) as *const T)
    }
}
<commit_msg>py_capsule_fn! macro for direct function capsules<commit_after>//! Work wih Python capsules
//!
use super::object::PyObject;
use err::{self, PyErr, PyResult};
use ffi::{PyCapsule_GetPointer, PyCapsule_Import, PyCapsule_New};
use libc::c_void;
use python::{Python, ToPythonPointer};
use std::ffi::{CStr, CString, NulError};
use std::mem;

/// Represents a Python capsule object.
pub struct PyCapsule(PyObject);

pyobject_newtype!(PyCapsule, PyCapsule_CheckExact, PyCapsule_Type);

/// Macro to retrieve a function pointer capsule
///
/// For general explanations about Capsules, see [`PyCapsule`].
///
/// This macro takes the following arguments:
/// - segments of the full Python dotted name of the capsule
/// - `$rustmod`, a suitable name to define a module
/// - signature of the wished function (the macro will insert the `extern unsafe fn`)
///
/// The macro defines a Rust module with a retrieval function such as:
///
/// ```ignore
/// mod $rustmod {
///     pub type CapsFn = unsafe extern "C" ( ... ) -> ... ;
///     pub unsafe fn retrieve<'a>(py: Python) -> PyResult<CapsFn) { ... }
/// }
/// ```
///
/// # Examples
/// There is in the Python library no capsule enclosing a function pointer directly,
/// although the documentation presents it as a valid use-case. For this example, we'll
/// therefore have to create one, using the [`PyCapsule`] constructor, and to set it in an
/// existing  module (not to imply that a real extension should follow that example
/// and set capsules in modules they don't define!)
///
///
/// ```
/// #[macro_use] extern crate cpython;
/// extern crate libc;
/// use cpython::{PyCapsule, Python, FromPyObject};
/// use libc::{c_int, c_void};
///
/// extern "C" fn inc(a: c_int) -> c_int {
///     a + 1
/// }
///
/// /// for testing purposes, stores a capsule named `sys.capsfn`` pointing to `inc()`.
/// fn create_capsule() {
///     let gil = Python::acquire_gil();
///     let py = gil.python();
///     let pymod = py.import("sys").unwrap();
///     let caps = PyCapsule::new(py, inc as *mut c_void, "sys.capsfn").unwrap();
///     pymod.add(py, "capsfn", caps).unwrap();
///  }
///
/// py_capsule_fn!(sys, capsfn, capsmod, (a: c_int) -> c_int);
///
/// // One could, e.g., reexport if needed:
/// pub use capsmod::CapsFn;
///
/// fn retrieve_use_capsule() {
///     let gil = Python::acquire_gil();
///     let py = gil.python();
///     let fun = capsmod::retrieve(py).unwrap();
///     assert_eq!( unsafe { fun(1) }, 2);
///
///     // let's demonstrate the (reexported) function type
///     let g: CapsFn = fun;
/// }
///
/// fn main() {
///     create_capsule();
///     retrieve_use_capsule();
///     retrieve_use_capsule();
/// }
/// ```
/// [`PyCapsule`]: struct.PyCapsule.html
#[macro_export]
macro_rules! py_capsule_fn {
    ($($capsmod:ident).+, $capsname:ident, $rustmod:ident, $( $sig: tt)* ) => (
        mod $rustmod {
            use super::*;
            use std::sync::Once;
            use $crate::PyClone;

            pub type CapsFn = unsafe extern "C" fn $( $sig )*;

            static mut CAPS_FN: Option<$crate::PyResult<CapsFn>> = None;

            static INIT: Once = Once::new();

            fn import(py: $crate::Python) -> $crate::PyResult<CapsFn> {
                unsafe {
                    let caps_name =
                        std::ffi::CStr::from_bytes_with_nul_unchecked(
                            concat!($( stringify!($capsmod), "."),*,
                                    stringify!($capsname),
                                    "\0").as_bytes());
                    Ok(::std::mem::transmute($crate::PyCapsule::import(py, caps_name)?))
                }
            }

            pub fn retrieve(py: $crate::Python) -> $crate::PyResult<CapsFn> {
                unsafe {
                    INIT.call_once(|| { CAPS_FN = Some(import(py)) });
                    match CAPS_FN.as_ref().unwrap() {
                        Ok(f) => Ok(*f),
                        Err(ref e) => Err(e.clone_ref(py)),
                    }
                }
            }
        }
    )
}

/// Capsules are the preferred way to export/import C APIs between extension modules,
/// see [Providing a C API for an Extension Module](https://docs.python.org/3/extending/extending.html#using-capsules).
///
/// In particular, capsules can be very useful to start adding Rust extensions besides
/// existing traditional C ones, be it for gradual rewrites or to extend with new functionality.
/// They can also be used for interaction between independently compiled Rust extensions if needed.
///
/// Capsules can point to data, usually static arrays of constants and function pointers,
/// or to function pointers directly. These two cases have to be handled differently in Rust,
/// and the latter is possible only for architectures were data and function pointers have
/// the same sizes.
///
/// # Examples
/// ## Using a capsule defined in another extension module
/// This retrieves and use one of the simplest capsules in the Python standard library, found in
/// the `unicodedata` module. The C API enclosed in this capsule is the same for all Python
/// versions supported by this crate. This is not the case of all capsules from the standard
/// library. For instance the `struct` referenced by `datetime.datetime_CAPI` gets a new member
/// in version 3.7.
///
/// ```
/// #[macro_use] extern crate cpython;
/// extern crate libc;
///
/// use cpython::{Python, PyCapsule};
/// use libc::{c_char, c_int};
/// use std::ffi::{c_void, CStr, CString};
/// use std::mem;
/// use std::ptr::null_mut;
///
/// #[allow(non_camel_case_types)]
/// type Py_UCS4 = u32;
/// const UNICODE_NAME_MAXLEN: usize = 256;
///
/// #[repr(C)]
/// pub struct unicode_name_CAPI {
///     // the `ucd` signature arguments are actually optional (can be `NULL`) FFI PyObject
///     // pointers used to pass alternate (former) versions of Unicode data.
///     // We won't need to use them with an actual value in these examples, so it's enough to
///     // specify them as `*mut c_void`, and it spares us a direct reference to the lower
///     // level Python FFI bindings.
///     size: c_int,
///     getname: unsafe extern "C" fn(
///         ucd: *mut c_void,
///         code: Py_UCS4,
///         buffer: *mut c_char,
///         buflen: c_int,
///         with_alias_and_seq: c_int,
///     ) -> c_int,
///     getcode: unsafe extern "C" fn(
///         ucd: *mut c_void,
///         name: *const c_char,
///         namelen: c_int,
///         code: *mut Py_UCS4,
///     ) -> c_int,
/// }

/// #[derive(Debug, PartialEq)]
/// pub enum UnicodeDataError {
///     InvalidCode,
///     UnknownName,
/// }
/// impl unicode_name_CAPI {
///     pub fn get_name(&self, code: Py_UCS4) -> Result<CString, UnicodeDataError> {
///         let mut buf: Vec<c_char> = Vec::with_capacity(UNICODE_NAME_MAXLEN);
///         let buf_ptr = buf.as_mut_ptr();
///         if unsafe {
///           ((*self).getname)(null_mut(), code, buf_ptr, UNICODE_NAME_MAXLEN as c_int, 0)
///         } != 1 {
///             return Err(UnicodeDataError::InvalidCode);
///         }
///         mem::forget(buf);
///         Ok(unsafe { CString::from_raw(buf_ptr) })
///     }
///
///     pub fn get_code(&self, name: &CStr) -> Result<Py_UCS4, UnicodeDataError> {
///         let namelen = name.to_bytes().len() as c_int;
///         let mut code: [Py_UCS4; 1] = [0; 1];
///         if unsafe {
///             ((*self).getcode)(null_mut(), name.as_ptr(), namelen, code.as_mut_ptr())
///         } != 1 {
///             return Err(UnicodeDataError::UnknownName);
///         }
///         Ok(code[0])
///     }
/// }
///
/// let gil = Python::acquire_gil();
/// let py = gil.python();
///
/// let capi: &unicode_name_CAPI = unsafe {
///     PyCapsule::import_data(
///         py,
///         CStr::from_bytes_with_nul_unchecked(b"unicodedata.ucnhash_CAPI\0"),
///     )
/// }
/// .unwrap();
///
/// assert_eq!(capi.get_name(32).unwrap().to_str(), Ok("SPACE"));
/// assert_eq!(capi.get_name(0), Err(UnicodeDataError::InvalidCode));
///
/// assert_eq!(
///     capi.get_code(CStr::from_bytes_with_nul(b"COMMA\0").unwrap()),
///     Ok(44)
/// );
/// assert_eq!(
///     capi.get_code(CStr::from_bytes_with_nul(b"\0").unwrap()),
///     Err(UnicodeDataError::UnknownName)
/// );
/// ```
///
/// ## Creating a capsule from Rust
/// In this example, we enclose some data and a function in a capsule, using an intermediate
/// `struct` as enclosing type, then retrieve them back and use them.
///
/// ```
/// extern crate cpython;
/// extern crate libc;
///
/// use libc::c_int;
/// use cpython::{PyCapsule, Python};
/// use std::ffi::{c_void, CStr, CString};
///
/// #[repr(C)]
/// struct CapsData {
///     value: c_int,
///     fun: fn(c_int, c_int) -> c_int,
/// }
///
/// fn add(a: c_int, b: c_int) -> c_int {
///     a + b
/// }
///
/// const DATA: CapsData = CapsData{value: 1, fun: add};
///
/// let gil = Python::acquire_gil();
/// let py = gil.python();
/// let caps = PyCapsule::new_data(py, &mut DATA, "somemod.capsdata").unwrap();
///
/// let retrieved: &CapsData = unsafe {caps.data_ref("somemod.capsdata")}.unwrap();
/// assert_eq!(retrieved.value, 1);
/// assert_eq!((retrieved.fun)(2 as c_int, 3 as c_int), 5);
/// ```
///
/// Of course, a more realistic example would be to store the capsule in a Python module,
/// allowing another extension (possibly foreign) to retrieve and use it.
/// Note that in that case, the capsule `name` must be full dotted name of the capsule object,
/// as we're doing here.
/// ```
/// # #[macro_use] extern crate cpython;
/// # extern crate libc;
/// # use libc::c_int;
/// # use cpython::PyCapsule;
/// # #[repr(C)]
/// # struct CapsData {
/// #     value: c_int,
/// #     fun: fn(c_int, c_int) -> c_int,
/// # }
/// # fn add(a: c_int, b: c_int) -> c_int {
/// #     a + b
/// # }
/// # const DATA: CapsData = CapsData{value: 1, fun: add};
/// py_module_initializer!(somemod, initsomemod, PyInit_somemod, |py, m| {
///   m.add(py, "__doc__", "A module holding a capsule")?;
///   m.add(py, "capsdata", PyCapsule::new_data(py, &mut DATA, "somemod.capsdata").unwrap())?;
///   Ok(())
/// });
/// ```
/// Another Rust extension could then declare `CapsData` and use `PyCapsule::import_data` to
/// fetch it back.
///
impl PyCapsule {
    /// Retrieve the contents of a capsule pointing to some data as a reference.
    ///
    /// The retrieved data would typically be an array of static data and/or function pointers.
    /// This method doesn't work for standalone function pointers.
    ///
    /// # Safety
    /// This method is unsafe, because
    /// - nothing guarantees that the `T` type is appropriate for the data referenced by the capsule
    ///   pointer
    /// - the returned lifetime doesn't guarantee either to cover the actual lifetime of the data
    ///   (although capsule data is usually static)
    pub unsafe fn import_data<'a, T>(py: Python, name: &CStr) -> PyResult<&'a T> {
        Ok(&*(Self::import(py, name)? as *const T))
    }

    /// Retrieves the contents of a capsule as a void pointer by its name.
    ///
    /// This is suitable in particular for later conversion as a function pointer
    /// with `mem::transmute`, for architectures where data and function pointers have
    /// the same size (see details about this the documentation of the Rust standard library).
    pub fn import(py: Python, name: &CStr) -> PyResult<*mut c_void> {
        let caps_ptr = unsafe { PyCapsule_Import(name.as_ptr(), 0) };
        if caps_ptr.is_null() {
            return Err(PyErr::fetch(py));
        }
        Ok(caps_ptr)
    }

    /// Convenience method to create a capsule for some data
    ///
    /// The encapsuled data may be an array of functions, but it can't be itself a
    /// function directly.
    ///
    /// May panic when running out of memory.
    ///
    pub fn new_data<T>(
        py: Python,
        data: &mut T,
        name: impl Into<Vec<u8>>,
    ) -> Result<Self, NulError> {
        Self::new(py, data as *mut T as *mut c_void, name)
    }

    /// Creates a new capsule from a raw void pointer
    ///
    /// This is suitable in particular to store a function pointer in a capsule. These
    /// can be obtained simply by a simple cast:
    ///
    /// ```
    /// extern crate libc;
    /// use libc::c_void;
    ///
    /// extern "C" fn inc(a: i32) -> i32 {
    ///     a + 1
    /// }
    /// let ptr = inc as *mut c_void;
    /// ```
    ///
    /// # Errors
    /// This method returns `NulError` if `name` contains a 0 byte (see also `CString::new`)
    pub fn new(
        py: Python,
        pointer: *mut c_void,
        name: impl Into<Vec<u8>>,
    ) -> Result<Self, NulError> {
        let name = CString::new(name)?;
        let caps = unsafe {
            Ok(err::cast_from_owned_ptr_or_panic(
                py,
                PyCapsule_New(pointer, name.as_ptr(), None),
            ))
        };
        // it is required that the capsule name outlives the call as a char*
        // TODO implement a proper PyCapsule_Destructor to release it properly
        mem::forget(name);
        caps
    }

    /// Returns a reference to the capsule data.
    ///
    /// The name must match exactly the one given at capsule creation time (see `new_data`) and
    /// is converted to a C string under the hood. If that's too much overhead, consider using
    /// `data_ref_cstr()` or caching strategies.
    ///
    /// This is unsafe, because
    /// - nothing guarantees that the `T` type is appropriate for the data referenced by the capsule
    ///   pointer
    /// - the returned lifetime doesn't guarantee either to cover the actual lifetime of the data
    ///   (although capsule data is usually static)
    ///
    /// # Errors
    /// This method returns `NulError` if `name` contains a 0 byte (see also `CString::new`)
    pub unsafe fn data_ref<'a, T>(&self, name: impl Into<Vec<u8>>) -> Result<&'a T, NulError> {
        Ok(self.data_ref_cstr(&CString::new(name)?))
    }

    /// Returns a reference to the capsule data.
    ///
    /// This is identical to `data_ref`, except for the name passing. This allows to use
    /// lower level constructs without overhead, such as `CStr::from_bytes_with_nul_unchecked`
    /// or the `cstr!` macro of `rust-cpython`
    pub unsafe fn data_ref_cstr<'a, T>(&self, name: &CStr) -> &'a T {
        &*(PyCapsule_GetPointer(self.as_ptr(), name.as_ptr()) as *const T)
    }
}
<|endoftext|>