<commit_before>// Copyright 2014 Dmitry "Divius" Tantsur <divius.inside@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//

//! KRPC DHT service as described in
//! [BEP 0005](http://www.bittorrent.org/beps/bep_0005.html).
//!
//! Create as:
//! ```
//! let service = dht::bt::KRpcService::new(this_node);
//! ```

use std::io::IoResult;
use std::sync;

use super::super::base;
use super::super::knodetable;

use super::udpwrapper;

/// Implementation of basic KRPC DHT on which BitTorrent DHT is based.
///
/// No peer retrival is supported: just finding and pinging nodes.
pub struct KRpcService<TNodeTable: base::GenericNodeTable,
                       TSocket: udpwrapper::GenericSocketWrapper> {
    this_node: base::Node,
    node_table: sync::Arc<sync::RWLock<TNodeTable>>,
    socket: TSocket,
}

/// Default kind of KRpc service.
pub type DefaultKRpcService = KRpcService<knodetable::KNodeTable, udpwrapper::UdpSocketWrapper>;

fn handle_incoming<TSocket: udpwrapper::GenericSocketWrapper>(socket: TSocket) {
    // TODO(divius): implement
    drop(socket);
}

impl KRpcService<knodetable::KNodeTable, udpwrapper::UdpSocketWrapper> {
    /// New service with default node table.
    pub fn new_default(this_node: base::Node) -> IoResult<DefaultKRpcService> {
        let node_table = knodetable::KNodeTable::new(this_node.id.clone());
        let socket = try!(udpwrapper::UdpSocketWrapper::new(&this_node));
        KRpcService::new(this_node, node_table, socket)
    }
}

impl<TNodeTable: base::GenericNodeTable, TSocket: udpwrapper::GenericSocketWrapper>
KRpcService<TNodeTable, TSocket> {
    /// New service with given node table and socket.
    pub fn new(this_node: base::Node, node_table: TNodeTable, socket: TSocket)
            -> IoResult<KRpcService<TNodeTable, TSocket>> {
        let listening_socket = socket.clone();
        spawn(proc() handle_incoming(listening_socket));

        Ok(KRpcService {
            this_node: this_node,
            node_table: sync::Arc::new(sync::RWLock::new(node_table)),
            socket: socket,
        })
    }

    /// Get lock guarding access to a node table.
    pub fn node_table_lock(&self) -> &sync::RWLock<TNodeTable> {
        self.node_table.deref()
    }
}

#[cfg(test)]
mod test {
    use std::io::IoResult;
    use std::io::net::ip;

    use num;

    use super::super::super::base::{mod, GenericNodeTable};
    use super::super::super::utils::test;

    use super::super::protocol;
    use super::super::udpwrapper::GenericSocketWrapper;

    use super::KRpcService;

    struct DummyNodeTable {
        last_node: Option<base::Node>,
    }

    impl GenericNodeTable for DummyNodeTable {
        fn random_id(&self) -> num::BigUint {
            // This number is random, I promise :)
            test::uint_to_id(42)
        }

        fn update(&mut self, node: &base::Node) -> bool {
            self.last_node = Some(node.clone());
            true
        }
        #[allow(unused_variable)]
        fn find(&self, id: &num::BigUint, count: uint) -> Vec<base::Node> {
            match self.last_node {
                Some(ref n) if n.id == *id => vec![n.clone()],
                _ => vec![]
            }
        }
        fn pop_oldest(&mut self) -> Vec<base::Node> {
            vec![]
        }
    }

    #[deriving(Clone)]
    struct DummySocketWrapper {
        last_package: Option<protocol::Package>,
        last_node: Option<base::Node>
    }

    impl GenericSocketWrapper for DummySocketWrapper {
        fn send(&mut self, package: &protocol::Package, node: &base::Node)
            -> IoResult<()> {
            self.last_package = Some(package.clone());
            self.last_node = Some(node.clone());
            Ok(())
        }

        fn receive(&mut self) -> IoResult<(protocol::Package, ip::SocketAddr)> {
            Ok((self.last_package.as_ref().unwrap().clone(),
                self.last_node.as_ref().unwrap().address.clone()))
        }
    }

    #[test]
    fn test_new() {
        let n = test::new_node_with_port(42, 8007);
        let sock = DummySocketWrapper { last_package: None, last_node: None };
        let s = KRpcService::new(n.clone(),
                                 DummyNodeTable { last_node: None },
                                 sock).unwrap();
        assert_eq!(n.id, s.this_node.id);
        let mut nt = s.node_table_lock().write();
        nt.update(&test::new_node(1));
        let nt2 = nt.downgrade();
        assert_eq!(nt2.random_id().to_u8().unwrap(), 42);
    }

    #[test]
    fn test_new_default() {
        let n = test::new_node_with_port(42, 8009);
        let s = KRpcService::new_default(n.clone()).unwrap();
        assert_eq!(n.id, s.this_node.id);
        let nt = s.node_table_lock().read();
        assert_eq!(0, nt.find(&test::uint_to_id(1), 1).len());
    }
}
<commit_msg>Add socket_ref() to bt::KRpcService<commit_after>// Copyright 2014 Dmitry "Divius" Tantsur <divius.inside@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//

//! KRPC DHT service as described in
//! [BEP 0005](http://www.bittorrent.org/beps/bep_0005.html).
//!
//! Create as:
//! ```
//! let service = dht::bt::KRpcService::new(this_node);
//! ```

use std::io::IoResult;
use std::sync;

use super::super::base;
use super::super::knodetable;

use super::udpwrapper;

/// Implementation of basic KRPC DHT on which BitTorrent DHT is based.
///
/// No peer retrival is supported: just finding and pinging nodes.
pub struct KRpcService<TNodeTable: base::GenericNodeTable,
                       TSocket: udpwrapper::GenericSocketWrapper> {
    this_node: base::Node,
    node_table: sync::Arc<sync::RWLock<TNodeTable>>,
    socket: TSocket,
}

/// Default kind of KRpc service.
pub type DefaultKRpcService = KRpcService<knodetable::KNodeTable, udpwrapper::UdpSocketWrapper>;

fn handle_incoming<TSocket: udpwrapper::GenericSocketWrapper>(socket: TSocket) {
    // TODO(divius): implement
    drop(socket);
}

impl KRpcService<knodetable::KNodeTable, udpwrapper::UdpSocketWrapper> {
    /// New service with default node table.
    pub fn new_default(this_node: base::Node) -> IoResult<DefaultKRpcService> {
        let node_table = knodetable::KNodeTable::new(this_node.id.clone());
        let socket = try!(udpwrapper::UdpSocketWrapper::new(&this_node));
        KRpcService::new(this_node, node_table, socket)
    }
}

impl<TNodeTable: base::GenericNodeTable, TSocket: udpwrapper::GenericSocketWrapper>
KRpcService<TNodeTable, TSocket> {
    /// New service with given node table and socket.
    pub fn new(this_node: base::Node, node_table: TNodeTable, socket: TSocket)
            -> IoResult<KRpcService<TNodeTable, TSocket>> {
        let listening_socket = socket.clone();
        spawn(proc() handle_incoming(listening_socket));

        Ok(KRpcService {
            this_node: this_node,
            node_table: sync::Arc::new(sync::RWLock::new(node_table)),
            socket: socket,
        })
    }

    /// Get lock guarding access to a node table.
    pub fn node_table_lock(&self) -> &sync::RWLock<TNodeTable> {
        self.node_table.deref()
    }

    /// Get reference to a socket wrapper.
    ///
    /// Clone it if you want to get mutable copy.
    pub fn socket_ref(&self) -> &TSocket {
        &self.socket
    }
}

#[cfg(test)]
mod test {
    use std::io::IoResult;
    use std::io::net::ip;

    use num;

    use super::super::super::base::{mod, GenericNodeTable};
    use super::super::super::utils::test;

    use super::super::protocol;
    use super::super::udpwrapper::GenericSocketWrapper;

    use super::KRpcService;

    struct DummyNodeTable {
        last_node: Option<base::Node>,
    }

    impl GenericNodeTable for DummyNodeTable {
        fn random_id(&self) -> num::BigUint {
            // This number is random, I promise :)
            test::uint_to_id(42)
        }

        fn update(&mut self, node: &base::Node) -> bool {
            self.last_node = Some(node.clone());
            true
        }
        #[allow(unused_variable)]
        fn find(&self, id: &num::BigUint, count: uint) -> Vec<base::Node> {
            match self.last_node {
                Some(ref n) if n.id == *id => vec![n.clone()],
                _ => vec![]
            }
        }
        fn pop_oldest(&mut self) -> Vec<base::Node> {
            vec![]
        }
    }

    #[deriving(Clone)]
    struct DummySocketWrapper {
        last_package: Option<protocol::Package>,
        last_node: Option<base::Node>
    }

    impl GenericSocketWrapper for DummySocketWrapper {
        fn send(&mut self, package: &protocol::Package, node: &base::Node)
            -> IoResult<()> {
            self.last_package = Some(package.clone());
            self.last_node = Some(node.clone());
            Ok(())
        }

        fn receive(&mut self) -> IoResult<(protocol::Package, ip::SocketAddr)> {
            Ok((self.last_package.as_ref().unwrap().clone(),
                self.last_node.as_ref().unwrap().address.clone()))
        }
    }

    #[test]
    fn test_new() {
        let n = test::new_node_with_port(42, 8007);
        let sock = DummySocketWrapper { last_package: None, last_node: None };
        let s = KRpcService::new(n.clone(),
                                 DummyNodeTable { last_node: None },
                                 sock).unwrap();
        assert_eq!(n.id, s.this_node.id);
        let mut nt = s.node_table_lock().write();
        nt.update(&test::new_node(1));
        let nt2 = nt.downgrade();
        assert_eq!(nt2.random_id().to_u8().unwrap(), 42);
    }

    #[test]
    fn test_new_default() {
        let n = test::new_node_with_port(42, 8009);
        let s = KRpcService::new_default(n.clone()).unwrap();
        assert_eq!(n.id, s.this_node.id);
        let nt = s.node_table_lock().read();
        assert_eq!(0, nt.find(&test::uint_to_id(1), 1).len());
    }
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;
use std::collections::BinaryHeap;
use std::ops::IndexMut;

use ::{SMF,Event,SMFFormat,MetaEvent,MidiMessage,Track,TrackEvent};

/// An AbsoluteEvent is an event that has an absolute time
/// This is useful for apps that want to store events internally
/// with absolute times and then quickly build an SMF file for saving etc...
pub struct AbsoluteEvent {
    time: u64,
    event: Event,
}

impl AbsoluteEvent {
    pub fn new_midi(time: u64, midi: MidiMessage) -> AbsoluteEvent {
        AbsoluteEvent {
            time: time,
            event: Event::Midi(midi),
        }
    }
    pub fn new_meta(time: u64, meta: MetaEvent) -> AbsoluteEvent {
        AbsoluteEvent {
            time: time,
            event: Event::Meta(meta),
        }
    }

    /// Return true if the event inside this AbsoluteEvent is a midi
    /// event, false if it's a meta event
    pub fn is_midi(&self) -> bool {
        match self.event {
            Event::Midi(_) => true,
            Event::Meta(_) => false,
        }
    }

    /// Return true if the event inside this AbsoluteEvent is a meta
    /// event, false if it's a midi event
    pub fn is_meta(&self) -> bool {
        match self.event {
            Event::Midi(_) => false,
            Event::Meta(_) => true,
        }
    }

    pub fn get_event(&self) -> &Event {
        &self.event
    }

    pub fn get_time(&self) -> u64 {
        self.time
    }
}

impl Eq for AbsoluteEvent {}

impl PartialEq for AbsoluteEvent {
    fn eq(&self, other: &AbsoluteEvent) -> bool {
        if self.time == other.time {
            match (&self.event,&other.event) {
                (&Event::Midi(_),&Event::Meta(_)) => false,
                (&Event::Meta(_),&Event::Midi(_)) => false,
                (&Event::Meta(ref me),&Event::Meta(ref you)) => {
                    me.command == you.command
                },
                (&Event::Midi(ref me),&Event::Midi(ref you)) => {
                    me.data(0) == you.data(0)
                        &&
                    me.data(1) == me.data(1)
                },
            }
        } else {
            false
        }
    }

    fn ne(&self, other: &AbsoluteEvent) -> bool {
        !(self.eq(other))
    }
}

// Implement `Ord` and sort messages by time
impl Ord for AbsoluteEvent {
    fn cmp(&self, other: &AbsoluteEvent) -> Ordering {
        let res = self.time.cmp(&other.time);
        match res {
            // vtime takes priority
            Ordering::Less | Ordering::Greater => res,
            // if vtime is the same, check types and make meta events
            // sort before standard events
            Ordering::Equal => {
                match (&self.event,&other.event) {
                    // I'm midi, other is meta, so I'm greater
                    (&Event::Midi(_),&Event::Meta(_)) => Ordering::Greater,
                    // I'm meta, other is midi, so I'm less
                    (&Event::Meta(_),&Event::Midi(_)) => Ordering::Less,
                    (&Event::Meta(ref me),&Event::Meta(ref you)) => {
                        me.command.cmp(&you.command)
                    },
                    (&Event::Midi(ref me),&Event::Midi(ref you)) => {
                        if      me.data(0) < you.data(0) { Ordering::Less }
                        else if me.data(0) > you.data(0) { Ordering::Greater }
                        else {
                            if me.data(1) < you.data(1) {
                                Ordering::Less
                            } else if me.data(1) > you.data(1) {
                                Ordering::Greater
                            } else {
                                res
                            }
                        }
                    },
                }
            }
        }
    }
}

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

enum EventContainer {
    Heap(BinaryHeap<AbsoluteEvent>),
    Static(Vec<TrackEvent>),
}

struct TrackBuilder {
    copyright: Option<String>,
    name: Option<String>,
    events: EventContainer,
}

impl TrackBuilder {

    fn result(self) -> Track {
        Track {
            copyright: self.copyright,
            name: self.name,
            events: match self.events {
                EventContainer::Heap(mut heap) => {
                    let mut events = Vec::new();
                    events.reserve(heap.len());
                    let mut cur_time: u64 = 0;
                    loop {
                        match heap.pop() {
                            Some(bev) => {
                                let vtime = bev.time - cur_time;
                                cur_time = vtime;
                                events.push(TrackEvent {
                                    vtime: vtime,
                                    event: bev.event,
                                });
                            }
                            None => { break; }
                        }
                    }
                    events
                },
                EventContainer::Static(vec) => vec,
            },
        }
    }

    fn abs_time_from_delta(&self,delta: u64) -> u64 {
        match self.events {
            EventContainer::Heap(ref heap) => {
                match heap.peek() {
                    Some(e) => { e.time + delta }
                    None => { delta }
                }
            }
            _ => { panic!("Can't call abs_time_from_delta on non-heap builder") }
        }
    }
}

/// An SMFBuilder can be used to create an SMF file.  This is done by
/// adding tracks to the builder via `add_track` and then adding
/// events to each track.
pub struct SMFBuilder {
    tracks:Vec<TrackBuilder>
}

impl SMFBuilder {
    /// Create a new SMFBuilder.  Initially the builder will have no tracks
    pub fn new() -> SMFBuilder {
        SMFBuilder {
            tracks: Vec::new(),
        }
    }

    /// Get the number of tracks currenly in the builder
    pub fn num_tracks(&self) -> usize {
        self.tracks.len()
    }

    /// Add new a track to this builder
    pub fn add_track(&mut self) {
        self.tracks.push(TrackBuilder {
            copyright: None,
            name: None,
            events: EventContainer::Heap(BinaryHeap::new()),
        });
    }

    /// Add a static track to the builder (note this will clone all events in the passed iterator)
    pub fn add_static_track<'a,I>(&mut self, track: I) where I: Iterator<Item=&'a AbsoluteEvent> {
        let mut cur_time: u64 = 0;
        let vec = track.map(|bev| {
            assert!(bev.time >= cur_time);
            let vtime = bev.time - cur_time;
            cur_time = vtime;
            TrackEvent {
                vtime: vtime,
                event: bev.event.clone(),
            }
        }).collect();
        self.tracks.push(TrackBuilder {
            copyright: None,
            name: None,
            events: EventContainer::Static(vec),
        });
    }

    /// Set the copyright for the track at index `track`.  This will
    /// also cause a copyright meta event to be inserted.
    /// ## Panics
    ///
    /// Panics if `track` is >= to the number of tracks in this
    /// builder, or if the track already has a copyright set.
    pub fn set_copyright(&mut self, track: usize, copyright: String) {
        assert!(self.tracks.len() >= track);
        assert!(self.tracks[track].copyright.is_none());
        // let event = AbsoluteEvent {
        //     time: 0,
        //     event: Event::Meta(MetaEvent::copyright_notice(copyright.clone())),
        // };
        self.tracks[track].copyright = Some(copyright);
    }

    /// Set the name for the track at index `track`.  This will
    /// also cause a name meta event to be inserted.
    ///
    /// ## Panics
    ///
    /// Panics if `track` is >= to the number of tracks in this
    /// builder, or if the track already has a name set.
    pub fn set_name(&mut self, track: usize, name: String) {
        assert!(self.tracks.len() >= track);
        assert!(self.tracks[track].name.is_none());
        // let event = AbsoluteEvent{
        //     time: 0,
        //     event: Event::Meta(MetaEvent::sequence_or_track_name(name.clone())),
        // };
        self.tracks[track].name = Some(name);
    }

    /// Add a midi message to track at index `track` at absolute time
    /// `time`.
    ///
    /// ## Panics
    ///
    /// Panics if `track` is >= to the number of tracks in this builder
    pub fn add_midi_abs(&mut self, track: usize, time: u64, msg: MidiMessage) {
        assert!(self.tracks.len() >= track);
        match self.tracks.index_mut(track).events {
            EventContainer::Heap(ref mut heap) => {
                heap.push(AbsoluteEvent {
                    time: time,
                    event: Event::Midi(msg),
                });
            }
            _ => { panic!("Can't add events to static tracks") }
        }
    }

    /// Add a midi message to track at index `track` at `delta` ticks
    /// after the last message (or at `delta` if no current messages
    /// exist)
    ///
    /// ## Panics
    ///
    /// Panics if `track` is >= to the number of tracks in this builder
    pub fn add_midi_rel(&mut self, track: usize, delta: u64, msg: MidiMessage) {
        assert!(self.tracks.len() >= track);
        let time = self.tracks[track].abs_time_from_delta(delta);
        self.add_midi_abs(track,time,msg);
    }

    /// Add a meta event to track at index `track` at absolute  time
    /// `time`.
    ///
    /// ## Panics
    ///
    /// Panics if `track` is >= to the number of tracks in this builder
    pub fn add_meta_abs(&mut self, track: usize, time: u64, event: MetaEvent) {
        assert!(self.tracks.len() >= track);
        match self.tracks.index_mut(track).events {
            EventContainer::Heap(ref mut heap) => {
                heap.push(AbsoluteEvent {
                    time: time,
                    event: Event::Meta(event),
                });
            }
            _ => { panic!("Can't add events to static tracks") }
        }
    }

    /// Add a meta event to track at index `track` at `delta` ticks
    /// after the last message (or at `delta` if no current messages
    /// exist)
    ///
    /// ## Panics
    ///
    /// Panics if `track` is >= to the number of tracks in this builder
    pub fn add_meta_rel(&mut self, track: usize, delta: u64, event: MetaEvent) {
        assert!(self.tracks.len() >= track);
        let time = self.tracks[track].abs_time_from_delta(delta);
        self.add_meta_abs(track,time,event);
    }

    /// Add a TrackEvent to the track at index `track`.  The event
    /// will be added at `event.vtime` after the last event currently
    /// in the builder for the track.
    ///
    /// ## Panics
    ///
    /// Panics if `track` is >= to the number of tracks in this builder
    pub fn add_event(&mut self, track: usize, event: TrackEvent) {
        assert!(self.tracks.len() >= track);
        let bevent = AbsoluteEvent {
            time: self.tracks[track].abs_time_from_delta(event.vtime),
            event: event.event,
        };
        match self.tracks.index_mut(track).events {
            EventContainer::Heap(ref mut heap) => {
                heap.push(bevent);
            }
            _ => { panic!("Can't add events to static tracks") }
        }
    }

    /// Generate an SMF file with the events that have been added to
    /// the builder
    pub fn result(self) -> SMF {
        SMF {
            format: SMFFormat::MultiTrack,
            tracks: self.tracks.into_iter().map(|tb| tb.result()).collect(),
            division: 0,
        }
    }
}
<commit_msg>bug fix again<commit_after>use std::cmp::Ordering;
use std::collections::BinaryHeap;
use std::ops::IndexMut;

use ::{SMF,Event,SMFFormat,MetaEvent,MidiMessage,Track,TrackEvent};

/// An AbsoluteEvent is an event that has an absolute time
/// This is useful for apps that want to store events internally
/// with absolute times and then quickly build an SMF file for saving etc...
pub struct AbsoluteEvent {
    time: u64,
    event: Event,
}

impl AbsoluteEvent {
    pub fn new_midi(time: u64, midi: MidiMessage) -> AbsoluteEvent {
        AbsoluteEvent {
            time: time,
            event: Event::Midi(midi),
        }
    }
    pub fn new_meta(time: u64, meta: MetaEvent) -> AbsoluteEvent {
        AbsoluteEvent {
            time: time,
            event: Event::Meta(meta),
        }
    }

    /// Return true if the event inside this AbsoluteEvent is a midi
    /// event, false if it's a meta event
    pub fn is_midi(&self) -> bool {
        match self.event {
            Event::Midi(_) => true,
            Event::Meta(_) => false,
        }
    }

    /// Return true if the event inside this AbsoluteEvent is a meta
    /// event, false if it's a midi event
    pub fn is_meta(&self) -> bool {
        match self.event {
            Event::Midi(_) => false,
            Event::Meta(_) => true,
        }
    }

    pub fn get_event(&self) -> &Event {
        &self.event
    }

    pub fn get_time(&self) -> u64 {
        self.time
    }
}

impl Eq for AbsoluteEvent {}

impl PartialEq for AbsoluteEvent {
    fn eq(&self, other: &AbsoluteEvent) -> bool {
        if self.time == other.time {
            match (&self.event,&other.event) {
                (&Event::Midi(_),&Event::Meta(_)) => false,
                (&Event::Meta(_),&Event::Midi(_)) => false,
                (&Event::Meta(ref me),&Event::Meta(ref you)) => {
                    me.command == you.command
                },
                (&Event::Midi(ref me),&Event::Midi(ref you)) => {
                    me.data(0) == you.data(0)
                        &&
                    me.data(1) == me.data(1)
                },
            }
        } else {
            false
        }
    }

    fn ne(&self, other: &AbsoluteEvent) -> bool {
        !(self.eq(other))
    }
}

// Implement `Ord` and sort messages by time
impl Ord for AbsoluteEvent {
    fn cmp(&self, other: &AbsoluteEvent) -> Ordering {
        let res = self.time.cmp(&other.time);
        match res {
            // vtime takes priority
            Ordering::Less | Ordering::Greater => res,
            // if vtime is the same, check types and make meta events
            // sort before standard events
            Ordering::Equal => {
                match (&self.event,&other.event) {
                    // I'm midi, other is meta, so I'm greater
                    (&Event::Midi(_),&Event::Meta(_)) => Ordering::Greater,
                    // I'm meta, other is midi, so I'm less
                    (&Event::Meta(_),&Event::Midi(_)) => Ordering::Less,
                    (&Event::Meta(ref me),&Event::Meta(ref you)) => {
                        me.command.cmp(&you.command)
                    },
                    (&Event::Midi(ref me),&Event::Midi(ref you)) => {
                        if      me.data(0) < you.data(0) { Ordering::Less }
                        else if me.data(0) > you.data(0) { Ordering::Greater }
                        else {
                            if me.data(1) < you.data(1) {
                                Ordering::Less
                            } else if me.data(1) > you.data(1) {
                                Ordering::Greater
                            } else {
                                res
                            }
                        }
                    },
                }
            }
        }
    }
}

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

enum EventContainer {
    Heap(BinaryHeap<AbsoluteEvent>),
    Static(Vec<TrackEvent>),
}

struct TrackBuilder {
    copyright: Option<String>,
    name: Option<String>,
    events: EventContainer,
}

impl TrackBuilder {

    fn result(self) -> Track {
        Track {
            copyright: self.copyright,
            name: self.name,
            events: match self.events {
                EventContainer::Heap(mut heap) => {
                    let mut events = Vec::new();
                    events.reserve(heap.len());
                    let mut cur_time: u64 = 0;
                    loop {
                        match heap.pop() {
                            Some(bev) => {
                                let vtime = bev.time - cur_time;
                                cur_time = vtime;
                                events.push(TrackEvent {
                                    vtime: vtime,
                                    event: bev.event,
                                });
                            }
                            None => { break; }
                        }
                    }
                    events
                },
                EventContainer::Static(vec) => vec,
            },
        }
    }

    fn abs_time_from_delta(&self,delta: u64) -> u64 {
        match self.events {
            EventContainer::Heap(ref heap) => {
                match heap.peek() {
                    Some(e) => { e.time + delta }
                    None => { delta }
                }
            }
            _ => { panic!("Can't call abs_time_from_delta on non-heap builder") }
        }
    }
}

/// An SMFBuilder can be used to create an SMF file.  This is done by
/// adding tracks to the builder via `add_track` and then adding
/// events to each track.
pub struct SMFBuilder {
    tracks:Vec<TrackBuilder>
}

impl SMFBuilder {
    /// Create a new SMFBuilder.  Initially the builder will have no tracks
    pub fn new() -> SMFBuilder {
        SMFBuilder {
            tracks: Vec::new(),
        }
    }

    /// Get the number of tracks currenly in the builder
    pub fn num_tracks(&self) -> usize {
        self.tracks.len()
    }

    /// Add new a track to this builder
    pub fn add_track(&mut self) {
        self.tracks.push(TrackBuilder {
            copyright: None,
            name: None,
            events: EventContainer::Heap(BinaryHeap::new()),
        });
    }

    /// Add a static track to the builder (note this will clone all events in the passed iterator)
    pub fn add_static_track<'a,I>(&mut self, track: I) where I: Iterator<Item=&'a AbsoluteEvent> {
        let mut cur_time: u64 = 0;
        let vec = track.map(|bev| {
            assert!(bev.time >= cur_time);
            let vtime = bev.time - cur_time;
            cur_time = vtime;
            TrackEvent {
                vtime: vtime,
                event: bev.event.clone(),
            }
        }).collect();
        self.tracks.push(TrackBuilder {
            copyright: None,
            name: None,
            events: EventContainer::Static(vec),
        });
    }

    /// Set the copyright for the track at index `track`.  This will
    /// also cause a copyright meta event to be inserted.
    /// ## Panics
    ///
    /// Panics if `track` is >= to the number of tracks in this
    /// builder, or if the track already has a copyright set.
    pub fn set_copyright(&mut self, track: usize, copyright: String) {
        assert!(self.tracks.len() > track);
        assert!(self.tracks[track].copyright.is_none());
        // let event = AbsoluteEvent {
        //     time: 0,
        //     event: Event::Meta(MetaEvent::copyright_notice(copyright.clone())),
        // };
        self.tracks[track].copyright = Some(copyright);
    }

    /// Set the name for the track at index `track`.  This will
    /// also cause a name meta event to be inserted.
    ///
    /// ## Panics
    ///
    /// Panics if `track` is >= to the number of tracks in this
    /// builder, or if the track already has a name set.
    pub fn set_name(&mut self, track: usize, name: String) {
        assert!(self.tracks.len() > track);
        assert!(self.tracks[track].name.is_none());
        // let event = AbsoluteEvent{
        //     time: 0,
        //     event: Event::Meta(MetaEvent::sequence_or_track_name(name.clone())),
        // };
        self.tracks[track].name = Some(name);
    }

    /// Add a midi message to track at index `track` at absolute time
    /// `time`.
    ///
    /// ## Panics
    ///
    /// Panics if `track` is >= to the number of tracks in this builder
    pub fn add_midi_abs(&mut self, track: usize, time: u64, msg: MidiMessage) {
        assert!(self.tracks.len() > track);
        match self.tracks.index_mut(track).events {
            EventContainer::Heap(ref mut heap) => {
                heap.push(AbsoluteEvent {
                    time: time,
                    event: Event::Midi(msg),
                });
            }
            _ => { panic!("Can't add events to static tracks") }
        }
    }

    /// Add a midi message to track at index `track` at `delta` ticks
    /// after the last message (or at `delta` if no current messages
    /// exist)
    ///
    /// ## Panics
    ///
    /// Panics if `track` is >= to the number of tracks in this builder
    pub fn add_midi_rel(&mut self, track: usize, delta: u64, msg: MidiMessage) {
        assert!(self.tracks.len() > track);
        let time = self.tracks[track].abs_time_from_delta(delta);
        self.add_midi_abs(track,time,msg);
    }

    /// Add a meta event to track at index `track` at absolute  time
    /// `time`.
    ///
    /// ## Panics
    ///
    /// Panics if `track` is >= to the number of tracks in this builder
    pub fn add_meta_abs(&mut self, track: usize, time: u64, event: MetaEvent) {
        assert!(self.tracks.len() > track);
        match self.tracks.index_mut(track).events {
            EventContainer::Heap(ref mut heap) => {
                heap.push(AbsoluteEvent {
                    time: time,
                    event: Event::Meta(event),
                });
            }
            _ => { panic!("Can't add events to static tracks") }
        }
    }

    /// Add a meta event to track at index `track` at `delta` ticks
    /// after the last message (or at `delta` if no current messages
    /// exist)
    ///
    /// ## Panics
    ///
    /// Panics if `track` is >= to the number of tracks in this builder
    pub fn add_meta_rel(&mut self, track: usize, delta: u64, event: MetaEvent) {
        assert!(self.tracks.len() > track);
        let time = self.tracks[track].abs_time_from_delta(delta);
        self.add_meta_abs(track,time,event);
    }

    /// Add a TrackEvent to the track at index `track`.  The event
    /// will be added at `event.vtime` after the last event currently
    /// in the builder for the track.
    ///
    /// ## Panics
    ///
    /// Panics if `track` is >= to the number of tracks in this builder
    pub fn add_event(&mut self, track: usize, event: TrackEvent) {
        assert!(self.tracks.len() > track);
        let bevent = AbsoluteEvent {
            time: self.tracks[track].abs_time_from_delta(event.vtime),
            event: event.event,
        };
        match self.tracks.index_mut(track).events {
            EventContainer::Heap(ref mut heap) => {
                heap.push(bevent);
            }
            _ => { panic!("Can't add events to static tracks") }
        }
    }

    /// Generate an SMF file with the events that have been added to
    /// the builder
    pub fn result(self) -> SMF {
        SMF {
            format: SMFFormat::MultiTrack,
            tracks: self.tracks.into_iter().map(|tb| tb.result()).collect(),
            division: 0,
        }
    }
}
<|endoftext|>


<commit_before>use std::cell::{Cell, RefCell};

use cairo::{self, ImageSurface};

use attributes::Attribute;
use error::{AttributeError, NodeError};
use handle::RsvgHandle;
use node::{NodeResult, NodeTrait, RsvgCNodeImpl, RsvgNode};
use parsers::{self, parse, Parse};
use property_bag::PropertyBag;
use srgb::{linearize_surface, unlinearize_surface};
use util::clamp;

use super::context::{FilterContext, FilterOutput, FilterResult};
use super::input::Input;
use super::iterators::{ImageSurfaceDataExt, ImageSurfaceDataShared, Pixel, Pixels};
use super::{get_surface, Filter, FilterError, PrimitiveWithInput};

/// Enumeration of the possible compositing operations.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
enum Operator {
    Over,
    In,
    Out,
    Atop,
    Xor,
    Arithmetic,
}

/// The `feComposite` filter primitive.
pub struct Composite {
    base: PrimitiveWithInput,
    in2: RefCell<Option<Input>>,
    operator: Cell<Operator>,
    k1: Cell<f64>,
    k2: Cell<f64>,
    k3: Cell<f64>,
    k4: Cell<f64>,
}

impl Composite {
    /// Constructs a new `Composite` with empty properties.
    #[inline]
    pub fn new() -> Composite {
        Composite {
            base: PrimitiveWithInput::new::<Self>(),
            in2: RefCell::new(None),
            operator: Cell::new(Operator::Over),
            k1: Cell::new(0f64),
            k2: Cell::new(0f64),
            k3: Cell::new(0f64),
            k4: Cell::new(0f64),
        }
    }
}

impl NodeTrait for Composite {
    fn set_atts(
        &self,
        node: &RsvgNode,
        handle: *const RsvgHandle,
        pbag: &PropertyBag,
    ) -> NodeResult {
        self.base.set_atts(node, handle, pbag)?;

        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::In2 => {
                    self.in2.replace(Some(parse("in2", value, (), None)?));
                }
                Attribute::Operator => self.operator.set(parse("operator", value, (), None)?),
                Attribute::K1 => self
                    .k1
                    .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
                Attribute::K2 => self
                    .k2
                    .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
                Attribute::K3 => self
                    .k3
                    .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
                Attribute::K4 => self
                    .k4
                    .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
                _ => (),
            }
        }

        Ok(())
    }

    #[inline]
    fn get_c_impl(&self) -> *const RsvgCNodeImpl {
        self.base.get_c_impl()
    }
}

impl Filter for Composite {
    fn render(&self, _node: &RsvgNode, ctx: &FilterContext) -> Result<FilterResult, FilterError> {
        let bounds = self.base.get_bounds(ctx);

        let input_surface = get_surface(self.base.get_input(ctx))?;
        let input_2_surface = get_surface(ctx.get_input(self.in2.borrow().as_ref()))?;

        // It's important to linearize sRGB before doing any blending, since otherwise the colors
        // will be darker than they should be.
        let input_surface =
            linearize_surface(&input_surface, bounds).map_err(FilterError::BadInputSurfaceStatus)?;

        let output_surface = if self.operator.get() == Operator::Arithmetic {
            let input_data = ImageSurfaceDataShared::new(&input_surface)?;
            let input_2_data = ImageSurfaceDataShared::new(&input_2_surface)?;

            let mut output_surface = ImageSurface::create(
                cairo::Format::ARgb32,
                input_data.width as i32,
                input_data.height as i32,
            ).map_err(FilterError::OutputSurfaceCreation)?;

            let output_stride = output_surface.get_stride() as usize;
            {
                let mut output_data = output_surface.get_data().unwrap();

                let k1 = self.k1.get();
                let k2 = self.k2.get();
                let k3 = self.k3.get();
                let k4 = self.k4.get();

                for (x, y, pixel, pixel_2) in Pixels::new(input_data, bounds)
                    .map(|(x, y, p)| (x, y, p, input_2_data.get_pixel(x, y)))
                {
                    let i1a = f64::from(pixel.a) / 255f64;
                    let i2a = f64::from(pixel_2.a) / 255f64;
                    let oa = k1 * i1a * i2a + k2 * i1a + k3 * i2a + k4;
                    let oa = clamp(oa, 0f64, 1f64);

                    // Contents of image surfaces are transparent by default, so if the
                    // resulting pixel is transparent there's no need
                    // to do anything.
                    if oa > 0f64 {
                        let compute = |i1, i2| {
                            let i1 = f64::from(i1) / 255f64;
                            let i2 = f64::from(i2) / 255f64;

                            let o = k1 * i1 * i2 + k2 * i1 + k3 * i2 + k4;
                            let o = clamp(o, 0f64, oa);

                            (o * 255f64).round() as u8
                        };

                        let output_pixel = Pixel {
                            r: compute(pixel.r, pixel_2.r),
                            g: compute(pixel.g, pixel_2.g),
                            b: compute(pixel.b, pixel_2.b),
                            a: (oa * 255f64).round() as u8,
                        };
                        output_data.set_pixel(output_stride, output_pixel, x, y);
                    }
                }
            }

            output_surface
        } else {
            let output_surface = linearize_surface(&input_2_surface, bounds)
                .map_err(FilterError::BadInputSurfaceStatus)?;

            let cr = cairo::Context::new(&output_surface);
            cr.rectangle(
                bounds.x0 as f64,
                bounds.y0 as f64,
                (bounds.x1 - bounds.x0) as f64,
                (bounds.y1 - bounds.y0) as f64,
            );
            cr.clip();

            cr.set_source_surface(&input_surface, 0f64, 0f64);
            cr.set_operator(self.operator.get().into());
            cr.paint();

            output_surface
        };

        let output_surface = unlinearize_surface(&output_surface, bounds)
            .map_err(FilterError::OutputSurfaceCreation)?;

        Ok(FilterResult {
            name: self.base.result.borrow().clone(),
            output: FilterOutput {
                surface: output_surface,
                bounds,
            },
        })
    }
}

impl Parse for Operator {
    type Data = ();
    type Err = AttributeError;

    fn parse(s: &str, _data: Self::Data) -> Result<Self, Self::Err> {
        match s {
            "over" => Ok(Operator::Over),
            "in" => Ok(Operator::In),
            "out" => Ok(Operator::Out),
            "atop" => Ok(Operator::Atop),
            "xor" => Ok(Operator::Xor),
            "arithmetic" => Ok(Operator::Arithmetic),
            _ => Err(AttributeError::Value("invalid operator value".to_string())),
        }
    }
}

impl From<Operator> for cairo::Operator {
    #[inline]
    fn from(x: Operator) -> Self {
        match x {
            Operator::Over => cairo::Operator::Over,
            Operator::In => cairo::Operator::In,
            Operator::Out => cairo::Operator::Out,
            Operator::Atop => cairo::Operator::Atop,
            Operator::Xor => cairo::Operator::Xor,
            _ => panic!("can't convert Operator::Arithmetic to a cairo::Operator"),
        }
    }
}
<commit_msg>filters/composite.rs: Use a cssparser<commit_after>use std::cell::{Cell, RefCell};

use cairo::{self, ImageSurface};
use cssparser::{CowRcStr, Parser, ParserInput, Token};

use attributes::Attribute;
use error::{AttributeError, NodeError};
use handle::RsvgHandle;
use node::{NodeResult, NodeTrait, RsvgCNodeImpl, RsvgNode};
use parsers::{self, parse, Parse};
use property_bag::PropertyBag;
use srgb::{linearize_surface, unlinearize_surface};
use util::clamp;

use super::context::{FilterContext, FilterOutput, FilterResult};
use super::input::Input;
use super::iterators::{ImageSurfaceDataExt, ImageSurfaceDataShared, Pixel, Pixels};
use super::{get_surface, Filter, FilterError, PrimitiveWithInput};

/// Enumeration of the possible compositing operations.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
enum Operator {
    Over,
    In,
    Out,
    Atop,
    Xor,
    Arithmetic,
}

/// The `feComposite` filter primitive.
pub struct Composite {
    base: PrimitiveWithInput,
    in2: RefCell<Option<Input>>,
    operator: Cell<Operator>,
    k1: Cell<f64>,
    k2: Cell<f64>,
    k3: Cell<f64>,
    k4: Cell<f64>,
}

impl Composite {
    /// Constructs a new `Composite` with empty properties.
    #[inline]
    pub fn new() -> Composite {
        Composite {
            base: PrimitiveWithInput::new::<Self>(),
            in2: RefCell::new(None),
            operator: Cell::new(Operator::Over),
            k1: Cell::new(0f64),
            k2: Cell::new(0f64),
            k3: Cell::new(0f64),
            k4: Cell::new(0f64),
        }
    }
}

impl NodeTrait for Composite {
    fn set_atts(
        &self,
        node: &RsvgNode,
        handle: *const RsvgHandle,
        pbag: &PropertyBag,
    ) -> NodeResult {
        self.base.set_atts(node, handle, pbag)?;

        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::In2 => {
                    self.in2.replace(Some(parse("in2", value, (), None)?));
                }
                Attribute::Operator => self.operator.set(parse("operator", value, (), None)?),
                Attribute::K1 => self
                    .k1
                    .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
                Attribute::K2 => self
                    .k2
                    .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
                Attribute::K3 => self
                    .k3
                    .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
                Attribute::K4 => self
                    .k4
                    .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
                _ => (),
            }
        }

        Ok(())
    }

    #[inline]
    fn get_c_impl(&self) -> *const RsvgCNodeImpl {
        self.base.get_c_impl()
    }
}

impl Filter for Composite {
    fn render(&self, _node: &RsvgNode, ctx: &FilterContext) -> Result<FilterResult, FilterError> {
        let bounds = self.base.get_bounds(ctx);

        let input_surface = get_surface(self.base.get_input(ctx))?;
        let input_2_surface = get_surface(ctx.get_input(self.in2.borrow().as_ref()))?;

        // It's important to linearize sRGB before doing any blending, since otherwise the colors
        // will be darker than they should be.
        let input_surface =
            linearize_surface(&input_surface, bounds).map_err(FilterError::BadInputSurfaceStatus)?;

        let output_surface = if self.operator.get() == Operator::Arithmetic {
            let input_data = ImageSurfaceDataShared::new(&input_surface)?;
            let input_2_data = ImageSurfaceDataShared::new(&input_2_surface)?;

            let mut output_surface = ImageSurface::create(
                cairo::Format::ARgb32,
                input_data.width as i32,
                input_data.height as i32,
            ).map_err(FilterError::OutputSurfaceCreation)?;

            let output_stride = output_surface.get_stride() as usize;
            {
                let mut output_data = output_surface.get_data().unwrap();

                let k1 = self.k1.get();
                let k2 = self.k2.get();
                let k3 = self.k3.get();
                let k4 = self.k4.get();

                for (x, y, pixel, pixel_2) in Pixels::new(input_data, bounds)
                    .map(|(x, y, p)| (x, y, p, input_2_data.get_pixel(x, y)))
                {
                    let i1a = f64::from(pixel.a) / 255f64;
                    let i2a = f64::from(pixel_2.a) / 255f64;
                    let oa = k1 * i1a * i2a + k2 * i1a + k3 * i2a + k4;
                    let oa = clamp(oa, 0f64, 1f64);

                    // Contents of image surfaces are transparent by default, so if the
                    // resulting pixel is transparent there's no need
                    // to do anything.
                    if oa > 0f64 {
                        let compute = |i1, i2| {
                            let i1 = f64::from(i1) / 255f64;
                            let i2 = f64::from(i2) / 255f64;

                            let o = k1 * i1 * i2 + k2 * i1 + k3 * i2 + k4;
                            let o = clamp(o, 0f64, oa);

                            (o * 255f64).round() as u8
                        };

                        let output_pixel = Pixel {
                            r: compute(pixel.r, pixel_2.r),
                            g: compute(pixel.g, pixel_2.g),
                            b: compute(pixel.b, pixel_2.b),
                            a: (oa * 255f64).round() as u8,
                        };
                        output_data.set_pixel(output_stride, output_pixel, x, y);
                    }
                }
            }

            output_surface
        } else {
            let output_surface = linearize_surface(&input_2_surface, bounds)
                .map_err(FilterError::BadInputSurfaceStatus)?;

            let cr = cairo::Context::new(&output_surface);
            cr.rectangle(
                bounds.x0 as f64,
                bounds.y0 as f64,
                (bounds.x1 - bounds.x0) as f64,
                (bounds.y1 - bounds.y0) as f64,
            );
            cr.clip();

            cr.set_source_surface(&input_surface, 0f64, 0f64);
            cr.set_operator(self.operator.get().into());
            cr.paint();

            output_surface
        };

        let output_surface = unlinearize_surface(&output_surface, bounds)
            .map_err(FilterError::OutputSurfaceCreation)?;

        Ok(FilterResult {
            name: self.base.result.borrow().clone(),
            output: FilterOutput {
                surface: output_surface,
                bounds,
            },
        })
    }
}

impl Parse for Operator {
    type Data = ();
    type Err = AttributeError;

    fn parse(s: &str, _data: Self::Data) -> Result<Self, Self::Err> {
        let mut input = ParserInput::new(s);
        let mut parser = Parser::new(&mut input);
        let loc = parser.current_source_location();

        parser
            .expect_ident()
            .and_then(|cow| match cow.as_ref() {
                "over" => Ok(Operator::Over),
                "in" => Ok(Operator::In),
                "out" => Ok(Operator::Out),
                "atop" => Ok(Operator::Atop),
                "xor" => Ok(Operator::Xor),
                "arithmetic" => Ok(Operator::Arithmetic),
                _ => Err(
                    loc.new_basic_unexpected_token_error(Token::Ident(CowRcStr::from(
                        cow.as_ref().to_string(),
                    ))),
                ),
            })
            .map_err(|_| AttributeError::Value("invalid operator value".to_string()))
    }
}

impl From<Operator> for cairo::Operator {
    #[inline]
    fn from(x: Operator) -> Self {
        match x {
            Operator::Over => cairo::Operator::Over,
            Operator::In => cairo::Operator::In,
            Operator::Out => cairo::Operator::Out,
            Operator::Atop => cairo::Operator::Atop,
            Operator::Xor => cairo::Operator::Xor,
            _ => panic!("can't convert Operator::Arithmetic to a cairo::Operator"),
        }
    }
}
<|endoftext|>


<commit_before>use std::cell::Cell;
use std::mem;
use std::ptr;

use super::{Allocator, AllocatorError, HeapAllocator, HEAP};

/// A scoped linear allocator
pub struct ScopedAllocator<'parent, A: 'parent + Allocator> {
    allocator: &'parent A,
    current: Cell<*mut u8>,
    end: *mut u8,
    root: bool,
    start: *mut u8,
}

impl ScopedAllocator<'static, HeapAllocator> {
    /// Creates a new `ScopedAllocator` backed by `size` bytes from the heap.
    pub fn new(size: usize) -> Result<Self, AllocatorError> {
        ScopedAllocator::new_from(HEAP, size)
    }
}

impl<'parent, A: Allocator> ScopedAllocator<'parent, A> {
    /// Creates a new `ScopedAllocator` backed by `size` bytes from the allocator supplied.
    pub fn new_from(alloc: &'parent A, size: usize) -> Result<Self, AllocatorError> {
        // Create a memory buffer with the desired size and maximal align from the parent.
        match unsafe { alloc.allocate_raw(size, mem::align_of::<usize>()) } {
            Ok(start) => Ok(ScopedAllocator {
                allocator: alloc,
                current: Cell::new(start),
                end: unsafe { start.offset(size as isize) },
                root: true,
                start: start,
            }),
            Err(err) => Err(err),
        }
    }

    /// Calls the supplied function with a new scope of the allocator.
    ///
    /// Returns the result of the closure or an error if this allocator
    /// has already been scoped.
    pub fn scope<F, U>(&self, f: F) -> Result<U, ()>
        where F: FnMut(&Self) -> U
    {
        if self.is_scoped() {
            return Err(())
        }

        let mut f = f;
        let old = self.current.get();
        let alloc = ScopedAllocator {
            allocator: self.allocator,
            current: self.current.clone(),
            end: self.end,
            root: false,
            start: self.start,
        };

        // set the current pointer to null as a flag to indicate
        // that this allocator is being scoped.
        self.current.set(ptr::null_mut());
        let u = f(&alloc);
        self.current.set(old);

        mem::forget(alloc);
        Ok(u)
    }

    // Whether this allocator is currently scoped.
    pub fn is_scoped(&self) -> bool {
        self.current.get().is_null()
    }
}

unsafe impl<'a, A: Allocator> Allocator for ScopedAllocator<'a, A> {
    unsafe fn allocate_raw(&self, size: usize, align: usize) -> Result<*mut u8, AllocatorError> {
        if self.is_scoped() {
            return Err(AllocatorError::AllocatorSpecific("Called allocate on already scoped \
                                                          allocator."
                                                             .into()))
        }

        let current_ptr = self.current.get();
        let aligned_ptr = ((current_ptr as usize + align - 1) & !(align - 1)) as *mut u8;
        let end_ptr = aligned_ptr.offset(size as isize);

        if end_ptr > self.end {
            Err(AllocatorError::OutOfMemory)
        } else {
            self.current.set(end_ptr);
            Ok(aligned_ptr)
        }
    }

    #[allow(unused_variables)]
    unsafe fn deallocate_raw(&self, ptr: *mut u8, size: usize, align: usize) {
        // no op for this. The memory gets reused when the scope is cleared.
    }
}

impl<'a, A: Allocator> Drop for ScopedAllocator<'a, A> {
    /// Drops the `ScopedAllocator`
    fn drop(&mut self) {
        let size = self.end as usize - self.start as usize;
        // only free if this allocator is the root to make sure
        // that memory is freed after destructors for allocated objects
        // are called in case of unwind
        if self.root && size > 0 {
            unsafe { self.allocator.deallocate_raw(self.start, size, mem::align_of::<usize>()) }
        }
    }
}

#[cfg(test)]
mod tests {
    use std::any::Any;

    use super::super::*;

    #[test]
    #[should_panic]
    fn use_outer() {
        let alloc = ScopedAllocator::new(4).unwrap();
        let mut outer_val = alloc.allocate_val(0i32).ok().unwrap();
        alloc.scope(|_inner| {
            // using outer allocator is dangerous and should fail.
                 outer_val = alloc.allocate_val(1i32).ok().unwrap();
             })
             .unwrap();
    }

    #[test]
    fn unsizing() {
        struct Bomb;
        impl Drop for Bomb {
            fn drop(&mut self) {
                println!("Boom")
            }
        }

        let alloc = ScopedAllocator::new(4).unwrap();
        let my_foo: Allocated<Any, _> = alloc.allocate_val(Bomb).ok().unwrap();
        let _: Allocated<Bomb, _> = my_foo.downcast().ok().unwrap();
    }

    #[test]
    fn scope_scope() {
        let alloc = ScopedAllocator::new(64).unwrap();
        let _ = alloc.allocate_val(0).ok().unwrap();
        alloc.scope(|inner| {
                 let _ = inner.allocate_val(32);
                 inner.scope(|bottom| {
                          let _ = bottom.allocate_val(23);
                      })
                      .unwrap();
             })
             .unwrap();
    }

    #[test]
    fn out_of_memory() {
        // allocate more memory than the allocator has.
        let alloc = ScopedAllocator::new(0).unwrap();
        let (err, _) = alloc.allocate_val(1i32).err().unwrap();
        assert_eq!(err, AllocatorError::OutOfMemory);
    }

    #[test]
    fn placement_in() {
        let alloc = ScopedAllocator::new(8_000_000).unwrap();
        // this would smash the stack otherwise.
        let _big = in alloc.allocate().unwrap() { [0u8; 8_000_000] };
    }
}
<commit_msg>Refined ScopeAllocator::deallocate_raw<commit_after>use std::cell::Cell;
use std::mem;
use std::ptr;

use super::{Allocator, AllocatorError, HeapAllocator, HEAP};

/// A scoped linear allocator
pub struct ScopedAllocator<'parent, A: 'parent + Allocator> {
    allocator: &'parent A,
    current: Cell<*mut u8>,
    end: *mut u8,
    root: bool,
    start: *mut u8,
}

impl ScopedAllocator<'static, HeapAllocator> {
    /// Creates a new `ScopedAllocator` backed by `size` bytes from the heap.
    pub fn new(size: usize) -> Result<Self, AllocatorError> {
        ScopedAllocator::new_from(HEAP, size)
    }
}

impl<'parent, A: Allocator> ScopedAllocator<'parent, A> {
    /// Creates a new `ScopedAllocator` backed by `size` bytes from the allocator supplied.
    pub fn new_from(alloc: &'parent A, size: usize) -> Result<Self, AllocatorError> {
        // Create a memory buffer with the desired size and maximal align from the parent.
        match unsafe { alloc.allocate_raw(size, mem::align_of::<usize>()) } {
            Ok(start) => Ok(ScopedAllocator {
                allocator: alloc,
                current: Cell::new(start),
                end: unsafe { start.offset(size as isize) },
                root: true,
                start: start,
            }),
            Err(err) => Err(err),
        }
    }

    /// Calls the supplied function with a new scope of the allocator.
    ///
    /// Returns the result of the closure or an error if this allocator
    /// has already been scoped.
    pub fn scope<F, U>(&self, f: F) -> Result<U, ()>
        where F: FnMut(&Self) -> U
    {
        if self.is_scoped() {
            return Err(())
        }

        let mut f = f;
        let old = self.current.get();
        let alloc = ScopedAllocator {
            allocator: self.allocator,
            current: self.current.clone(),
            end: self.end,
            root: false,
            start: self.start,
        };

        // set the current pointer to null as a flag to indicate
        // that this allocator is being scoped.
        self.current.set(ptr::null_mut());
        let u = f(&alloc);
        self.current.set(old);

        mem::forget(alloc);
        Ok(u)
    }

    // Whether this allocator is currently scoped.
    pub fn is_scoped(&self) -> bool {
        self.current.get().is_null()
    }
}

unsafe impl<'a, A: Allocator> Allocator for ScopedAllocator<'a, A> {
    unsafe fn allocate_raw(&self, size: usize, align: usize) -> Result<*mut u8, AllocatorError> {
        if self.is_scoped() {
            return Err(AllocatorError::AllocatorSpecific("Called allocate on already scoped \
                                                          allocator."
                                                             .into()))
        }

        let current_ptr = self.current.get();
        let aligned_ptr = ((current_ptr as usize + align - 1) & !(align - 1)) as *mut u8;
        let end_ptr = aligned_ptr.offset(size as isize);

        if end_ptr > self.end {
            Err(AllocatorError::OutOfMemory)
        } else {
            self.current.set(end_ptr);
            Ok(aligned_ptr)
        }
    }

    #[allow(unused_variables)]
    unsafe fn deallocate_raw(&self, ptr: *mut u8, size: usize, align: usize) {
        // no op for this unless this is the last allocation.
        // The memory gets reused when the scope is cleared.
        let current_ptr = self.current.get();
        if !self.is_scoped() && ptr.offset(size as isize) == current_ptr {
            self.current.set(ptr);
        }
    }
}

impl<'a, A: Allocator> Drop for ScopedAllocator<'a, A> {
    /// Drops the `ScopedAllocator`
    fn drop(&mut self) {
        let size = self.end as usize - self.start as usize;
        // only free if this allocator is the root to make sure
        // that memory is freed after destructors for allocated objects
        // are called in case of unwind
        if self.root && size > 0 {
            unsafe { self.allocator.deallocate_raw(self.start, size, mem::align_of::<usize>()) }
        }
    }
}

#[cfg(test)]
mod tests {
    use std::any::Any;

    use super::super::*;

    #[test]
    #[should_panic]
    fn use_outer() {
        let alloc = ScopedAllocator::new(4).unwrap();
        let mut outer_val = alloc.allocate_val(0i32).ok().unwrap();
        alloc.scope(|_inner| {
            // using outer allocator is dangerous and should fail.
                 outer_val = alloc.allocate_val(1i32).ok().unwrap();
             })
             .unwrap();
    }

    #[test]
    fn unsizing() {
        struct Bomb;
        impl Drop for Bomb {
            fn drop(&mut self) {
                println!("Boom")
            }
        }

        let alloc = ScopedAllocator::new(4).unwrap();
        let my_foo: Allocated<Any, _> = alloc.allocate_val(Bomb).ok().unwrap();
        let _: Allocated<Bomb, _> = my_foo.downcast().ok().unwrap();
    }

    #[test]
    fn scope_scope() {
        let alloc = ScopedAllocator::new(64).unwrap();
        let _ = alloc.allocate_val(0).ok().unwrap();
        alloc.scope(|inner| {
                 let _ = inner.allocate_val(32);
                 inner.scope(|bottom| {
                          let _ = bottom.allocate_val(23);
                      })
                      .unwrap();
             })
             .unwrap();
    }

    #[test]
    fn out_of_memory() {
        // allocate more memory than the allocator has.
        let alloc = ScopedAllocator::new(0).unwrap();
        let (err, _) = alloc.allocate_val(1i32).err().unwrap();
        assert_eq!(err, AllocatorError::OutOfMemory);
    }

    #[test]
    fn placement_in() {
        let alloc = ScopedAllocator::new(8_000_000).unwrap();
        // this would smash the stack otherwise.
        let _big = in alloc.allocate().unwrap() { [0u8; 8_000_000] };
    }
}
<|endoftext|>


<commit_before>// #![feature(scoped)]
// #![feature(collections)]

extern crate mmap;
extern crate time;
extern crate timely;
extern crate columnar;
extern crate dataflow_join;

extern crate docopt;
use docopt::Docopt;

use std::thread;

use dataflow_join::graph::{GraphTrait, GraphMMap};

use timely::progress::timestamp::RootTimestamp;
use timely::progress::scope::Scope;
use timely::progress::nested::Summary::Local;
use timely::example_static::*;
use timely::communication::*;
use timely::communication::pact::Exchange;

use timely::networking::initialize_networking;
use timely::networking::initialize_networking_from_file;

use timely::drain::DrainExt;

static USAGE: &'static str = "
Usage: pagerank <source> [options] [<arguments>...]

Options:
    -w <arg>, --workers <arg>    number of workers per process [default: 1]
    -p <arg>, --processid <arg>  identity of this process      [default: 0]
    -n <arg>, --processes <arg>  number of processes involved  [default: 1]
    -h <arg>, --hosts <arg>      list of host:port for workers
";

fn main () {
    let args = Docopt::new(USAGE).and_then(|dopt| dopt.parse()).unwrap_or_else(|e| e.exit());

    // let workers = if let Ok(threads) = args.get_str("<workers>").parse() { threads }
    //               else { panic!("invalid setting for workers: {}", args.get_str("<workers>")) };
    // println!("starting pagerank dataflow with {:?} worker{}", workers, if workers == 1 { "" } else { "s" });
    let source = args.get_str("<source>").to_owned();

    let workers: u64 = if let Ok(threads) = args.get_str("-w").parse() { threads }
                       else { panic!("invalid setting for --workers: {}", args.get_str("-t")) };
    let process_id: u64 = if let Ok(proc_id) = args.get_str("-p").parse() { proc_id }
                          else { panic!("invalid setting for --processid: {}", args.get_str("-p")) };
    let processes: u64 = if let Ok(processes) = args.get_str("-n").parse() { processes }
                         else { panic!("invalid setting for --processes: {}", args.get_str("-n")) };

    println!("Starting pagerank dataflow with");
    println!("\tworkers:\t{}", workers);
    println!("\tprocesses:\t{}", processes);
    println!("\tprocessid:\t{}", process_id);

    // vector holding communicators to use; one per local worker.
    if processes > 1 {
        println!("Initializing BinaryCommunicator");

        let hosts = args.get_str("-h");
        let communicators = if hosts != "" {
            initialize_networking_from_file(hosts, process_id, workers).ok().expect("error initializing networking")
        }
        else {
            let addresses = (0..processes).map(|index| format!("localhost:{}", 2101 + index).to_string()).collect();
            initialize_networking(addresses, process_id, workers).ok().expect("error initializing networking")
        };

        pagerank_multi(communicators, source);
    }
    else if workers > 1 {
        println!("Initializing ProcessCommunicator");
        pagerank_multi(ProcessCommunicator::new_vector(workers), source);
    }
    else {
        println!("Initializing ThreadCommunicator");
        pagerank_multi(vec![ThreadCommunicator], source);
    };
}

fn pagerank_multi<C>(communicators: Vec<C>, filename: String)
where C: Communicator+Send {
    let mut guards = Vec::new();
    let workers = communicators.len();
    for communicator in communicators.into_iter() {
        let filename = filename.clone();
        guards.push(thread::Builder::new().name(format!("timely worker {}", communicator.index()))
                                          .spawn(move || pagerank(communicator, filename, workers))
                                          .unwrap());
    }

    for guard in guards { guard.join().unwrap(); }
}

fn transpose(filename: String, index: usize, peers: usize) -> (Vec<u32>, Vec<(u32, u32)>, Vec<u32>)  {

    let graph = GraphMMap::<u32>::new(&filename);

    let mut edges = Vec::new();
    let mut deg = vec![];

    for node in 0..graph.nodes() {
        if node % peers == index {
            deg.push(graph.edges(node).len() as u32);
            for &b in graph.edges(node) {
                edges.push((b as u32, node as u32));
            }
        }
    }

    println!("slice {} of {} extracted {} edges", index, peers, edges.len());

    edges.sort();

    let mut rev = vec![(0,0);0];
    let mut reversed = vec![];
    for (d, s) in edges.drain_temp() {
        let len = rev.len();
        if len == 0 || rev[len-1].1 < d {
            rev.push((d, 0));
        }

        let len = rev.len();
        rev[len-1].1 += 1;
        reversed.push(s);
    }

    return (deg, rev, reversed);
}

fn pagerank<C>(communicator: C, filename: String, workers: usize)
where C: Communicator {
    let index = communicator.index() as usize;
    let peers = communicator.peers() as usize;

    let mut root = GraphRoot::new(communicator);

    {   // new scope avoids long borrow on root
        let mut builder = root.new_subgraph();

        // establish the beginnings of a loop,
        // 20 iterations, each time around += 1.
        let (helper, stream) = builder.loop_variable::<(u32, f32)>(RootTimestamp::new(20), Local(1));

        let mut start = time::precise_time_s();

        let (deg, rev, edges) = transpose(filename, index, peers);

        println!("sorted {} edges; {}s", edges.len(), time::precise_time_s() - start);
        start = time::precise_time_s();

        let mut src = vec![0.0; deg.len()];

        // from feedback, place an operator that
        // aggregates and broadcasts ranks along edges.
        let ranks = stream.enable(builder).unary_notify(

            Exchange::new(|x: &(u32, f32)| x.0 as u64),     // 1. how data should be exchanged
            format!("PageRank"),                            // 2. a tasteful, descriptive name
            vec![RootTimestamp::new(0)],                    // 3. indicate an initial capability
            move |input, output, iterator| {                // 4. provide the operator logic

                while let Some((iter, _)) = iterator.next() {

                    for node in 0..src.len() {
                        src[node] = 0.15 + 0.85 * src[node] / deg[node] as f32;
                    }

                    let mut session = output.session(&iter);

                    let mut counter = 0;
                    let mut slice = &edges[..];
                    for &(dst, deg) in &rev {
                        let mut accum = 0.0;
                        for &s in &slice[..deg as usize] {
                            accum += src[s as usize];
                        }
                        slice = &slice[deg as usize..];
                        session.give((dst, accum));
                        counter += 1;
                    }

                    for s in &mut src { *s = 0.0; }

                    println!("iteration {:?}: {}s; sent {} updates", iter, time::precise_time_s() - start, counter);
                    start = time::precise_time_s();
                }

                while let Some((iter, data)) = input.pull() {
                    iterator.notify_at(&iter);
                    for (node, rank) in data.drain_temp() {
                        src[node as usize / peers] += rank;
                    }
                }
            }
        );

        // let local_index = index as usize % workers;
        // let mut acc = vec![0.0; src.len()];

        ranks
        // .unary_notify(
        //     Exchange::new(move |x: &(u32, f32)| (workers * (index / workers)) as u64 + (x.0 as u64 % workers as u64)),
        //     format!("Aggregation"),
        //     vec![],
        //     move |input, output, iterator| {
        //         while let Some((iter, data)) = input.pull() {
        //             iterator.notify_at(&iter);
        //             for (node, rank) in data.drain_temp() {
        //                 acc[node as usize / workers] += rank;
        //             }
        //         }
        //
        //         while let Some((item, _)) = iterator.next() {
        //
        //             output.give_at(&item, acc.drain_temp().enumerate().filter(|x| x.1 != 0.0)
        //                                      .map(|(u,f)| (((u * workers + local_index) as u32), f)));
        //
        //             for _ in 0..(1 + (nodes/workers)) { acc.push(0.0); }
        //             assert!(acc.len() == (1 + (nodes/workers)));
        //         }
        //     }
        // )
        .connect_loop(helper);
    }

    while root.step() { }
}
<commit_msg>updated transpose implementation<commit_after>// #![feature(scoped)]
// #![feature(collections)]

extern crate mmap;
extern crate time;
extern crate timely;
extern crate columnar;
extern crate dataflow_join;

extern crate docopt;
use docopt::Docopt;

use std::thread;

use dataflow_join::graph::{GraphTrait, GraphMMap};

use timely::progress::timestamp::RootTimestamp;
use timely::progress::scope::Scope;
use timely::progress::nested::Summary::Local;
use timely::example_static::*;
use timely::communication::*;
use timely::communication::pact::Exchange;

use timely::networking::initialize_networking;
use timely::networking::initialize_networking_from_file;

use timely::drain::DrainExt;

static USAGE: &'static str = "
Usage: pagerank <source> [options] [<arguments>...]

Options:
    -w <arg>, --workers <arg>    number of workers per process [default: 1]
    -p <arg>, --processid <arg>  identity of this process      [default: 0]
    -n <arg>, --processes <arg>  number of processes involved  [default: 1]
    -h <arg>, --hosts <arg>      list of host:port for workers
";

fn main () {
    let args = Docopt::new(USAGE).and_then(|dopt| dopt.parse()).unwrap_or_else(|e| e.exit());

    // let workers = if let Ok(threads) = args.get_str("<workers>").parse() { threads }
    //               else { panic!("invalid setting for workers: {}", args.get_str("<workers>")) };
    // println!("starting pagerank dataflow with {:?} worker{}", workers, if workers == 1 { "" } else { "s" });
    let source = args.get_str("<source>").to_owned();

    let workers: u64 = if let Ok(threads) = args.get_str("-w").parse() { threads }
                       else { panic!("invalid setting for --workers: {}", args.get_str("-t")) };
    let process_id: u64 = if let Ok(proc_id) = args.get_str("-p").parse() { proc_id }
                          else { panic!("invalid setting for --processid: {}", args.get_str("-p")) };
    let processes: u64 = if let Ok(processes) = args.get_str("-n").parse() { processes }
                         else { panic!("invalid setting for --processes: {}", args.get_str("-n")) };

    println!("Starting pagerank dataflow with");
    println!("\tworkers:\t{}", workers);
    println!("\tprocesses:\t{}", processes);
    println!("\tprocessid:\t{}", process_id);

    // vector holding communicators to use; one per local worker.
    if processes > 1 {
        println!("Initializing BinaryCommunicator");

        let hosts = args.get_str("-h");
        let communicators = if hosts != "" {
            initialize_networking_from_file(hosts, process_id, workers).ok().expect("error initializing networking")
        }
        else {
            let addresses = (0..processes).map(|index| format!("localhost:{}", 2101 + index).to_string()).collect();
            initialize_networking(addresses, process_id, workers).ok().expect("error initializing networking")
        };

        pagerank_multi(communicators, source);
    }
    else if workers > 1 {
        println!("Initializing ProcessCommunicator");
        pagerank_multi(ProcessCommunicator::new_vector(workers), source);
    }
    else {
        println!("Initializing ThreadCommunicator");
        pagerank_multi(vec![ThreadCommunicator], source);
    };
}

fn pagerank_multi<C>(communicators: Vec<C>, filename: String)
where C: Communicator+Send {
    let mut guards = Vec::new();
    let workers = communicators.len();
    for communicator in communicators.into_iter() {
        let filename = filename.clone();
        guards.push(thread::Builder::new().name(format!("timely worker {}", communicator.index()))
                                          .spawn(move || pagerank(communicator, filename, workers))
                                          .unwrap());
    }

    for guard in guards { guard.join().unwrap(); }
}

fn transpose(filename: String, index: usize, peers: usize) -> (Vec<u32>, Vec<(u32, u32)>, Vec<u32>)  {

    let graph = GraphMMap::<u32>::new(&filename);

    let mut edges = Vec::new();
    let mut deg = vec![];

    for node in 0..graph.nodes() {
        if node % peers == index {
            deg.push(graph.edges(node).len() as u32);
            for &b in graph.edges(node) {
                edges.push((b as u32, node as u32));
            }
        }
    }

    println!("slice {} of {} extracted {} edges", index, peers, edges.len());

    edges.sort();

    let mut rev = vec![(0,0);0];
    let mut reversed = vec![];
    for (d, s) in edges.drain_temp() {
        let len = rev.len();
        if len == 0 || rev[len-1].1 < d {
            rev.push((d, 0));
        }

        let len = rev.len();
        rev[len-1].1 += 1;
        reversed.push(s / peers);
    }

    return (deg, rev, reversed);
}

fn pagerank<C>(communicator: C, filename: String, workers: usize)
where C: Communicator {
    let index = communicator.index() as usize;
    let peers = communicator.peers() as usize;

    let mut root = GraphRoot::new(communicator);

    {   // new scope avoids long borrow on root
        let mut builder = root.new_subgraph();

        // establish the beginnings of a loop,
        // 20 iterations, each time around += 1.
        let (helper, stream) = builder.loop_variable::<(u32, f32)>(RootTimestamp::new(20), Local(1));

        let mut start = time::precise_time_s();

        let (deg, rev, edges) = transpose(filename, index, peers);

        println!("sorted {} edges; {}s", edges.len(), time::precise_time_s() - start);
        start = time::precise_time_s();

        let mut src = vec![0.0; deg.len()];

        // from feedback, place an operator that
        // aggregates and broadcasts ranks along edges.
        let ranks = stream.enable(builder).unary_notify(

            Exchange::new(|x: &(u32, f32)| x.0 as u64),     // 1. how data should be exchanged
            format!("PageRank"),                            // 2. a tasteful, descriptive name
            vec![RootTimestamp::new(0)],                    // 3. indicate an initial capability
            move |input, output, iterator| {                // 4. provide the operator logic

                while let Some((iter, _)) = iterator.next() {

                    for node in 0..src.len() {
                        src[node] = 0.15 + 0.85 * src[node] / deg[node] as f32;
                    }

                    let mut session = output.session(&iter);

                    let mut counter = 0;
                    let mut slice = &edges[..];
                    for &(dst, deg) in &rev {
                        let mut accum = 0.0;
                        for &s in &slice[..deg as usize] {
                            accum += src[s as usize];
                        }
                        slice = &slice[deg as usize..];
                        session.give((dst, accum));
                        counter += 1;
                    }

                    for s in &mut src { *s = 0.0; }

                    println!("iteration {:?}: {}s; sent {} updates", iter, time::precise_time_s() - start, counter);
                    start = time::precise_time_s();
                }

                while let Some((iter, data)) = input.pull() {
                    iterator.notify_at(&iter);
                    for (node, rank) in data.drain_temp() {
                        src[node as usize / peers] += rank;
                    }
                }
            }
        );

        // let local_index = index as usize % workers;
        // let mut acc = vec![0.0; src.len()];

        ranks
        // .unary_notify(
        //     Exchange::new(move |x: &(u32, f32)| (workers * (index / workers)) as u64 + (x.0 as u64 % workers as u64)),
        //     format!("Aggregation"),
        //     vec![],
        //     move |input, output, iterator| {
        //         while let Some((iter, data)) = input.pull() {
        //             iterator.notify_at(&iter);
        //             for (node, rank) in data.drain_temp() {
        //                 acc[node as usize / workers] += rank;
        //             }
        //         }
        //
        //         while let Some((item, _)) = iterator.next() {
        //
        //             output.give_at(&item, acc.drain_temp().enumerate().filter(|x| x.1 != 0.0)
        //                                      .map(|(u,f)| (((u * workers + local_index) as u32), f)));
        //
        //             for _ in 0..(1 + (nodes/workers)) { acc.push(0.0); }
        //             assert!(acc.len() == (1 + (nodes/workers)));
        //         }
        //     }
        // )
        .connect_loop(helper);
    }

    while root.step() { }
}
<|endoftext|>