<commit_before>use std::convert::{TryFrom, TryInto};

use rustc_data_structures::fx::FxHashMap;
use rustc_session::Session;

use cranelift_module::{FuncId, Module};

use object::{SectionKind, SymbolFlags, RelocationKind, RelocationEncoding};
use object::write::*;

use cranelift_object::*;

use gimli::SectionId;

use crate::debuginfo::{DebugReloc, DebugRelocName};

pub(crate) trait WriteMetadata {
    fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>, is_like_osx: bool);
}

impl WriteMetadata for object::write::Object {
    fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>, _is_like_osx: bool) {
        let segment = self.segment_name(object::write::StandardSegment::Data).to_vec();
        let section_id = self.add_section(segment, b".rustc".to_vec(), object::SectionKind::Data);
        let offset = self.append_section_data(section_id, &data, 1);
        // For MachO and probably PE this is necessary to prevent the linker from throwing away the
        // .rustc section. For ELF this isn't necessary, but it also doesn't harm.
        self.add_symbol(object::write::Symbol {
            name: symbol_name.into_bytes(),
            value: offset,
            size: data.len() as u64,
            kind: object::SymbolKind::Data,
            scope: object::SymbolScope::Dynamic,
            weak: false,
            section: SymbolSection::Section(section_id),
            flags: SymbolFlags::None,
        });
    }
}

pub(crate) trait WriteDebugInfo {
    type SectionId: Copy;

    fn add_debug_section(&mut self, name: SectionId, data: Vec<u8>) -> Self::SectionId;
    fn add_debug_reloc(
        &mut self,
        section_map: &FxHashMap<SectionId, Self::SectionId>,
        from: &Self::SectionId,
        reloc: &DebugReloc,
    );
}

impl WriteDebugInfo for ObjectProduct {
    type SectionId = (object::write::SectionId, object::write::SymbolId);

    fn add_debug_section(
        &mut self,
        id: SectionId,
        data: Vec<u8>,
    ) -> (object::write::SectionId, object::write::SymbolId) {
        let name = if self.object.format() == object::BinaryFormat::MachO {
            id.name().replace('.', "__") // machO expects __debug_info instead of .debug_info
        } else {
            id.name().to_string()
        }.into_bytes();

        let segment = self.object.segment_name(StandardSegment::Debug).to_vec();
        let section_id = self.object.add_section(segment, name, SectionKind::Debug);
        self.object.section_mut(section_id).set_data(data, 1);
        let symbol_id = self.object.section_symbol(section_id);
        (section_id, symbol_id)
    }

    fn add_debug_reloc(
        &mut self,
        section_map: &FxHashMap<SectionId, Self::SectionId>,
        from: &Self::SectionId,
        reloc: &DebugReloc,
    ) {
        let (symbol, symbol_offset) = match reloc.name {
            DebugRelocName::Section(id) => {
                (section_map.get(&id).unwrap().1, 0)
            }
            DebugRelocName::Symbol(id) => {
                let symbol_id = self.function_symbol(FuncId::from_u32(id.try_into().unwrap()));
                self.object.symbol_section_and_offset(symbol_id).expect("Debug reloc for undef sym???")
            }
        };
        self.object.add_relocation(from.0, Relocation {
            offset: u64::from(reloc.offset),
            symbol,
            kind: RelocationKind::Absolute,
            encoding: RelocationEncoding::Generic,
            size: reloc.size * 8,
            addend: i64::try_from(symbol_offset).unwrap() + reloc.addend,
        }).unwrap();
    }
}

// FIXME remove once atomic instructions are implemented in Cranelift.
pub(crate) trait AddConstructor {
    fn add_constructor(&mut self, func_id: FuncId);
}

impl AddConstructor for ObjectProduct {
    fn add_constructor(&mut self, func_id: FuncId) {
        let symbol = self.function_symbol(func_id);
        let segment = self.object.segment_name(object::write::StandardSegment::Data);
        let init_array_section = self.object.add_section(segment.to_vec(), b".init_array".to_vec(), SectionKind::Data);
        self.object.append_section_data(
            init_array_section,
            &std::iter::repeat(0).take(8 /*FIXME pointer size*/).collect::<Vec<u8>>(),
            8,
        );
        self.object.add_relocation(init_array_section, object::write::Relocation {
            offset: 0,
            size: 64, // FIXME pointer size
            kind: RelocationKind::Absolute,
            encoding: RelocationEncoding::Generic,
            symbol,
            addend: 0,
        }).unwrap();
    }
}

pub(crate) trait Emit {
    fn emit(self) -> Vec<u8>;
}

impl Emit for ObjectProduct {
    fn emit(self) -> Vec<u8> {
        self.object.write().unwrap()
    }
}

pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object)) -> Vec<u8> {
    let triple = crate::build_isa(sess, true).triple().clone();

    let binary_format = match triple.binary_format {
        target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf,
        target_lexicon::BinaryFormat::Coff => object::BinaryFormat::Coff,
        target_lexicon::BinaryFormat::Macho => object::BinaryFormat::MachO,
        target_lexicon::BinaryFormat::Wasm => sess.fatal("binary format wasm is unsupported"),
        target_lexicon::BinaryFormat::Unknown => sess.fatal("binary format is unknown"),
    };
    let architecture = match triple.architecture {
        target_lexicon::Architecture::I386
        | target_lexicon::Architecture::I586
        | target_lexicon::Architecture::I686 => object::Architecture::I386,
        target_lexicon::Architecture::X86_64 => object::Architecture::X86_64,
        target_lexicon::Architecture::Arm(_) => object::Architecture::Arm,
        target_lexicon::Architecture::Aarch64(_) => object::Architecture::Aarch64,
        architecture => sess.fatal(&format!(
            "target architecture {:?} is unsupported",
            architecture,
        ))
    };
    let endian = match triple.endianness().unwrap() {
        target_lexicon::Endianness::Little => object::Endianness::Little,
        target_lexicon::Endianness::Big => object::Endianness::Big,
    };

    let mut metadata_object = object::write::Object::new(binary_format, architecture, endian);
    metadata_object.add_file_symbol(name.as_bytes().to_vec());
    f(&mut metadata_object);
    metadata_object.write().unwrap()
}

pub(crate) type Backend = impl cranelift_module::Backend<Product: AddConstructor + Emit + WriteDebugInfo>;

pub(crate) fn make_module(sess: &Session, name: String) -> Module<Backend> {
    let module: Module<ObjectBackend> = Module::new(
        ObjectBuilder::new(
            crate::build_isa(sess, true),
            name + ".o",
            cranelift_module::default_libcall_names(),
        ).unwrap(),
    );
    module
}
<commit_msg>Fix ambiguity between object and cranelift_object::object<commit_after>use std::convert::{TryFrom, TryInto};

use rustc_data_structures::fx::FxHashMap;
use rustc_session::Session;

use cranelift_module::{FuncId, Module};

use object::{SectionKind, SymbolFlags, RelocationKind, RelocationEncoding};
use object::write::*;

use cranelift_object::{ObjectBackend, ObjectBuilder, ObjectProduct};

use gimli::SectionId;

use crate::debuginfo::{DebugReloc, DebugRelocName};

pub(crate) trait WriteMetadata {
    fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>, is_like_osx: bool);
}

impl WriteMetadata for object::write::Object {
    fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>, _is_like_osx: bool) {
        let segment = self.segment_name(object::write::StandardSegment::Data).to_vec();
        let section_id = self.add_section(segment, b".rustc".to_vec(), object::SectionKind::Data);
        let offset = self.append_section_data(section_id, &data, 1);
        // For MachO and probably PE this is necessary to prevent the linker from throwing away the
        // .rustc section. For ELF this isn't necessary, but it also doesn't harm.
        self.add_symbol(object::write::Symbol {
            name: symbol_name.into_bytes(),
            value: offset,
            size: data.len() as u64,
            kind: object::SymbolKind::Data,
            scope: object::SymbolScope::Dynamic,
            weak: false,
            section: SymbolSection::Section(section_id),
            flags: SymbolFlags::None,
        });
    }
}

pub(crate) trait WriteDebugInfo {
    type SectionId: Copy;

    fn add_debug_section(&mut self, name: SectionId, data: Vec<u8>) -> Self::SectionId;
    fn add_debug_reloc(
        &mut self,
        section_map: &FxHashMap<SectionId, Self::SectionId>,
        from: &Self::SectionId,
        reloc: &DebugReloc,
    );
}

impl WriteDebugInfo for ObjectProduct {
    type SectionId = (object::write::SectionId, object::write::SymbolId);

    fn add_debug_section(
        &mut self,
        id: SectionId,
        data: Vec<u8>,
    ) -> (object::write::SectionId, object::write::SymbolId) {
        let name = if self.object.format() == object::BinaryFormat::MachO {
            id.name().replace('.', "__") // machO expects __debug_info instead of .debug_info
        } else {
            id.name().to_string()
        }.into_bytes();

        let segment = self.object.segment_name(StandardSegment::Debug).to_vec();
        let section_id = self.object.add_section(segment, name, SectionKind::Debug);
        self.object.section_mut(section_id).set_data(data, 1);
        let symbol_id = self.object.section_symbol(section_id);
        (section_id, symbol_id)
    }

    fn add_debug_reloc(
        &mut self,
        section_map: &FxHashMap<SectionId, Self::SectionId>,
        from: &Self::SectionId,
        reloc: &DebugReloc,
    ) {
        let (symbol, symbol_offset) = match reloc.name {
            DebugRelocName::Section(id) => {
                (section_map.get(&id).unwrap().1, 0)
            }
            DebugRelocName::Symbol(id) => {
                let symbol_id = self.function_symbol(FuncId::from_u32(id.try_into().unwrap()));
                self.object.symbol_section_and_offset(symbol_id).expect("Debug reloc for undef sym???")
            }
        };
        self.object.add_relocation(from.0, Relocation {
            offset: u64::from(reloc.offset),
            symbol,
            kind: RelocationKind::Absolute,
            encoding: RelocationEncoding::Generic,
            size: reloc.size * 8,
            addend: i64::try_from(symbol_offset).unwrap() + reloc.addend,
        }).unwrap();
    }
}

// FIXME remove once atomic instructions are implemented in Cranelift.
pub(crate) trait AddConstructor {
    fn add_constructor(&mut self, func_id: FuncId);
}

impl AddConstructor for ObjectProduct {
    fn add_constructor(&mut self, func_id: FuncId) {
        let symbol = self.function_symbol(func_id);
        let segment = self.object.segment_name(object::write::StandardSegment::Data);
        let init_array_section = self.object.add_section(segment.to_vec(), b".init_array".to_vec(), SectionKind::Data);
        self.object.append_section_data(
            init_array_section,
            &std::iter::repeat(0).take(8 /*FIXME pointer size*/).collect::<Vec<u8>>(),
            8,
        );
        self.object.add_relocation(init_array_section, object::write::Relocation {
            offset: 0,
            size: 64, // FIXME pointer size
            kind: RelocationKind::Absolute,
            encoding: RelocationEncoding::Generic,
            symbol,
            addend: 0,
        }).unwrap();
    }
}

pub(crate) trait Emit {
    fn emit(self) -> Vec<u8>;
}

impl Emit for ObjectProduct {
    fn emit(self) -> Vec<u8> {
        self.object.write().unwrap()
    }
}

pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object)) -> Vec<u8> {
    let triple = crate::build_isa(sess, true).triple().clone();

    let binary_format = match triple.binary_format {
        target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf,
        target_lexicon::BinaryFormat::Coff => object::BinaryFormat::Coff,
        target_lexicon::BinaryFormat::Macho => object::BinaryFormat::MachO,
        target_lexicon::BinaryFormat::Wasm => sess.fatal("binary format wasm is unsupported"),
        target_lexicon::BinaryFormat::Unknown => sess.fatal("binary format is unknown"),
    };
    let architecture = match triple.architecture {
        target_lexicon::Architecture::I386
        | target_lexicon::Architecture::I586
        | target_lexicon::Architecture::I686 => object::Architecture::I386,
        target_lexicon::Architecture::X86_64 => object::Architecture::X86_64,
        target_lexicon::Architecture::Arm(_) => object::Architecture::Arm,
        target_lexicon::Architecture::Aarch64(_) => object::Architecture::Aarch64,
        architecture => sess.fatal(&format!(
            "target architecture {:?} is unsupported",
            architecture,
        ))
    };
    let endian = match triple.endianness().unwrap() {
        target_lexicon::Endianness::Little => object::Endianness::Little,
        target_lexicon::Endianness::Big => object::Endianness::Big,
    };

    let mut metadata_object = object::write::Object::new(binary_format, architecture, endian);
    metadata_object.add_file_symbol(name.as_bytes().to_vec());
    f(&mut metadata_object);
    metadata_object.write().unwrap()
}

pub(crate) type Backend = impl cranelift_module::Backend<Product: AddConstructor + Emit + WriteDebugInfo>;

pub(crate) fn make_module(sess: &Session, name: String) -> Module<Backend> {
    let module: Module<ObjectBackend> = Module::new(
        ObjectBuilder::new(
            crate::build_isa(sess, true),
            name + ".o",
            cranelift_module::default_libcall_names(),
        ).unwrap(),
    );
    module
}
<|endoftext|>


<commit_before>extern crate postgres;
extern crate uuid;
extern crate stratis_shared as shared;

mod server;
mod distributor;
mod store;

pub use server::Server;
pub use shared::client::Client;
pub use store::Store;
<commit_msg>pub store,datastore<commit_after>extern crate postgres;
extern crate uuid;
extern crate stratis_shared as shared;

mod server;
mod distributor;
mod store;

pub use server::Server;
pub use shared::client::Client;
pub use store::{Store,DataStore};
<|endoftext|>


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

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),
        }
    }
}

impl Eq for AbsoluteEvent {}

impl PartialEq for AbsoluteEvent {
    fn eq(&self, other: &AbsoluteEvent) -> bool {
        self.time == other.time
    }

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

// 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,
                    // same type, so just use above res as Equal
                    _ => res
                }
            }
        }
    }
}

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

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

impl TrackBuilder {

    fn result(self) -> Track {
        let mut cur_time: u64 = 0;
        Track {
            copyright: self.copyright,
            name: self.name,
            events: self.events.into_iter().map(|bev| {
                let vtime = bev.time - cur_time;
                cur_time = vtime;
                TrackEvent {
                    vtime: vtime,
                    event: bev.event,
                }
            }).collect(),
        }
    }

    fn abs_time_from_delta(&self,delta: u64) -> u64 {
        match self.events.peek() {
            Some(e) => { e.time + delta }
            None => { delta }
        }
    }
}

/// 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: BinaryHeap::new()
        });
    }

    /// 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].events.push(event);
        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].events.push(event);
        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);
        self.tracks[track].events.push(AbsoluteEvent {
            time: time,
            event: Event::Midi(msg),
        });
    }

    /// 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.tracks[track].events.push(AbsoluteEvent {
            time: time,
            event: Event::Midi(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);
        self.tracks[track].events.push(AbsoluteEvent {
            time: time,
            event: Event::Meta(event),
        });
    }

    /// 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.tracks[track].events.push(AbsoluteEvent {
            time: time,
            event: Event::Meta(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,
        };
        self.tracks[track].events.push(bevent);
    }

    /// 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>Oops, need to sort heap for result, and get_time<commit_after>use std::cmp::Ordering;
use std::collections::BinaryHeap;

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),
        }
    }

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

impl Eq for AbsoluteEvent {}

impl PartialEq for AbsoluteEvent {
    fn eq(&self, other: &AbsoluteEvent) -> bool {
        self.time == other.time
    }

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

// 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,
                    // same type, so just use above res as Equal
                    _ => res
                }
            }
        }
    }
}

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

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

impl TrackBuilder {

    fn result(self) -> Track {
        let mut cur_time: u64 = 0;
        Track {
            copyright: self.copyright,
            name: self.name,
            events: self.events.into_sorted_vec().into_iter().map(|bev| {
                let vtime = bev.time - cur_time;
                cur_time = vtime;
                TrackEvent {
                    vtime: vtime,
                    event: bev.event,
                }
            }).collect(),
        }
    }

    fn abs_time_from_delta(&self,delta: u64) -> u64 {
        match self.events.peek() {
            Some(e) => { e.time + delta }
            None => { delta }
        }
    }
}

/// 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: BinaryHeap::new()
        });
    }

    /// 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].events.push(event);
        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].events.push(event);
        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);
        self.tracks[track].events.push(AbsoluteEvent {
            time: time,
            event: Event::Midi(msg),
        });
    }

    /// 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.tracks[track].events.push(AbsoluteEvent {
            time: time,
            event: Event::Midi(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);
        self.tracks[track].events.push(AbsoluteEvent {
            time: time,
            event: Event::Meta(event),
        });
    }

    /// 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.tracks[track].events.push(AbsoluteEvent {
            time: time,
            event: Event::Meta(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,
        };
        self.tracks[track].events.push(bevent);
    }

    /// 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 xml::Element;

use ::{Category, ElementUtils, Item, TextInput, ViaXml};

/// [RSS 2.0 Specification § Required channel elements]
/// (http://cyber.law.harvard.edu/rss/rss.html#requiredChannelElements)
///
/// ## Examples
///
/// ```
/// use rss::Channel;
///
/// let channel = Channel {
///     title: String::from("My Blog"),
///     link: String::from("http://myblog.com"),
///     description: String::from("My thoughts on life, the universe, and everything"),
///     items: vec![],
///     ..Default::default()
/// };
/// ```
#[derive(Default)]
pub struct Channel {
    pub title: String,
    pub link: String,
    pub description: String,
    pub items: Vec<Item>,
    pub language: Option<String>,
    pub copyright: Option<String>,
    pub managing_editor: Option<String>,
    pub web_master: Option<String>,
    pub pub_date: Option<String>,
    pub last_build_date: Option<String>,
    pub categories: Vec<Category>,
    pub generator: Option<String>,
    pub docs: Option<String>,
    // pub cloud:
    pub ttl: Option<String>,  // TODO: change this to Option<i32>?
    pub image: Option<String>,
    pub rating: Option<String>,
    pub text_input: Option<TextInput>,
    pub skip_hours: Option<String>,
    pub skip_days: Option<String>,
}

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

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

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

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

        if let Some(ref text_input) = self.text_input {
            channel.tag(text_input.to_xml());
        }

        channel.tag_with_optional_text("skipHours", &self.skip_hours);
        channel.tag_with_optional_text("skipDays", &self.skip_days);

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

        channel
    }

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

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

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

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

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

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

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

        let text_input = elem.get_child("textInput", None).map(|e| ViaXml::from_xml(e.clone()).unwrap());

        let skip_hours = elem.get_child("skip_hours", None).map(Element::content_str);
        let skip_days = elem.get_child("skip_days", None).map(Element::content_str);

        Ok(Channel {
            title: title,
            link: link,
            description: description,
            items: items,
            language: language,
            copyright: copyright,
            managing_editor: managing_editor,
            web_master: web_master,
            pub_date: pub_date,
            last_build_date: last_build_date,
            categories: categories,
            generator: generator,
            docs: docs,
            ttl: ttl,
            image: image,
            rating: rating,
            text_input: text_input,
            skip_hours: skip_hours,
            skip_days: skip_days,
        })
    }
}
<commit_msg>Update section heading for example<commit_after>use xml::Element;

use ::{Category, ElementUtils, Item, TextInput, ViaXml};

/// [RSS 2.0 Specification § Required channel elements]
/// (http://cyber.law.harvard.edu/rss/rss.html#requiredChannelElements)
///
/// # Examples
///
/// ```
/// use rss::Channel;
///
/// let channel = Channel {
///     title: String::from("My Blog"),
///     link: String::from("http://myblog.com"),
///     description: String::from("My thoughts on life, the universe, and everything"),
///     items: vec![],
///     ..Default::default()
/// };
/// ```
#[derive(Default)]
pub struct Channel {
    pub title: String,
    pub link: String,
    pub description: String,
    pub items: Vec<Item>,
    pub language: Option<String>,
    pub copyright: Option<String>,
    pub managing_editor: Option<String>,
    pub web_master: Option<String>,
    pub pub_date: Option<String>,
    pub last_build_date: Option<String>,
    pub categories: Vec<Category>,
    pub generator: Option<String>,
    pub docs: Option<String>,
    // pub cloud:
    pub ttl: Option<String>,  // TODO: change this to Option<i32>?
    pub image: Option<String>,
    pub rating: Option<String>,
    pub text_input: Option<TextInput>,
    pub skip_hours: Option<String>,
    pub skip_days: Option<String>,
}

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

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

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

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

        if let Some(ref text_input) = self.text_input {
            channel.tag(text_input.to_xml());
        }

        channel.tag_with_optional_text("skipHours", &self.skip_hours);
        channel.tag_with_optional_text("skipDays", &self.skip_days);

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

        channel
    }

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

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

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

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

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

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

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

        let text_input = elem.get_child("textInput", None).map(|e| ViaXml::from_xml(e.clone()).unwrap());

        let skip_hours = elem.get_child("skip_hours", None).map(Element::content_str);
        let skip_days = elem.get_child("skip_days", None).map(Element::content_str);

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


<commit_before>/*
Tristen Horton
tristen@tristenhorton.com
2017-04-03

Module for basic channel data
Its possible to be in multiple channels at once in Twitch, so we want a simple way
to represent multiple channels at once - we'll be using this module and structure
for that.
*/

use message::Message;
use std::str::Split;

pub struct Channel {
	name: String,
	state: ChannelState
}

impl Channel {
	pub fn name(&self) -> &String {
		&self.name
	}

	pub fn state(&self) -> &ChannelState {
		&self.state
	}
}

pub struct ChannelState {

	r9k_mode: bool,
	sub_only: bool,
	slow_mode: bool,
	emote_only: bool,

	broadcaster_lang: String,
}

impl ChannelState {
	pub fn from(irc: String) -> ChannelState {

	// typical irc message:
	// broadcaster-lang=;emote-only=0;r9k=0;slow=0;subs-only=1 :tmi.twitch.tv ROOMSTATE #phxvyper

		let properties = irc.split_whitespace().nth(0);
		let mut r9k = false;
		let mut sub = false;
		let mut slow = false;
		let mut emote = false;
		let mut lang = String::from("");
		let mut channel = String::from("");

		for prop in properties.unwrap_or("").split(";") {
			let mut prop_split = prop.split("=");
			match prop_split.nth(0).unwrap_or("") {

				"broadcaster-lang" => lang = prop_split.nth(1).unwrap_or("").to_string(),

				"emote-only" => emote = bool_from_nth_str(&mut prop_split, 1),
				"r9k" => r9k = bool_from_nth_str(&mut prop_split, 1),
				"slow" => slow = bool_from_nth_str(&mut prop_split, 1),
				"subs-only" => sub = bool_from_nth_str(&mut prop_split, 1),

				_ => println!("[twitch-rs] Unnacounted for irc property: {:?}", prop),
			}
		}

		channel = irc.to_string().split("#").nth(1).unwrap_or("").to_string();

		ChannelState {
			r9k_mode: r9k,
			sub_only: sub,
			slow_mode: slow,
			emote_only: emote,
			broadcaster_lang: lang,
		}
	}
}

fn bool_from_nth_str(split: &mut Split<&str>, nth: usize) -> bool {
	split.nth(nth)
		.unwrap_or("false")
		.parse::<bool>()
		.unwrap_or(false)
}
<commit_msg>replaced macro with error handling function<commit_after>/*
Tristen Horton
tristen@tristenhorton.com
2017-04-03

Module for basic channel data
Its possible to be in multiple channels at once in Twitch, so we want a simple way
to represent multiple channels at once - we'll be using this module and structure
for that.
*/

use message::ChatMessage;
use std::str::Split;

pub struct Channel {
	name: String,
	state: ChannelState
}

impl Channel {
	pub fn from(name: String, state: ChannelState) -> Channel {
		Channel {
			name: name,
			state: state,
		}
	}

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

	pub fn state(&self) -> &ChannelState {
		&self.state
	}
}

pub struct ChannelState {

	r9k_mode: bool,
	sub_only: bool,
	slow_mode: bool,
	emote_only: bool,

	channel: String,
	broadcaster_lang: String,
}

impl ChannelState {
	pub fn from(irc: String) -> ChannelState {

	// typical irc message:
	// broadcaster-lang=;emote-only=0;r9k=0;slow=0;subs-only=1 :tmi.twitch.tv ROOMSTATE #phxvyper

		let properties = irc.split_whitespace().nth(0);
		let mut r9k = false;
		let mut sub = false;
		let mut slow = false;
		let mut emote = false;
		let mut lang = String::from("");
		let mut channel;

		for prop in properties.unwrap_or("").split(";") {
			let mut prop_split = prop.split("=");
			match prop_split.nth(0).unwrap_or("") {

				"broadcaster-lang" => lang = prop_split.nth(1).unwrap_or("").to_string(),

				"emote-only" => emote = bool_from_nth_str(&mut prop_split, 1),
				"r9k" => r9k = bool_from_nth_str(&mut prop_split, 1),
				"slow" => slow = bool_from_nth_str(&mut prop_split, 1),
				"subs-only" => sub = bool_from_nth_str(&mut prop_split, 1),

				_ => println!("[twitch-rs] Unnacounted for irc property: {:?}", prop),
			}
		}

		channel = irc.to_string().split("#").nth(1).unwrap_or("").to_string();

		ChannelState {
			r9k_mode: r9k,
			sub_only: sub,
			slow_mode: slow,
			emote_only: emote,
			channel: channel,
			broadcaster_lang: lang,
		}
	}
}

fn bool_from_nth_str(split: &mut Split<&str>, nth: usize) -> bool {
	split.nth(nth)
		.unwrap_or("false")
		.parse::<bool>()
		.unwrap_or(false)
}
<|endoftext|>


<commit_before>// Copyright 2013 The color-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Color channel conversions and utility methods

pub trait Channel: Primitive + Orderable {
    priv fn from<T:Channel>(chan: T) -> Self;
    pub fn to_channel<T:Channel>(&self) -> T;
    pub fn to_channel_u8(&self)  -> u8;
    pub fn to_channel_u16(&self) -> u16;
    pub fn to_channel_f32(&self) -> f32;
    pub fn to_channel_f64(&self) -> f64;

    pub fn invert_channel(&self) -> Self;
}

impl Channel for u8 {
    #[inline] priv fn from<T:Channel>(chan: T) -> u8 { chan.to_channel_u8() }
    #[inlune] pub fn to_channel<T:Channel>(&self) -> T { Channel::from(*self) }
    #[inline] pub fn to_channel_u8(&self)  -> u8  { (*self) }
    #[inline] pub fn to_channel_u16(&self) -> u16 { (*self as u16 << 8) | (*self) as u16 }
    #[inline] pub fn to_channel_f32(&self) -> f32 { (*self as f32) / (0xFF as f32) }
    #[inline] pub fn to_channel_f64(&self) -> f64 { (*self as f64) / (0xFF as f64) }

    #[inline] pub fn invert_channel(&self) -> u8 { !(*self) }
}

impl Channel for u16 {
    #[inline] priv fn from<T:Channel>(chan: T) -> u16 { chan.to_channel_u16() }
    #[inlune] pub fn to_channel<T:Channel>(&self) -> T { Channel::from(*self) }
    #[inline] pub fn to_channel_u8(&self)  -> u8  { (*self >> 8) as u8 }
    #[inline] pub fn to_channel_u16(&self) -> u16 { (*self) }
    #[inline] pub fn to_channel_f32(&self) -> f32 { (*self) / 0xFFFF as f32 }
    #[inline] pub fn to_channel_f64(&self) -> f64 { (*self) / 0xFFFF as f64 }

    #[inline] pub fn invert_channel(&self) -> u16 { !(*self) }
}

impl Channel for f32 {
    #[inline] priv fn from<T:Channel>(chan: T) -> f32 { chan.to_channel_f32() }
    #[inlune] pub fn to_channel<T:Channel>(&self) -> T { Channel::from(*self) }
    #[inline] pub fn to_channel_u8(&self)  -> u8  { (*self) * (0xFF as f32) as u8 }
    #[inline] pub fn to_channel_u16(&self) -> u16 { (*self) * (0xFFFF as f32) as u16 }
    #[inline] pub fn to_channel_f32(&self) -> f32 { (*self) }
    #[inline] pub fn to_channel_f64(&self) -> f64 { (*self) as f64 }

    #[inline] pub fn invert_channel(&self) -> f32 { 1.0 - (*self) }
}

impl Channel for f64 {
    #[inline] priv fn from<T:Channel>(chan: T) -> f64 { chan.to_channel_f64() }
    #[inlune] pub fn to_channel<T:Channel>(&self) -> T { Channel::from(*self) }
    #[inline] pub fn to_channel_u8(&self)  -> u8  { (*self) * (0xFF as f64) as u8 }
    #[inline] pub fn to_channel_u16(&self) -> u16 { (*self) * (0xFFFF as f64) as u16 }
    #[inline] pub fn to_channel_f32(&self) -> f32 { (*self) as f32 }
    #[inline] pub fn to_channel_f64(&self) -> f64 { (*self) }

    #[inline] pub fn invert_channel(&self) -> f64 { 1.0 - (*self) }
}

pub trait FloatChannel: Float + Channel {
    pub fn normalize_channel(&self) -> Self;
    pub fn normalize_degrees(&self) -> Self;
    pub fn invert_degrees(&self) -> Self;
}

impl FloatChannel for f32 {
    #[inline]
    pub fn normalize_channel(&self) -> f32 {
        self.clamp(&0.0, &1.0)
    }

    #[inline]
    pub fn normalize_degrees(&self) -> f32 {
        if (*self) < 0.0 {
            (*self + 360.0) % 360.0
        } else {
            *self % 360.0
        }
    }

    #[inline]
    pub fn invert_degrees(&self) -> f32 {
        (*self + 180.0).normalize_degrees()
    }
}

impl FloatChannel for f64 {
    #[inline]
    pub fn normalize_channel(&self) -> f64 {
        self.clamp(&0.0, &1.0)
    }

    #[inline]
    pub fn normalize_degrees(&self) -> f64 {
        if (*self) < 0.0 {
            (*self + 360.0) % 360.0
        } else {
            *self % 360.0
        }
    }

    #[inline]
    pub fn invert_degrees(&self) -> f64 {
        (*self + 180.0).normalize_degrees()
    }
}

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

    #[test]
    fn test_to_channel_u8() {
        assert_eq!(0x00_u8.to_channel_u8(), 0x00_u8);
        assert_eq!(0x30_u8.to_channel_u8(), 0x30_u8);
        assert_eq!(0x66_u8.to_channel_u8(), 0x66_u8);
        assert_eq!(0xA0_u8.to_channel_u8(), 0xA0_u8);
        assert_eq!(0xFF_u8.to_channel_u8(), 0xFF_u8);

        assert_eq!(0x00_u8.to_channel_u16(), 0x0000_u16);
        assert_eq!(0x30_u8.to_channel_u16(), 0x3030_u16);
        assert_eq!(0x66_u8.to_channel_u16(), 0x6666_u16);
        assert_eq!(0xA0_u8.to_channel_u16(), 0xA0A0_u16);
        assert_eq!(0xFF_u8.to_channel_u16(), 0xFFFF_u16);

        assert_eq!(0x00_u8.to_channel_f32(), 0f32);
        assert_eq!(0xFF_u8.to_channel_f32(), 1f32);

        assert_eq!(0x00_u8.to_channel_f64(), 0f64);
        assert_eq!(0xFF_u8.to_channel_f64(), 1f64);
    }

    #[test]
    fn test_invert_channel_u8() {
        assert_eq!(0x00_u8.invert_channel(), 0xFF_u8);
        assert_eq!(0x66_u8.invert_channel(), 0x99_u8);
        assert_eq!(0xFF_u8.invert_channel(), 0x00_u8);
    }

    #[test]
    fn test_to_channel_u16() {
        assert_eq!(0x0000_u16.to_channel_u8(), 0x00_u8);
        assert_eq!(0x3300_u16.to_channel_u8(), 0x33_u8);
        assert_eq!(0x6666_u16.to_channel_u8(), 0x66_u8);
        assert_eq!(0xAA00_u16.to_channel_u8(), 0xAA_u8);
        assert_eq!(0xFFFF_u16.to_channel_u8(), 0xFF_u8);

        assert_eq!(0x0000_u16.to_channel_u16(), 0x0000_u16);
        assert_eq!(0x3300_u16.to_channel_u16(), 0x3300_u16);
        assert_eq!(0x6666_u16.to_channel_u16(), 0x6666_u16);
        assert_eq!(0xAA00_u16.to_channel_u16(), 0xAA00_u16);
        assert_eq!(0xFFFF_u16.to_channel_u16(), 0xFFFF_u16);

        assert_eq!(0x0000_u16.to_channel_f32(), 0f32);
        assert_eq!(0xFFFF_u16.to_channel_f32(), 1f32);

        assert_eq!(0x0000_u16.to_channel_f64(), 0f64);
        assert_eq!(0xFFFF_u16.to_channel_f64(), 1f64);
    }

    #[test]
    fn test_invert_channel_u16() {
        assert_eq!(0x0000_u16.invert_channel(), 0xFFFF_u16);
        assert_eq!(0x6666_u16.invert_channel(), 0x9999_u16);
        assert_eq!(0xFFFF_u16.invert_channel(), 0x0000_u16);
    }

    #[test]
    fn test_to_channel_f32() {
        assert_eq!(0.00f32.to_channel_u8(), 0x00);
        assert_eq!(0.25f32.to_channel_u8(), 0x3F);
        assert_eq!(0.50f32.to_channel_u8(), 0x7F);
        assert_eq!(0.75f32.to_channel_u8(), 0xBF);
        assert_eq!(1.00f32.to_channel_u8(), 0xFF);

        assert_eq!(0.00f32.to_channel_u16(), 0x0000);
        assert_eq!(0.25f32.to_channel_u16(), 0x3FFF);
        assert_eq!(0.50f32.to_channel_u16(), 0x7FFF);
        assert_eq!(0.75f32.to_channel_u16(), 0xBFFF);
        assert_eq!(1.00f32.to_channel_u16(), 0xFFFF);

        assert_eq!(0.00f32.to_channel_f32(), 0.00f32);
        assert_eq!(1.00f32.to_channel_f32(), 1.00f32);

        assert_eq!(0.00f32.to_channel_f64(), 0.00f64);
        assert_eq!(1.00f32.to_channel_f64(), 1.00f64);
    }

    #[test]
    fn test_invert_channel_f32() {
        assert_eq!(0.00f32.invert_channel(), 1.00f32);
        assert_eq!(0.50f32.invert_channel(), 0.50f32);
        assert_eq!(1.00f32.invert_channel(), 0.00f32);
    }

    #[test]
    fn test_invert_degrees_f32() {
        assert_eq!(  0.00f32.invert_degrees(), 180.00f32);
        assert_eq!( 45.00f32.invert_degrees(), 225.00f32);
        assert_eq!( 90.00f32.invert_degrees(), 270.00f32);
        assert_eq!(360.00f32.invert_degrees(), 180.00f32);
        assert_eq!(720.00f32.invert_degrees(), 180.00f32);
    }

    #[test]
    fn test_to_channel_f64() {
        assert_eq!(0.00f64.to_channel_u8(), 0x00);
        assert_eq!(0.25f64.to_channel_u8(), 0x3F);
        assert_eq!(0.50f64.to_channel_u8(), 0x7F);
        assert_eq!(0.75f64.to_channel_u8(), 0xBF);
        assert_eq!(1.00f64.to_channel_u8(), 0xFF);

        assert_eq!(0.00f64.to_channel_u16(), 0x0000);
        assert_eq!(0.25f64.to_channel_u16(), 0x3FFF);
        assert_eq!(0.50f64.to_channel_u16(), 0x7FFF);
        assert_eq!(0.75f64.to_channel_u16(), 0xBFFF);
        assert_eq!(1.00f64.to_channel_u16(), 0xFFFF);

        assert_eq!(0.00f64.to_channel_f32(), 0.00f32);
        assert_eq!(1.00f64.to_channel_f32(), 1.00f32);

        assert_eq!(0.00f64.to_channel_f64(), 0.00f64);
        assert_eq!(1.00f64.to_channel_f64(), 1.00f64);
    }

    #[test]
    fn test_invert_channel_f64() {
        assert_eq!(0.00f64.invert_channel(), 1.00f64);
        assert_eq!(0.50f64.invert_channel(), 0.50f64);
        assert_eq!(1.00f64.invert_channel(), 0.00f64);
    }

    #[test]
    fn test_invert_degrees_f64() {
        assert_eq!(  0.00f64.invert_degrees(), 180.00f64);
        assert_eq!( 45.00f64.invert_degrees(), 225.00f64);
        assert_eq!( 90.00f64.invert_degrees(), 270.00f64);
        assert_eq!(360.00f64.invert_degrees(), 180.00f64);
        assert_eq!(720.00f64.invert_degrees(), 180.00f64);
    }
}
<commit_msg>Use default methods<commit_after>// Copyright 2013 The color-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Color channel conversions and utility methods

use std::num::cast;

pub trait Channel: Clone + Primitive + Orderable {
    priv fn from<T:Channel>(chan: T) -> Self;
    pub fn to_channel<T:Channel>(&self) -> T { Channel::from(self.clone()) }
    pub fn to_channel_u8(&self)  -> u8;
    pub fn to_channel_u16(&self) -> u16;
    pub fn to_channel_f32(&self) -> f32;
    pub fn to_channel_f64(&self) -> f64;

    pub fn invert_channel(&self) -> Self;
}

impl Channel for u8 {
    #[inline] priv fn from<T:Channel>(chan: T) -> u8 { chan.to_channel_u8() }
    #[inline] pub fn to_channel_u8(&self)  -> u8  { (*self) }
    #[inline] pub fn to_channel_u16(&self) -> u16 { (*self as u16 << 8) | (*self) as u16 }
    #[inline] pub fn to_channel_f32(&self) -> f32 { (*self as f32) / (0xFF as f32) }
    #[inline] pub fn to_channel_f64(&self) -> f64 { (*self as f64) / (0xFF as f64) }

    #[inline] pub fn invert_channel(&self) -> u8 { !(*self) }
}

impl Channel for u16 {
    #[inline] priv fn from<T:Channel>(chan: T) -> u16 { chan.to_channel_u16() }
    #[inline] pub fn to_channel_u8(&self)  -> u8  { (*self >> 8) as u8 }
    #[inline] pub fn to_channel_u16(&self) -> u16 { (*self) }
    #[inline] pub fn to_channel_f32(&self) -> f32 { (*self) / 0xFFFF as f32 }
    #[inline] pub fn to_channel_f64(&self) -> f64 { (*self) / 0xFFFF as f64 }

    #[inline] pub fn invert_channel(&self) -> u16 { !(*self) }
}

impl Channel for f32 {
    #[inline] priv fn from<T:Channel>(chan: T) -> f32 { chan.to_channel_f32() }
    #[inline] pub fn to_channel_u8(&self)  -> u8  { (*self) * (0xFF as f32) as u8 }
    #[inline] pub fn to_channel_u16(&self) -> u16 { (*self) * (0xFFFF as f32) as u16 }
    #[inline] pub fn to_channel_f32(&self) -> f32 { (*self) }
    #[inline] pub fn to_channel_f64(&self) -> f64 { (*self) as f64 }

    #[inline] pub fn invert_channel(&self) -> f32 { 1.0 - (*self) }
}

impl Channel for f64 {
    #[inline] priv fn from<T:Channel>(chan: T) -> f64 { chan.to_channel_f64() }
    #[inline] pub fn to_channel_u8(&self)  -> u8  { (*self) * (0xFF as f64) as u8 }
    #[inline] pub fn to_channel_u16(&self) -> u16 { (*self) * (0xFFFF as f64) as u16 }
    #[inline] pub fn to_channel_f32(&self) -> f32 { (*self) as f32 }
    #[inline] pub fn to_channel_f64(&self) -> f64 { (*self) }

    #[inline] pub fn invert_channel(&self) -> f64 { 1.0 - (*self) }
}

pub trait FloatChannel: Float + Channel {
    #[inline]
    pub fn normalize_channel(&self) -> Self {
        self.clamp(&cast(0.0), &cast(1.0))
    }

    #[inline]
    pub fn normalize_degrees(&self) -> Self {
        if (*self) < cast(0.0) {
            (*self + cast(360.0)) % cast(360.0)
        } else {
            *self % cast(360.0)
        }
    }

    #[inline]
    pub fn invert_degrees(&self) -> Self {
        (*self + cast(180.0)).normalize_degrees()
    }
}

impl FloatChannel for f32;
impl FloatChannel for f64;

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

    #[test]
    fn test_to_channel_u8() {
        assert_eq!(0x00_u8.to_channel_u8(), 0x00_u8);
        assert_eq!(0x30_u8.to_channel_u8(), 0x30_u8);
        assert_eq!(0x66_u8.to_channel_u8(), 0x66_u8);
        assert_eq!(0xA0_u8.to_channel_u8(), 0xA0_u8);
        assert_eq!(0xFF_u8.to_channel_u8(), 0xFF_u8);

        assert_eq!(0x00_u8.to_channel_u16(), 0x0000_u16);
        assert_eq!(0x30_u8.to_channel_u16(), 0x3030_u16);
        assert_eq!(0x66_u8.to_channel_u16(), 0x6666_u16);
        assert_eq!(0xA0_u8.to_channel_u16(), 0xA0A0_u16);
        assert_eq!(0xFF_u8.to_channel_u16(), 0xFFFF_u16);

        assert_eq!(0x00_u8.to_channel_f32(), 0f32);
        assert_eq!(0xFF_u8.to_channel_f32(), 1f32);

        assert_eq!(0x00_u8.to_channel_f64(), 0f64);
        assert_eq!(0xFF_u8.to_channel_f64(), 1f64);
    }

    #[test]
    fn test_invert_channel_u8() {
        assert_eq!(0x00_u8.invert_channel(), 0xFF_u8);
        assert_eq!(0x66_u8.invert_channel(), 0x99_u8);
        assert_eq!(0xFF_u8.invert_channel(), 0x00_u8);
    }

    #[test]
    fn test_to_channel_u16() {
        assert_eq!(0x0000_u16.to_channel_u8(), 0x00_u8);
        assert_eq!(0x3300_u16.to_channel_u8(), 0x33_u8);
        assert_eq!(0x6666_u16.to_channel_u8(), 0x66_u8);
        assert_eq!(0xAA00_u16.to_channel_u8(), 0xAA_u8);
        assert_eq!(0xFFFF_u16.to_channel_u8(), 0xFF_u8);

        assert_eq!(0x0000_u16.to_channel_u16(), 0x0000_u16);
        assert_eq!(0x3300_u16.to_channel_u16(), 0x3300_u16);
        assert_eq!(0x6666_u16.to_channel_u16(), 0x6666_u16);
        assert_eq!(0xAA00_u16.to_channel_u16(), 0xAA00_u16);
        assert_eq!(0xFFFF_u16.to_channel_u16(), 0xFFFF_u16);

        assert_eq!(0x0000_u16.to_channel_f32(), 0f32);
        assert_eq!(0xFFFF_u16.to_channel_f32(), 1f32);

        assert_eq!(0x0000_u16.to_channel_f64(), 0f64);
        assert_eq!(0xFFFF_u16.to_channel_f64(), 1f64);
    }

    #[test]
    fn test_invert_channel_u16() {
        assert_eq!(0x0000_u16.invert_channel(), 0xFFFF_u16);
        assert_eq!(0x6666_u16.invert_channel(), 0x9999_u16);
        assert_eq!(0xFFFF_u16.invert_channel(), 0x0000_u16);
    }

    #[test]
    fn test_to_channel_f32() {
        assert_eq!(0.00f32.to_channel_u8(), 0x00);
        assert_eq!(0.25f32.to_channel_u8(), 0x3F);
        assert_eq!(0.50f32.to_channel_u8(), 0x7F);
        assert_eq!(0.75f32.to_channel_u8(), 0xBF);
        assert_eq!(1.00f32.to_channel_u8(), 0xFF);

        assert_eq!(0.00f32.to_channel_u16(), 0x0000);
        assert_eq!(0.25f32.to_channel_u16(), 0x3FFF);
        assert_eq!(0.50f32.to_channel_u16(), 0x7FFF);
        assert_eq!(0.75f32.to_channel_u16(), 0xBFFF);
        assert_eq!(1.00f32.to_channel_u16(), 0xFFFF);

        assert_eq!(0.00f32.to_channel_f32(), 0.00f32);
        assert_eq!(1.00f32.to_channel_f32(), 1.00f32);

        assert_eq!(0.00f32.to_channel_f64(), 0.00f64);
        assert_eq!(1.00f32.to_channel_f64(), 1.00f64);
    }

    #[test]
    fn test_invert_channel_f32() {
        assert_eq!(0.00f32.invert_channel(), 1.00f32);
        assert_eq!(0.50f32.invert_channel(), 0.50f32);
        assert_eq!(1.00f32.invert_channel(), 0.00f32);
    }

    #[test]
    fn test_invert_degrees_f32() {
        assert_eq!(  0.00f32.invert_degrees(), 180.00f32);
        assert_eq!( 45.00f32.invert_degrees(), 225.00f32);
        assert_eq!( 90.00f32.invert_degrees(), 270.00f32);
        assert_eq!(360.00f32.invert_degrees(), 180.00f32);
        assert_eq!(720.00f32.invert_degrees(), 180.00f32);
    }

    #[test]
    fn test_to_channel_f64() {
        assert_eq!(0.00f64.to_channel_u8(), 0x00);
        assert_eq!(0.25f64.to_channel_u8(), 0x3F);
        assert_eq!(0.50f64.to_channel_u8(), 0x7F);
        assert_eq!(0.75f64.to_channel_u8(), 0xBF);
        assert_eq!(1.00f64.to_channel_u8(), 0xFF);

        assert_eq!(0.00f64.to_channel_u16(), 0x0000);
        assert_eq!(0.25f64.to_channel_u16(), 0x3FFF);
        assert_eq!(0.50f64.to_channel_u16(), 0x7FFF);
        assert_eq!(0.75f64.to_channel_u16(), 0xBFFF);
        assert_eq!(1.00f64.to_channel_u16(), 0xFFFF);

        assert_eq!(0.00f64.to_channel_f32(), 0.00f32);
        assert_eq!(1.00f64.to_channel_f32(), 1.00f32);

        assert_eq!(0.00f64.to_channel_f64(), 0.00f64);
        assert_eq!(1.00f64.to_channel_f64(), 1.00f64);
    }

    #[test]
    fn test_invert_channel_f64() {
        assert_eq!(0.00f64.invert_channel(), 1.00f64);
        assert_eq!(0.50f64.invert_channel(), 0.50f64);
        assert_eq!(1.00f64.invert_channel(), 0.00f64);
    }

    #[test]
    fn test_invert_degrees_f64() {
        assert_eq!(  0.00f64.invert_degrees(), 180.00f64);
        assert_eq!( 45.00f64.invert_degrees(), 225.00f64);
        assert_eq!( 90.00f64.invert_degrees(), 270.00f64);
        assert_eq!(360.00f64.invert_degrees(), 180.00f64);
        assert_eq!(720.00f64.invert_degrees(), 180.00f64);
    }
}
<|endoftext|>


<commit_before>//! State machine compiler.

use parse;
use parse::{Expr, Greedy, NonGreedy};
use vm::{Program, Inst, Jump, Range, Save};

/// Compile an AST into a `Program`.
pub fn compile(e: &Expr) -> Program {
    let mut p = Builder::new();
    compile_expr(&mut p, e);
    p.reify()
}

struct Builder {
    program: Program,
    n_regs: uint
}

impl Builder {
    fn new() -> Builder {
        Builder {
            program: ~[],
            n_regs: 0
        }
    }

    fn len(&self) -> uint {
        self.program.len()
    }

    fn push(&mut self, inst: Inst) {
        self.program.push(inst);
    }

    fn push_jump(&mut self) {
        self.program.push(Jump(~[]));
    }

    fn jumps<'a>(&'a mut self, index: uint) -> &'a mut ~[uint] {
        match self.program[index] {
            Jump(ref mut exits) => exits,
            _ => fail!("something bad happened; it's really bad")
        }
    }

    fn allocate(&mut self) -> uint {
        let reg = self.n_regs;
        self.n_regs += 1;
        reg
    }

    fn reify(self) -> Program {
        let Builder { program, .. } = self;
        program
    }
}

macro_rules! record(
    () => (
        p.len()
    );
    ($list:expr) => (
        $list.push(p.len())
    )
)

fn compile_expr(p: &mut Builder, e: &Expr) {
    match *e {
        parse::Empty => (),
        parse::Range(lo, hi) => p.push(Range(lo, hi)),
        parse::Concatenate(ref inners) => {
            // Execute all children, one after the other
            for inner in inners.iter() {
                compile_expr(p, inner);
            }
        },
        parse::Alternate(ref inners) => {
            let fork = record!(); p.push_jump();

            let mut heads = ~[];
            let mut tails = ~[];
            for (i, inner) in inners.iter().enumerate() {
                record!(heads); compile_expr(p, inner);
                if i != inners.len() - 1 {
                    record!(tails); p.push_jump();
                }
            }

            p.jumps(fork).push_all_move(heads);

            let end = p.len();
            for tail in tails.move_iter() {
                p.jumps(tail).push(end);
            }
        },
        parse::Repeat(ref inner, min, max, greedy) => compile_repeat(p, *inner, min, max, greedy),
        parse::Capture(ref inner) => {
            let open_reg = p.allocate(); let close_reg = p.allocate();
            p.push(Save(open_reg));
            compile_expr(p, *inner);
            p.push(Save(close_reg));
        }
    }
}

fn compile_repeat(p: &mut Builder, inner: &Expr, min: u32, max: Option<u32>, greedy: Greedy) {
    match (min, max) {
        (_, Some(max_)) => {
            // Compile `min` repetitions
            for _ in range(0, min) {
                compile_expr(p, inner);
            }

            // Compile `max - min` optional repetitions
            let mut forks = ~[];
            for _ in range(min, max_) {
                record!(forks); p.push_jump();
                compile_expr(p, inner);
            }

            let end = p.len();
            for fork in forks.move_iter() {
                draw_fork(p.jumps(fork), 1+fork, end, greedy);
            }
        },
        (0, None) => {
            let fork = record!(); p.push_jump();
            compile_repeat(p, inner, 1, None, greedy);
            let end = p.len();
            draw_fork(p.jumps(fork), 1+fork, end, greedy);
        },
        (_, None) => {
            for _ in range(0, min-1) {
                compile_expr(p, inner);
            }

            // Draw a loop around the last repetition
            let start = record!();
            compile_expr(p, inner);
            let loopy = record!(); p.push_jump();
            draw_fork(p.jumps(loopy), start, 1+loopy, greedy);
        }
    }
}

fn draw_fork(jumps: &mut ~[uint], persist: uint, escape: uint, greedy: Greedy) {
    match greedy {
        NonGreedy => { jumps.push(escape); jumps.push(persist); },
        Greedy    => { jumps.push(persist); jumps.push(escape); }
    }
}
<commit_msg>Make register allocation more safe<commit_after>//! State machine compiler.

use parse;
use parse::{Expr, Greedy, NonGreedy};
use vm::{Program, Inst, Jump, Range, Save};

/// Compile an AST into a `Program`.
pub fn compile(e: &Expr) -> Program {
    let mut p = Builder::new();
    compile_expr(&mut p, e);
    p.reify()
}

struct Builder {
    program: Program,
    n_regs: uint
}

impl Builder {
    fn new() -> Builder {
        Builder {
            program: ~[],
            n_regs: 0
        }
    }

    fn len(&self) -> uint {
        self.program.len()
    }

    fn push(&mut self, inst: Inst) {
        self.program.push(inst);
    }

    fn push_jump(&mut self) {
        self.program.push(Jump(~[]));
    }

    fn jumps<'a>(&'a mut self, index: uint) -> &'a mut ~[uint] {
        match self.program[index] {
            Jump(ref mut exits) => exits,
            _ => fail!("something bad happened; it's really bad")
        }
    }

    fn allocate(&mut self) -> (uint, uint) {
        let reg = self.n_regs;
        self.n_regs = 2u.checked_add(&self.n_regs).expect("too many capturing groups");
        (reg, 1 + reg)
    }

    fn reify(self) -> Program {
        let Builder { program, .. } = self;
        program
    }
}

macro_rules! record(
    () => (
        p.len()
    );
    ($list:expr) => (
        $list.push(p.len())
    )
)

fn compile_expr(p: &mut Builder, e: &Expr) {
    match *e {
        parse::Empty => (),
        parse::Range(lo, hi) => p.push(Range(lo, hi)),
        parse::Concatenate(ref inners) => {
            // Execute all children, one after the other
            for inner in inners.iter() {
                compile_expr(p, inner);
            }
        },
        parse::Alternate(ref inners) => {
            let fork = record!(); p.push_jump();

            let mut heads = ~[];
            let mut tails = ~[];
            for (i, inner) in inners.iter().enumerate() {
                record!(heads); compile_expr(p, inner);
                if i != inners.len() - 1 {
                    record!(tails); p.push_jump();
                }
            }

            p.jumps(fork).push_all_move(heads);

            let end = p.len();
            for tail in tails.move_iter() {
                p.jumps(tail).push(end);
            }
        },
        parse::Repeat(ref inner, min, max, greedy) => compile_repeat(p, *inner, min, max, greedy),
        parse::Capture(ref inner) => {
            let (open_reg, close_reg) = p.allocate();
            p.push(Save(open_reg));
            compile_expr(p, *inner);
            p.push(Save(close_reg));
        }
    }
}

fn compile_repeat(p: &mut Builder, inner: &Expr, min: u32, max: Option<u32>, greedy: Greedy) {
    match (min, max) {
        (_, Some(max_)) => {
            // Compile `min` repetitions
            for _ in range(0, min) {
                compile_expr(p, inner);
            }

            // Compile `max - min` optional repetitions
            let mut forks = ~[];
            for _ in range(min, max_) {
                record!(forks); p.push_jump();
                compile_expr(p, inner);
            }

            let end = p.len();
            for fork in forks.move_iter() {
                draw_fork(p.jumps(fork), 1+fork, end, greedy);
            }
        },
        (0, None) => {
            let fork = record!(); p.push_jump();
            compile_repeat(p, inner, 1, None, greedy);
            let end = p.len();
            draw_fork(p.jumps(fork), 1+fork, end, greedy);
        },
        (_, None) => {
            for _ in range(0, min-1) {
                compile_expr(p, inner);
            }

            // Draw a loop around the last repetition
            let start = record!();
            compile_expr(p, inner);
            let loopy = record!(); p.push_jump();
            draw_fork(p.jumps(loopy), start, 1+loopy, greedy);
        }
    }
}

fn draw_fork(jumps: &mut ~[uint], persist: uint, escape: uint, greedy: Greedy) {
    match greedy {
        NonGreedy => { jumps.push(escape); jumps.push(persist); },
        Greedy    => { jumps.push(persist); jumps.push(escape); }
    }
}
<|endoftext|>


<commit_before>//! Switch control packets.

use byteorder::BigEndian;
use byteorder::ByteOrder;

#[derive(Clone)]
#[derive(Debug)]
#[derive(Eq)]
#[derive(PartialEq)]
pub enum ErrorType {
    /// No error, everything is ok.
    None,
    /// The switch label was malformed.
    MalformedAddress,
    /// Packet dropped because link is congested.
    Flood,
    /// Packet dropped because node has oversent its limit.
    LinkLimitExceeded,
    /// Message too big to send.
    OversizeMessage,
    /// Message smaller than expected headers.
    UndersizeMessage,
    /// Authentication failed.
    Authentication,
    /// Header is invalid or checksum failed.
    Invalid,
    /// Message could not be sent to its destination through no fault of the sender.
    Undeliverable,
    /// The route enters and leaves through the same interface in one switch.
    LoopRoute,
    /// The switch is unable to represent the return path.
    ReturnPathInvalid,
}

impl ErrorType {
    fn new(type_number: u32) -> Option<ErrorType> {
        match type_number {
            0 => Some(ErrorType::None),
            1 => Some(ErrorType::MalformedAddress),
            2 => Some(ErrorType::Flood),
            3 => Some(ErrorType::LinkLimitExceeded),
            4 => Some(ErrorType::OversizeMessage),
            5 => Some(ErrorType::UndersizeMessage),
            6 => Some(ErrorType::Authentication),
            7 => Some(ErrorType::Invalid),
            8 => Some(ErrorType::UndersizeMessage),
            9 => Some(ErrorType::LoopRoute),
            10 => Some(ErrorType::ReturnPathInvalid),
            _ => None,
        }
    }
    fn type_number(&self) -> u32 {
        match *self {
            ErrorType::None => 0,
            ErrorType::MalformedAddress => 1,
            ErrorType::Flood => 2,
            ErrorType::LinkLimitExceeded => 3,
            ErrorType::OversizeMessage => 4,
            ErrorType::UndersizeMessage => 5,
            ErrorType::Authentication => 6,
            ErrorType::Invalid => 7,
            ErrorType::Undeliverable => 8,
            ErrorType::LoopRoute => 9,
            ErrorType::ReturnPathInvalid => 10,
        }
    }
}

const PING_MAGIC: u32 = 0x09f91102;
const PONG_MAGIC: u32 = 0x9d74e35b;
const KEYPING_MAGIC: u32 = 0x01234567;
const KEYPONG_MAGIC: u32 = 0x89abcdef;

#[derive(Clone)]
#[derive(Debug)]
#[derive(Eq)]
#[derive(PartialEq)]
pub enum ControlPacket {
    Error { type_: ErrorType, cause: Vec<u8> },
    Ping { version: u32, opaque_data: Vec<u8> },
    Pong { version: u32, opaque_data: Vec<u8> },
    KeyPing { version: u32, opaque_data: Vec<u8>, key: Vec<u8> },
    KeyPong { version: u32, opaque_data: Vec<u8>, key: Vec<u8> },
}

impl ControlPacket {
    /// Returns a ControlPacket from its raw representation
    pub fn decode(raw: &[u8]) -> Option<ControlPacket> {
        let checksum = BigEndian::read_u16(&raw[0..2]); // TODO: check checksum
        let type_ = BigEndian::read_u16(&raw[2..4]);
        match type_ {
            2 => unimplemented!(), // TODO
            3 | 4 => if raw.len() < 18 { return None }, // PING or PONG
            5 | 6 => if raw.len() < 52 { return None }, // KEYPING or KEYPONG
            _ => return None // unknown type
        }

        let magic = BigEndian::read_u32(&raw[4..8]);
        let version = BigEndian::read_u32(&raw[8..12]);
        let res = match type_ {
            3 => {
                assert_eq!(magic, PING_MAGIC);
                let opaque_data = raw[12..].to_vec();
                ControlPacket::Ping {
                    version: version,
                    opaque_data: opaque_data,
                }
            },
            4 => {
                assert_eq!(magic, PONG_MAGIC);
                let opaque_data = raw[12..].to_vec();
                ControlPacket::Pong {
                    version: version,
                    opaque_data: opaque_data,
                }
            },
            5 => {
                assert_eq!(magic, KEYPING_MAGIC);
                let opaque_data = raw[56..].to_vec();
                ControlPacket::KeyPing {
                    version: version,
                    opaque_data: opaque_data,
                    key: raw[12..56].to_vec(),
                }
            },
            6 => {
                assert_eq!(magic, KEYPONG_MAGIC);
                let opaque_data = raw[56..].to_vec();
                ControlPacket::KeyPong {
                    version: version,
                    opaque_data: opaque_data,
                    key: raw[12..56].to_vec(),
                }
            },
            _ => panic!("The impossible happened.")
        };
        Some(res)
    }

    /// Return the magic number of this type of packet.
    fn type_number(&self) -> u16 {
        match *self {
            ControlPacket::Error { ..} => 2,
            ControlPacket::Ping { .. } => 3,
            ControlPacket::Pong { .. } => 4,
            ControlPacket::KeyPing { .. } => 5,
            ControlPacket::KeyPong { .. } => 6,
        }
    }

    fn checksum(raw: &[u8]) -> u16 {
        let mut sum = 0u32;
        let length = raw.len();
        let mut i = 0;
        while i < length {
            if i+1 < length {
                sum += ((raw[i] as u32) << 8) + (raw[i+1] as u32);
            }
            else {
                sum += (raw[i] as u32) << 8;
            }
            if sum & 0x80000000 != 0 {
                // We are close to an overflow. Sum the carries.
                sum = (sum & 0xffff) + (sum >> 16);
            }
            i += 2;
        }
        while sum >> 16 != 0 {
            sum = (sum & 0xffff) + (sum >> 16);
        }
        !sum as u16
    }

    /// Returns the raw representation of a ControlPacket
    pub fn encode(&self) -> Vec<u8> {
        let mut buf = vec![0; 8];
        match *self {
            ControlPacket::Error { ref type_, ref cause } => {
                buf[3] = 2;
                BigEndian::write_u32(&mut buf[4..8], type_.type_number());
                buf.extend_from_slice(cause);
            },
            ControlPacket::Ping { ref version, ref opaque_data } => {
                buf[3] = 3;
                BigEndian::write_u32(&mut buf[4..8], PING_MAGIC);
                buf.extend_from_slice(&vec![0; 4]);
                BigEndian::write_u32(&mut buf[8..12], *version);
                buf.extend_from_slice(opaque_data);
            }
            ControlPacket::Pong { ref version, ref opaque_data } => {
                buf[3] = 4;
                BigEndian::write_u32(&mut buf[4..8], PONG_MAGIC);
                buf.extend_from_slice(&vec![0; 4]);
                BigEndian::write_u32(&mut buf[8..12], *version);
                buf.extend_from_slice(opaque_data);
            }
            ControlPacket::KeyPing { ref version, ref opaque_data, ref key } => {
                buf[3] = 5;
                BigEndian::write_u32(&mut buf[4..8], KEYPING_MAGIC);
                buf.extend_from_slice(&vec![0; 4]);
                BigEndian::write_u32(&mut buf[8..12], *version);
                buf.extend_from_slice(key);
                buf.extend_from_slice(opaque_data);
            }
            ControlPacket::KeyPong { ref version, ref opaque_data, ref key } => {
                buf[3] = 6;
                BigEndian::write_u32(&mut buf[4..8], KEYPONG_MAGIC);
                buf.extend_from_slice(&vec![0; 4]);
                BigEndian::write_u32(&mut buf[8..12], *version);
                buf.extend_from_slice(key);
                buf.extend_from_slice(opaque_data);
            }
        }
        let checksum = ControlPacket::checksum(&buf);
        BigEndian::write_u16(&mut buf[0..2], checksum);
        buf
    }
}

#[cfg(test)]
mod test {
    //! From cjd's tests:
    //! https://github.com/cjdelisle/cjdnsctrl/blob/ba4a953e0484fb3e4d9b7d3a1463c91b43e4aa63/test.js
    use super::*;
    use hex::{ToHex, FromHex};

    #[test]
    fn ping() {
        let raw = Vec::from_hex("a2e5000309f91102000000124d160b1eee2929e12e19a3b1").unwrap();
        let msg = ControlPacket::Ping { version: 18, opaque_data: Vec::from_hex("4d160b1eee2929e12e19a3b1").unwrap() };
        assert_eq!(msg.encode(), raw);
        assert_eq!(ControlPacket::decode(&raw), Some(msg));
    }

    #[test]
    fn pong() {
        let raw = Vec::from_hex("497400049d74e35b0000001280534c66df69e44b496d5bc8").unwrap();
        let msg = ControlPacket::Pong { version: 18, opaque_data: Vec::from_hex("80534c66df69e44b496d5bc8").unwrap() };
        assert_eq!(msg.encode(), raw);
        assert_eq!(ControlPacket::decode(&raw), Some(msg));
    }

    #[test]
    fn keyping() {
        use fcp_cryptoauth::keys::decode_base32;
        let raw = Vec::from_hex("994b00050123456700000012a331ebbed8d92ac03b10efed3e389cd0c6ec7331a72dbde198476c5eb4d14a1f02e29842b42aedb6bce2ead3").unwrap();
        let key = decode_base32(b"3fdqgz2vtqb0wx02hhvx3wjmjqktyt567fcuvj3m72vw5u6ubu740k3m22fplqvqwpspy93").unwrap();
        let msg = ControlPacket::KeyPing { version: 18, opaque_data: vec![], key: key };
        assert_eq!(msg.encode(), raw);
        assert_eq!(ControlPacket::decode(&raw), Some(msg));
    }

    #[test]
    fn keypong() {
        use fcp_cryptoauth::keys::decode_base32;
        let raw = Vec::from_hex("3b96000689abcdef000000126bd2e8e50faca3d987623d6a043c17c0d9e9004e145f8dd90615d34edbb36d6a02e29842b42aedb6bce2ead3").unwrap();
        let key = decode_base32(b"cmnkylz1dx8mx3bdxku80yw20gqmg0s9nsrusdv0psnxnfhqfmu40k3m22fplqvqwpspy93").unwrap();
        let msg = ControlPacket::KeyPong { version: 18, opaque_data: vec![], key: key };
        assert_eq!(msg.encode(), raw);
        assert_eq!(ControlPacket::decode(&raw), Some(msg));
    }
}
<commit_msg>Add basic support for decoding errors.<commit_after>//! Switch control packets.

use byteorder::BigEndian;
use byteorder::ByteOrder;

#[derive(Clone)]
#[derive(Debug)]
#[derive(Eq)]
#[derive(PartialEq)]
pub enum ErrorType {
    /// No error, everything is ok.
    None,
    /// The switch label was malformed.
    MalformedAddress,
    /// Packet dropped because link is congested.
    Flood,
    /// Packet dropped because node has oversent its limit.
    LinkLimitExceeded,
    /// Message too big to send.
    OversizeMessage,
    /// Message smaller than expected headers.
    UndersizeMessage,
    /// Authentication failed.
    Authentication,
    /// Header is invalid or checksum failed.
    Invalid,
    /// Message could not be sent to its destination through no fault of the sender.
    Undeliverable,
    /// The route enters and leaves through the same interface in one switch.
    LoopRoute,
    /// The switch is unable to represent the return path.
    ReturnPathInvalid,
}

impl ErrorType {
    fn new(type_number: u32) -> Option<ErrorType> {
        match type_number {
            0 => Some(ErrorType::None),
            1 => Some(ErrorType::MalformedAddress),
            2 => Some(ErrorType::Flood),
            3 => Some(ErrorType::LinkLimitExceeded),
            4 => Some(ErrorType::OversizeMessage),
            5 => Some(ErrorType::UndersizeMessage),
            6 => Some(ErrorType::Authentication),
            7 => Some(ErrorType::Invalid),
            8 => Some(ErrorType::UndersizeMessage),
            9 => Some(ErrorType::LoopRoute),
            10 => Some(ErrorType::ReturnPathInvalid),
            _ => None,
        }
    }
    fn type_number(&self) -> u32 {
        match *self {
            ErrorType::None => 0,
            ErrorType::MalformedAddress => 1,
            ErrorType::Flood => 2,
            ErrorType::LinkLimitExceeded => 3,
            ErrorType::OversizeMessage => 4,
            ErrorType::UndersizeMessage => 5,
            ErrorType::Authentication => 6,
            ErrorType::Invalid => 7,
            ErrorType::Undeliverable => 8,
            ErrorType::LoopRoute => 9,
            ErrorType::ReturnPathInvalid => 10,
        }
    }
}

const PING_MAGIC: u32 = 0x09f91102;
const PONG_MAGIC: u32 = 0x9d74e35b;
const KEYPING_MAGIC: u32 = 0x01234567;
const KEYPONG_MAGIC: u32 = 0x89abcdef;

#[derive(Clone)]
#[derive(Debug)]
#[derive(Eq)]
#[derive(PartialEq)]
pub enum ControlPacket {
    Error { type_: ErrorType, cause: Vec<u8> },
    Ping { version: u32, opaque_data: Vec<u8> },
    Pong { version: u32, opaque_data: Vec<u8> },
    KeyPing { version: u32, opaque_data: Vec<u8>, key: Vec<u8> },
    KeyPong { version: u32, opaque_data: Vec<u8>, key: Vec<u8> },
}

impl ControlPacket {
    /// Returns a ControlPacket from its raw representation
    pub fn decode(raw: &[u8]) -> Option<ControlPacket> {
        let checksum = BigEndian::read_u16(&raw[0..2]); // TODO: check checksum
        let type_ = BigEndian::read_u16(&raw[2..4]);
        match type_ {
            2 => if raw.len() < 8 { return None },
            3 | 4 => if raw.len() < 18 { return None }, // PING or PONG
            5 | 6 => if raw.len() < 52 { return None }, // KEYPING or KEYPONG
            _ => return None // unknown type
        }

        let res = match type_ {
            2 => {
                let type_number = BigEndian::read_u32(&raw[4..8]);
                match ErrorType::new(type_number) {
                    Some(type_) => {
                        ControlPacket::Error {
                            type_: type_,
                            cause: raw[8..].to_vec(),
                        }
                    }
                    None => return None,
                }
            },
            3 => {
                let magic = BigEndian::read_u32(&raw[4..8]);
                let version = BigEndian::read_u32(&raw[8..12]);
                assert_eq!(magic, PING_MAGIC);
                let opaque_data = raw[12..].to_vec();
                ControlPacket::Ping {
                    version: version,
                    opaque_data: opaque_data,
                }
            },
            4 => {
                let magic = BigEndian::read_u32(&raw[4..8]);
                let version = BigEndian::read_u32(&raw[8..12]);
                assert_eq!(magic, PONG_MAGIC);
                let opaque_data = raw[12..].to_vec();
                ControlPacket::Pong {
                    version: version,
                    opaque_data: opaque_data,
                }
            },
            5 => {
                let magic = BigEndian::read_u32(&raw[4..8]);
                let version = BigEndian::read_u32(&raw[8..12]);
                assert_eq!(magic, KEYPING_MAGIC);
                let opaque_data = raw[56..].to_vec();
                ControlPacket::KeyPing {
                    version: version,
                    opaque_data: opaque_data,
                    key: raw[12..56].to_vec(),
                }
            },
            6 => {
                let magic = BigEndian::read_u32(&raw[4..8]);
                let version = BigEndian::read_u32(&raw[8..12]);
                assert_eq!(magic, KEYPONG_MAGIC);
                let opaque_data = raw[56..].to_vec();
                ControlPacket::KeyPong {
                    version: version,
                    opaque_data: opaque_data,
                    key: raw[12..56].to_vec(),
                }
            },
            _ => panic!("The impossible happened.")
        };
        Some(res)
    }

    /// Return the magic number of this type of packet.
    fn type_number(&self) -> u16 {
        match *self {
            ControlPacket::Error { ..} => 2,
            ControlPacket::Ping { .. } => 3,
            ControlPacket::Pong { .. } => 4,
            ControlPacket::KeyPing { .. } => 5,
            ControlPacket::KeyPong { .. } => 6,
        }
    }

    fn checksum(raw: &[u8]) -> u16 {
        let mut sum = 0u32;
        let length = raw.len();
        let mut i = 0;
        while i < length {
            if i+1 < length {
                sum += ((raw[i] as u32) << 8) + (raw[i+1] as u32);
            }
            else {
                sum += (raw[i] as u32) << 8;
            }
            if sum & 0x80000000 != 0 {
                // We are close to an overflow. Sum the carries.
                sum = (sum & 0xffff) + (sum >> 16);
            }
            i += 2;
        }
        while sum >> 16 != 0 {
            sum = (sum & 0xffff) + (sum >> 16);
        }
        !sum as u16
    }

    /// Returns the raw representation of a ControlPacket
    pub fn encode(&self) -> Vec<u8> {
        let mut buf = vec![0; 8];
        match *self {
            ControlPacket::Error { ref type_, ref cause } => {
                buf[3] = 2;
                BigEndian::write_u32(&mut buf[4..8], type_.type_number());
                buf.extend_from_slice(cause);
            },
            ControlPacket::Ping { ref version, ref opaque_data } => {
                buf[3] = 3;
                BigEndian::write_u32(&mut buf[4..8], PING_MAGIC);
                buf.extend_from_slice(&vec![0; 4]);
                BigEndian::write_u32(&mut buf[8..12], *version);
                buf.extend_from_slice(opaque_data);
            }
            ControlPacket::Pong { ref version, ref opaque_data } => {
                buf[3] = 4;
                BigEndian::write_u32(&mut buf[4..8], PONG_MAGIC);
                buf.extend_from_slice(&vec![0; 4]);
                BigEndian::write_u32(&mut buf[8..12], *version);
                buf.extend_from_slice(opaque_data);
            }
            ControlPacket::KeyPing { ref version, ref opaque_data, ref key } => {
                buf[3] = 5;
                BigEndian::write_u32(&mut buf[4..8], KEYPING_MAGIC);
                buf.extend_from_slice(&vec![0; 4]);
                BigEndian::write_u32(&mut buf[8..12], *version);
                buf.extend_from_slice(key);
                buf.extend_from_slice(opaque_data);
            }
            ControlPacket::KeyPong { ref version, ref opaque_data, ref key } => {
                buf[3] = 6;
                BigEndian::write_u32(&mut buf[4..8], KEYPONG_MAGIC);
                buf.extend_from_slice(&vec![0; 4]);
                BigEndian::write_u32(&mut buf[8..12], *version);
                buf.extend_from_slice(key);
                buf.extend_from_slice(opaque_data);
            }
        }
        let checksum = ControlPacket::checksum(&buf);
        BigEndian::write_u16(&mut buf[0..2], checksum);
        buf
    }
}

#[cfg(test)]
mod test {
    //! From cjd's tests:
    //! https://github.com/cjdelisle/cjdnsctrl/blob/ba4a953e0484fb3e4d9b7d3a1463c91b43e4aa63/test.js
    use super::*;
    use hex::{ToHex, FromHex};

    #[test]
    fn ping() {
        let raw = Vec::from_hex("a2e5000309f91102000000124d160b1eee2929e12e19a3b1").unwrap();
        let msg = ControlPacket::Ping { version: 18, opaque_data: Vec::from_hex("4d160b1eee2929e12e19a3b1").unwrap() };
        assert_eq!(msg.encode(), raw);
        assert_eq!(ControlPacket::decode(&raw), Some(msg));
    }

    #[test]
    fn pong() {
        let raw = Vec::from_hex("497400049d74e35b0000001280534c66df69e44b496d5bc8").unwrap();
        let msg = ControlPacket::Pong { version: 18, opaque_data: Vec::from_hex("80534c66df69e44b496d5bc8").unwrap() };
        assert_eq!(msg.encode(), raw);
        assert_eq!(ControlPacket::decode(&raw), Some(msg));
    }

    #[test]
    fn keyping() {
        use fcp_cryptoauth::keys::decode_base32;
        let raw = Vec::from_hex("994b00050123456700000012a331ebbed8d92ac03b10efed3e389cd0c6ec7331a72dbde198476c5eb4d14a1f02e29842b42aedb6bce2ead3").unwrap();
        let key = decode_base32(b"3fdqgz2vtqb0wx02hhvx3wjmjqktyt567fcuvj3m72vw5u6ubu740k3m22fplqvqwpspy93").unwrap();
        let msg = ControlPacket::KeyPing { version: 18, opaque_data: vec![], key: key };
        assert_eq!(msg.encode(), raw);
        assert_eq!(ControlPacket::decode(&raw), Some(msg));
    }

    #[test]
    fn keypong() {
        use fcp_cryptoauth::keys::decode_base32;
        let raw = Vec::from_hex("3b96000689abcdef000000126bd2e8e50faca3d987623d6a043c17c0d9e9004e145f8dd90615d34edbb36d6a02e29842b42aedb6bce2ead3").unwrap();
        let key = decode_base32(b"cmnkylz1dx8mx3bdxku80yw20gqmg0s9nsrusdv0psnxnfhqfmu40k3m22fplqvqwpspy93").unwrap();
        let msg = ControlPacket::KeyPong { version: 18, opaque_data: vec![], key: key };
        assert_eq!(msg.encode(), raw);
        assert_eq!(ControlPacket::decode(&raw), Some(msg));
    }

    #[test]
    fn error() {
        let raw = Vec::from_hex("bce300020000000a62c1d23a648114010379000000012d7c000006c378e071c46aefad3aa295fff396371d10678e9833807de083a4a40da39bf0f68f15c4380afbe92405196242a74bb304a8285088579f94fb01867be2171aa8d2c7b54198a89bbdb80c668e9c05").unwrap();
        let msg = ControlPacket::decode(&raw).unwrap();
        match msg {
            ControlPacket::Error { type_, .. } => assert_eq!(type_, ErrorType::ReturnPathInvalid),
            _ => assert!(false),
        }
    }
}
<|endoftext|>