<commit_before>use av_format::error::*;
use std::io::SeekFrom;
use av_data::packet::Packet;
use av_data::timeinfo::TimeInfo;
use av_data::params::*;
use av_format::stream::Stream;
use av_format::buffer::Buffered;
use av_format::demuxer::{Demuxer, Event};
use av_format::demuxer::{Descr, Descriptor};
use av_format::common::GlobalInfo;
use std::collections::VecDeque;
use rational::Rational64;

use ebml::{ebml_header, EBMLHeader};
use elements::{segment, segment_element, Cluster, SeekHead, Info, Tracks, TrackEntry,
               SegmentElement, simple_block};
use nom::{self, Err, IResult, Offset};

#[derive(Debug, Clone, PartialEq)]
pub struct MkvDemuxer {
    pub header: Option<EBMLHeader>,
    pub seek_head: Option<SeekHead>,
    pub info: Option<Info>,
    pub tracks: Option<Tracks>,
    pub queue: VecDeque<Event>,
    pub blockstream: Vec<u8>,
}

impl MkvDemuxer {
    pub fn new() -> MkvDemuxer {
        MkvDemuxer {
            header: None,
            seek_head: None,
            info: None,
            tracks: None,
            queue: VecDeque::new(),
            blockstream: Vec::new(),
        }
    }

    pub fn parse_until_tracks<'a>(&mut self, original_input: &'a [u8]) -> IResult<&'a [u8], ()> {
        let (i1, header) = try_parse!(original_input, ebml_header);

        self.header = Some(header);

        let (mut input, _) = try_parse!(i1, segment);

        self.seek_head = None;
        self.info = None;
        self.tracks = None;

        loop {
            if self.seek_head.is_some() && self.info.is_some() && self.tracks.is_some() {
                return Ok((input, ()));
            }

            // println!("offset: {}", original_input.offset(input));

            let (i3, element) = try_parse!(input, segment_element);

            match element {
                SegmentElement::SeekHead(s) => {
                    // println!("got seek head: {:#?}", s);
                    if self.seek_head.is_some() {
                        return Err(Err::Error(error_position!(nom::ErrorKind::Custom(1), input)));
                    } else {
                        self.seek_head = Some(s);
                    }
                }
                SegmentElement::Info(i) => {
                    // println!("got info: {:#?}", i);
                    if self.info.is_some() {
                        return Err(Err::Error(error_position!(nom::ErrorKind::Custom(1), input)));
                    } else {
                        self.info = Some(i);
                    }
                }
                SegmentElement::Tracks(t) => {
                    // println!("got tracks: {:#?}", t);
                    if self.tracks.is_some() {
                        return Err(Err::Error(error_position!(nom::ErrorKind::Custom(1), input)));
                    } else {
                        self.tracks = Some(t);
                    }
                }
                SegmentElement::Cluster(c) => {
                    // println!("got a cluster: {:#?}", c);
                    //self.clusters.push(c);
                }
                el => {
                    // println!("got element: {:#?}", el);
                }
            }

            input = i3;
        }
    }
}

use nom::Needed;

impl Demuxer for MkvDemuxer {
    fn read_headers(&mut self, buf: &Box<Buffered>, info: &mut GlobalInfo) -> Result<SeekFrom> {
        match self.parse_until_tracks(buf.data()) {
            Ok((i, _)) => {
                info.duration = self.info.as_ref().and_then(|info| info.duration).map(|d| d as u64);
                if let Some(ref t) = self.tracks {
                    info.streams = t.tracks.iter().map(|tr| {
                        track_to_stream(self.info.as_ref().unwrap(), tr)
                    }).collect();
                }
                Ok(SeekFrom::Current(buf.data().offset(i) as i64))
            },
            Err(Err::Incomplete(needed)) => {
                let sz = match needed {
                    Needed::Size(size) => size,
                    _ => 1024,
                };
                Err(Error::MoreDataNeeded(sz))
            },
            e => {
                // println!("error reading headers: {:?}", e);
                Err(Error::InvalidData)
            }
        }
    }

    fn read_event(&mut self, buf: &Box<Buffered>) -> Result<(SeekFrom, Event)> {
        if let Some(event) = self.queue.pop_front() {
            Ok((SeekFrom::Current(0), event))
        } else {
            // println!("no more stored packet, parsing a new one");
            match segment_element(buf.data()) {
                Ok((i, element)) => {
                    let seek = SeekFrom::Current(buf.data().offset(i) as i64);
                    match element {
                        SegmentElement::Cluster(c) => {
                            //self.clusters.push(c);
                            // println!("got cluster element at timecode: {}", c.timecode);
                            let mut packets = c.generate_packets();
                            self.queue.extend(packets.drain(..));
                            if let Some(event) = self.queue.pop_front() {
                                return Ok((seek, event));
                            }
                        }
                        el => {
                            // println!("got element: {:#?}", el);
                        }
                    }
                    Ok((seek, Event::MoreDataNeeded(0)))
                },
                Err(Err::Incomplete(Needed::Size(size))) => {
                    Err(Error::MoreDataNeeded(size))
                },
                e => {
                    println!("parsing issue: {:?}", e);
                    Err(Error::InvalidData)
                }
            }
        }
    }
}

fn track_entry_codec_id(t: &TrackEntry) -> Option<String> {
    // TODO: Support V_QUICKTIME and V_MS/VFW/FOURCC
    match t.codec_id.as_ref() {
        "A_OPUS" => Some("opus".to_owned()),
        "V_VP9" => Some("vp9".to_owned()),
        _ => None,
    }
}

fn track_entry_video_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Validate that a track::video exists for track::type video before.
    if let Some(ref video) = t.video {
        let v = VideoInfo {
            width: video.pixel_width as usize,
            height: video.pixel_height as usize,
            // TODO parse Colour and/or CodecPrivate to extract the format
            format: None,
        };
        Some(MediaKind::Video(v))
    } else {
        None
    }
}

fn track_entry_audio_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Validate that a track::video exists for track::type video before.
    if let Some(ref audio) = t.audio {
        let rate = if let Some(r) = audio.output_sampling_frequency {
            r
        } else {
            audio.sampling_frequency
        };
        // TODO: complete it
        let a = AudioInfo {
            rate: rate as usize,
            map: None,
            format: None,
        };
        Some(MediaKind::Audio(a))
    } else {
        None
    }
}

fn track_entry_media_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Use an enum for the track type
    match t.track_type {
        0x1 => track_entry_video_kind(t),
        0x2 => track_entry_audio_kind(t),
        _ => None,
    }
}

// TODO: make sure the timecode_scale isn't 0
pub fn track_to_stream(info: &Info, t: &TrackEntry) -> Stream {
    let num = if let Some(ts) = t.track_timecode_scale  {
        (ts * info.timecode_scale as f64) as i64
    } else {
        info.timecode_scale as i64
    };

    Stream {
        id: t.track_uid as usize,
        index: t.track_number as usize,
        start: None,
        duration: t.default_duration,
        timebase: Rational64::new(num, 1000 * 1000 * 1000),
        // TODO: Extend CodecParams and fill it with the remaining information
        params: CodecParams {
            extradata: t.codec_private.clone(),
            bit_rate: 0,
            delay: t.codec_delay.unwrap_or(0) as usize,
            convergence_window: t.seek_pre_roll.unwrap_or(0) as usize,
            codec_id: track_entry_codec_id(t),
            kind: track_entry_media_kind(t),
        },
    }
}

impl<'a> Cluster<'a> {
    pub fn generate_packets(&self) -> Vec<Event> {
        let mut v = Vec::new();

        for block_data in self.simple_block.iter() {
            if let Ok((i, block)) = simple_block(block_data) {
                //println!("parsing simple block: {:?}", block);
                let packet = Packet {
                    data: i.into(),
                    t: TimeInfo {
                        pts: Some(block.timecode as i64),
                        dts: None,
                        duration: None,
                        timebase: None,
                    },
                    pos: None,
                    stream_index: block.track_number as isize,
                    is_key: block.keyframe,
                    is_corrupted: false,
                };

                v.push(Event::NewPacket(packet));
            } else {
                println!("error parsing simple block");
            }
        }

        v
    }
}

struct Des {
    d: Descr,
}

impl Descriptor for Des {
    fn create(&self) -> Box<Demuxer> {
        Box::new(MkvDemuxer::new())
    }
    fn describe<'a>(&'a self) -> &'a Descr {
        &self.d
    }
    fn probe(&self, data: &[u8]) -> u8 {
        match ebml_header(&data[..100]) {
            Ok(_) => 100,
            _ => 0,
        }
    }
}

pub const MKV_DESC: &Descriptor = &Des {
    d: Descr {
        name: "matroska",
        demuxer: "mkv",
        description: "Nom-based Matroska demuxer",
        extensions: &["mkv", "webm", "mka"],
        mime: &["video/x-matroska", "audio/x-matroska"],
    }
};

#[cfg(test)]
mod tests {
    use super::*;
    use std::io::Cursor;
    use nom::Offset;
    use av_format::demuxer::Context;
    use av_format::buffer::*;

    const webm: &'static [u8] = include_bytes!("../assets/bbb-vp9-opus.webm");

    #[test]
    fn parse_headers() {
        let mut demuxer = MkvDemuxer::new();

        let res = demuxer.parse_until_tracks(webm);
        println!("got parsing res: {:?}", res);
        match res {
            Ok((i, _)) => {
                println!("offset: {} bytes", webm.offset(i));
            }
            e => {
                println!("could not parse: {:?}", e);
            }
        }

        println!("demuxer: {:#?}", demuxer);
    }

    #[test]
    fn parse_headers_incremental_buffer() {
        let mut demuxer = MkvDemuxer::new();

        for n in 100..2000 {
            let res = demuxer.parse_until_tracks(&webm[0..n]);
            match res {
                Ok(_) => println!("Size {} ok", n),
                Err(Err::Incomplete(needed)) => println!("Incomplete {} needs {:?}", n, needed),
                Err(e) => {
                    panic!("Error at size {}", n);
                }
            }
        }
    }

    #[test]
    fn context() {
        let mut context = Context::new(Box::new(MkvDemuxer::new()),
                                       Box::new(AccReader::new(Cursor::new(webm))));
        println!("DEMUXER CONTEXT read headers: {:?}", context.read_headers().unwrap());
        println!("DEMUXER CONTEXT streams: {:?}", context.info.streams);
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
    }
}
<commit_msg>add VP8 to demuxer<commit_after>use av_format::error::*;
use std::io::SeekFrom;
use av_data::packet::Packet;
use av_data::timeinfo::TimeInfo;
use av_data::params::*;
use av_format::stream::Stream;
use av_format::buffer::Buffered;
use av_format::demuxer::{Demuxer, Event};
use av_format::demuxer::{Descr, Descriptor};
use av_format::common::GlobalInfo;
use std::collections::VecDeque;
use rational::Rational64;

use ebml::{ebml_header, EBMLHeader};
use elements::{segment, segment_element, Cluster, SeekHead, Info, Tracks, TrackEntry,
               SegmentElement, simple_block};
use nom::{self, Err, IResult, Offset};

#[derive(Debug, Clone, PartialEq)]
pub struct MkvDemuxer {
    pub header: Option<EBMLHeader>,
    pub seek_head: Option<SeekHead>,
    pub info: Option<Info>,
    pub tracks: Option<Tracks>,
    pub queue: VecDeque<Event>,
    pub blockstream: Vec<u8>,
}

impl MkvDemuxer {
    pub fn new() -> MkvDemuxer {
        MkvDemuxer {
            header: None,
            seek_head: None,
            info: None,
            tracks: None,
            queue: VecDeque::new(),
            blockstream: Vec::new(),
        }
    }

    pub fn parse_until_tracks<'a>(&mut self, original_input: &'a [u8]) -> IResult<&'a [u8], ()> {
        let (i1, header) = try_parse!(original_input, ebml_header);

        self.header = Some(header);

        let (mut input, _) = try_parse!(i1, segment);

        self.seek_head = None;
        self.info = None;
        self.tracks = None;

        loop {
            if self.seek_head.is_some() && self.info.is_some() && self.tracks.is_some() {
                return Ok((input, ()));
            }

            // println!("offset: {}", original_input.offset(input));

            let (i3, element) = try_parse!(input, segment_element);

            match element {
                SegmentElement::SeekHead(s) => {
                    // println!("got seek head: {:#?}", s);
                    if self.seek_head.is_some() {
                        return Err(Err::Error(error_position!(nom::ErrorKind::Custom(1), input)));
                    } else {
                        self.seek_head = Some(s);
                    }
                }
                SegmentElement::Info(i) => {
                    // println!("got info: {:#?}", i);
                    if self.info.is_some() {
                        return Err(Err::Error(error_position!(nom::ErrorKind::Custom(1), input)));
                    } else {
                        self.info = Some(i);
                    }
                }
                SegmentElement::Tracks(t) => {
                    // println!("got tracks: {:#?}", t);
                    if self.tracks.is_some() {
                        return Err(Err::Error(error_position!(nom::ErrorKind::Custom(1), input)));
                    } else {
                        self.tracks = Some(t);
                    }
                }
                SegmentElement::Cluster(c) => {
                    // println!("got a cluster: {:#?}", c);
                    //self.clusters.push(c);
                }
                el => {
                    // println!("got element: {:#?}", el);
                }
            }

            input = i3;
        }
    }
}

use nom::Needed;

impl Demuxer for MkvDemuxer {
    fn read_headers(&mut self, buf: &Box<Buffered>, info: &mut GlobalInfo) -> Result<SeekFrom> {
        match self.parse_until_tracks(buf.data()) {
            Ok((i, _)) => {
                info.duration = self.info.as_ref().and_then(|info| info.duration).map(|d| d as u64);
                if let Some(ref t) = self.tracks {
                    info.streams = t.tracks.iter().map(|tr| {
                        track_to_stream(self.info.as_ref().unwrap(), tr)
                    }).collect();
                }
                Ok(SeekFrom::Current(buf.data().offset(i) as i64))
            },
            Err(Err::Incomplete(needed)) => {
                let sz = match needed {
                    Needed::Size(size) => size,
                    _ => 1024,
                };
                Err(Error::MoreDataNeeded(sz))
            },
            e => {
                // println!("error reading headers: {:?}", e);
                Err(Error::InvalidData)
            }
        }
    }

    fn read_event(&mut self, buf: &Box<Buffered>) -> Result<(SeekFrom, Event)> {
        if let Some(event) = self.queue.pop_front() {
            Ok((SeekFrom::Current(0), event))
        } else {
            // println!("no more stored packet, parsing a new one");
            match segment_element(buf.data()) {
                Ok((i, element)) => {
                    let seek = SeekFrom::Current(buf.data().offset(i) as i64);
                    match element {
                        SegmentElement::Cluster(c) => {
                            //self.clusters.push(c);
                            // println!("got cluster element at timecode: {}", c.timecode);
                            let mut packets = c.generate_packets();
                            self.queue.extend(packets.drain(..));
                            if let Some(event) = self.queue.pop_front() {
                                return Ok((seek, event));
                            }
                        }
                        el => {
                            // println!("got element: {:#?}", el);
                        }
                    }
                    Ok((seek, Event::MoreDataNeeded(0)))
                },
                Err(Err::Incomplete(Needed::Size(size))) => {
                    Err(Error::MoreDataNeeded(size))
                },
                e => {
                    println!("parsing issue: {:?}", e);
                    Err(Error::InvalidData)
                }
            }
        }
    }
}

fn track_entry_codec_id(t: &TrackEntry) -> Option<String> {
    // TODO: Support V_QUICKTIME and V_MS/VFW/FOURCC
    match t.codec_id.as_ref() {
        "A_OPUS" => Some("opus".to_owned()),
        "V_VP8" => Some("vp8".to_owned()),
        "V_VP9" => Some("vp9".to_owned()),
        _ => None,
    }
}

fn track_entry_video_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Validate that a track::video exists for track::type video before.
    if let Some(ref video) = t.video {
        let v = VideoInfo {
            width: video.pixel_width as usize,
            height: video.pixel_height as usize,
            // TODO parse Colour and/or CodecPrivate to extract the format
            format: None,
        };
        Some(MediaKind::Video(v))
    } else {
        None
    }
}

fn track_entry_audio_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Validate that a track::video exists for track::type video before.
    if let Some(ref audio) = t.audio {
        let rate = if let Some(r) = audio.output_sampling_frequency {
            r
        } else {
            audio.sampling_frequency
        };
        // TODO: complete it
        let a = AudioInfo {
            rate: rate as usize,
            map: None,
            format: None,
        };
        Some(MediaKind::Audio(a))
    } else {
        None
    }
}

fn track_entry_media_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Use an enum for the track type
    match t.track_type {
        0x1 => track_entry_video_kind(t),
        0x2 => track_entry_audio_kind(t),
        _ => None,
    }
}

// TODO: make sure the timecode_scale isn't 0
pub fn track_to_stream(info: &Info, t: &TrackEntry) -> Stream {
    let num = if let Some(ts) = t.track_timecode_scale  {
        (ts * info.timecode_scale as f64) as i64
    } else {
        info.timecode_scale as i64
    };

    Stream {
        id: t.track_uid as usize,
        index: t.track_number as usize,
        start: None,
        duration: t.default_duration,
        timebase: Rational64::new(num, 1000 * 1000 * 1000),
        // TODO: Extend CodecParams and fill it with the remaining information
        params: CodecParams {
            extradata: t.codec_private.clone(),
            bit_rate: 0,
            delay: t.codec_delay.unwrap_or(0) as usize,
            convergence_window: t.seek_pre_roll.unwrap_or(0) as usize,
            codec_id: track_entry_codec_id(t),
            kind: track_entry_media_kind(t),
        },
    }
}

impl<'a> Cluster<'a> {
    pub fn generate_packets(&self) -> Vec<Event> {
        let mut v = Vec::new();

        for block_data in self.simple_block.iter() {
            if let Ok((i, block)) = simple_block(block_data) {
                //println!("parsing simple block: {:?}", block);
                let packet = Packet {
                    data: i.into(),
                    t: TimeInfo {
                        pts: Some(block.timecode as i64),
                        dts: None,
                        duration: None,
                        timebase: None,
                    },
                    pos: None,
                    stream_index: block.track_number as isize,
                    is_key: block.keyframe,
                    is_corrupted: false,
                };

                v.push(Event::NewPacket(packet));
            } else {
                println!("error parsing simple block");
            }
        }

        v
    }
}

struct Des {
    d: Descr,
}

impl Descriptor for Des {
    fn create(&self) -> Box<Demuxer> {
        Box::new(MkvDemuxer::new())
    }
    fn describe<'a>(&'a self) -> &'a Descr {
        &self.d
    }
    fn probe(&self, data: &[u8]) -> u8 {
        match ebml_header(&data[..100]) {
            Ok(_) => 100,
            _ => 0,
        }
    }
}

pub const MKV_DESC: &Descriptor = &Des {
    d: Descr {
        name: "matroska",
        demuxer: "mkv",
        description: "Nom-based Matroska demuxer",
        extensions: &["mkv", "webm", "mka"],
        mime: &["video/x-matroska", "audio/x-matroska"],
    }
};

#[cfg(test)]
mod tests {
    use super::*;
    use std::io::Cursor;
    use nom::Offset;
    use av_format::demuxer::Context;
    use av_format::buffer::*;

    const webm: &'static [u8] = include_bytes!("../assets/bbb-vp9-opus.webm");

    #[test]
    fn parse_headers() {
        let mut demuxer = MkvDemuxer::new();

        let res = demuxer.parse_until_tracks(webm);
        println!("got parsing res: {:?}", res);
        match res {
            Ok((i, _)) => {
                println!("offset: {} bytes", webm.offset(i));
            }
            e => {
                println!("could not parse: {:?}", e);
            }
        }

        println!("demuxer: {:#?}", demuxer);
    }

    #[test]
    fn parse_headers_incremental_buffer() {
        let mut demuxer = MkvDemuxer::new();

        for n in 100..2000 {
            let res = demuxer.parse_until_tracks(&webm[0..n]);
            match res {
                Ok(_) => println!("Size {} ok", n),
                Err(Err::Incomplete(needed)) => println!("Incomplete {} needs {:?}", n, needed),
                Err(e) => {
                    panic!("Error at size {}", n);
                }
            }
        }
    }

    #[test]
    fn context() {
        let mut context = Context::new(Box::new(MkvDemuxer::new()),
                                       Box::new(AccReader::new(Cursor::new(webm))));
        println!("DEMUXER CONTEXT read headers: {:?}", context.read_headers().unwrap());
        println!("DEMUXER CONTEXT streams: {:?}", context.info.streams);
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 click2stream, Inc.
//
// 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.

#[cfg(feature="discovery")]
use std::thread;

use std::thread::JoinHandle;

use context::ApplicationContext;

#[cfg(feature = "discovery")]
use scanner::discovery;

#[cfg(feature="discovery")]
use utils;

use utils::logger::{BoxedLogger, Logger};

#[cfg(feature="discovery")]
use utils::logger::Severity;

use futures::{BoxFuture, Future, Poll, Stream};

use futures::sync::mpsc;
use futures::sync::mpsc::{UnboundedReceiver, UnboundedSender};

use time;

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Command {
    ResetServiceTable,
    ScanNetwork,
    PeriodicNetworkScan,
}

#[derive(Debug, Copy, Clone)]
enum Event {
    Command(Command),
    ScanCompleted,
}

type CommandReceiver = UnboundedReceiver<Event>;

type CommandSender = UnboundedSender<Event>;

/// A channel for sending commands across threads. The channel is cloneable and every copy of it
/// will send commands to the same handler.
#[derive(Clone)]
pub struct CommandChannel {
    tx: CommandSender,
}

impl CommandChannel {
    /// Create a new command channel.
    fn new(tx: CommandSender) -> CommandChannel {
        CommandChannel {
            tx: tx,
        }
    }

    /// Send a given command.
    pub fn send(&self, cmd: Command) {
        self.tx.send(Event::Command(cmd))
            .expect("broken command channel");
    }
}

/// Command handler context.
struct CommandHandlerContext {
    app_context:  ApplicationContext,
    logger:       BoxedLogger,
    cmd_sender:   CommandSender,
    last_nw_scan: f64,
    scanner:      Option<JoinHandle<()>>,
}

impl CommandHandlerContext {
    /// Create a new command handler context.
    fn new(app_context: ApplicationContext, cmd_sender: CommandSender) -> CommandHandlerContext {
        let logger = app_context.get_logger();

        let t = time::precise_time_s();

        CommandHandlerContext {
            app_context:  app_context,
            logger:       logger,
            cmd_sender:   cmd_sender,
            last_nw_scan: t - 300.0,
            scanner:      None,
        }
    }

    /// Process a given command handler event.
    fn proces_event(&mut self, event: Event) {
        match event {
            Event::Command(cmd)  => self.process_command(cmd),
            Event::ScanCompleted => self.scan_completed(),
        }
    }

    /// Process a given command.
    fn process_command(&mut self, cmd: Command) {
        match cmd {
            Command::ResetServiceTable   => self.reset_service_table(),
            Command::ScanNetwork         => self.scan_network(),
            Command::PeriodicNetworkScan => self.periodic_network_scan(),
        }
    }

    /// Reset service table.
    fn reset_service_table(&mut self) {
        self.app_context.reset_service_table()
    }

    /// Trigger periodic netork scan.
    fn periodic_network_scan(&mut self) {
        let t = time::precise_time_s();

        if (self.last_nw_scan + 300.0) < t {
            self.scan_network();
        }
    }

    #[cfg(feature="discovery")]
    /// Trigger a network scan.
    fn scan_network(&mut self) {
        if self.scanner.is_some() {
            return;
        }

        let app_context = self.app_context.clone();
        let cmd_sender  = self.cmd_sender.clone();

        let handle = thread::spawn(move || {
            network_scanner_thread(app_context);

            cmd_sender.send(Event::ScanCompleted)
                .unwrap();
        });

        self.scanner = Some(handle);
    }

    #[cfg(not(feature="discovery"))]
    /// Dummy network scan.
    fn scan_network(&mut self) {
    }

    /// Cleanup the scanner context.
    fn scan_completed(&mut self) {
        if let Some(handle) = self.scanner.take() {
            if let Err(_) = handle.join() {
                log_warn!(self.logger, "network scanner thread panicked");
            }
        }

        self.last_nw_scan = time::precise_time_s();
    }
}

/// Command handler. It implements the future trait and it's designed to be used in combination
/// with tokio event loop.
pub struct CommandHandler {
    handler: BoxFuture<(), ()>,
}

impl CommandHandler {
    /// Create a new command handler.
    fn new(
        app_context: ApplicationContext,
        rx: CommandReceiver,
        tx: CommandSender) -> CommandHandler {
        let mut context = CommandHandlerContext::new(app_context, tx);

        let handler = rx.for_each(move |event| {
            context.proces_event(event);
            Ok(())
        });

        CommandHandler {
            handler: handler.boxed(),
        }
    }
}

impl Future for CommandHandler {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        self.handler.poll()
    }
}

/// Create a new channel-handler pair.
pub fn new(app_context: ApplicationContext) -> (CommandChannel, CommandHandler) {
    let (tx, rx) = mpsc::unbounded();

    let rx = CommandHandler::new(app_context, rx, tx.clone());
    let tx = CommandChannel::new(tx);

    (tx, rx)
}

#[cfg(feature = "discovery")]
/// Run device discovery and update the service table.
fn network_scanner_thread(mut app_context: ApplicationContext) {
    let mut logger = app_context.get_logger();

    let rtsp_paths_file = app_context.get_rtsp_paths_file();
    let mjpeg_paths_file = app_context.get_mjpeg_paths_file();

    app_context.set_scanning(true);

    log_info!(logger, "looking for local services...");

    let result = utils::result_or_log(&mut logger, Severity::WARN,
        "network scanner error",
        discovery::scan_network(
            &rtsp_paths_file,
            &mjpeg_paths_file));

    if let Some(result) = result {
        let services = result.services()
            .map(|svc| svc.clone())
            .collect::<Vec<_>>();

        let count = services.len();

        app_context.update_service_table(services);
        app_context.set_scan_result(result);

        log_info!(logger, "{} services found, current service table: {}",
            count, app_context.get_service_table());
    }

    app_context.set_scanning(false);
}
<commit_msg>Minor tweaks in the command handler<commit_after>// Copyright 2017 click2stream, Inc.
//
// 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.

#[cfg(feature="discovery")]
use std::thread;

use std::thread::JoinHandle;

use context::ApplicationContext;

#[cfg(feature = "discovery")]
use scanner::discovery;

#[cfg(feature="discovery")]
use utils;

use utils::logger::{BoxedLogger, Logger};

#[cfg(feature="discovery")]
use utils::logger::Severity;

use futures::{BoxFuture, Future, Poll, Stream};

use futures::sync::mpsc;
use futures::sync::mpsc::{UnboundedReceiver, UnboundedSender};

use time;

/// Network scan period.
const NETWORK_SCAN_PERIOD: f64 = 300.0;

/// Different command types that the command handler can receive.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Command {
    ResetServiceTable,
    ScanNetwork,
    PeriodicNetworkScan,
}

/// Command handler event.
#[derive(Debug, Copy, Clone)]
enum Event {
    Command(Command),
    ScanCompleted,
}

type CommandReceiver = UnboundedReceiver<Event>;

type CommandSender = UnboundedSender<Event>;

/// A channel for sending commands across threads. The channel is cloneable and every copy of it
/// will send commands to the same handler.
#[derive(Clone)]
pub struct CommandChannel {
    tx: CommandSender,
}

impl CommandChannel {
    /// Create a new command channel.
    fn new(tx: CommandSender) -> CommandChannel {
        CommandChannel {
            tx: tx,
        }
    }

    /// Send a given command.
    pub fn send(&self, cmd: Command) {
        self.tx.send(Event::Command(cmd))
            .expect("broken command channel");
    }
}

/// Command handler context.
struct CommandHandlerContext {
    app_context:  ApplicationContext,
    logger:       BoxedLogger,
    cmd_sender:   CommandSender,
    last_nw_scan: f64,
    scanner:      Option<JoinHandle<()>>,
}

impl CommandHandlerContext {
    /// Create a new command handler context.
    fn new(app_context: ApplicationContext, cmd_sender: CommandSender) -> CommandHandlerContext {
        let logger = app_context.get_logger();

        let t = time::precise_time_s();

        CommandHandlerContext {
            app_context:  app_context,
            logger:       logger,
            cmd_sender:   cmd_sender,
            last_nw_scan: t - 300.0,
            scanner:      None,
        }
    }

    /// Process a given command handler event.
    fn proces_event(&mut self, event: Event) {
        match event {
            Event::Command(cmd)  => self.process_command(cmd),
            Event::ScanCompleted => self.scan_completed(),
        }
    }

    /// Process a given command.
    fn process_command(&mut self, cmd: Command) {
        match cmd {
            Command::ResetServiceTable   => self.reset_service_table(),
            Command::ScanNetwork         => self.scan_network(),
            Command::PeriodicNetworkScan => self.periodic_network_scan(),
        }
    }

    /// Reset service table.
    fn reset_service_table(&mut self) {
        self.app_context.reset_service_table()
    }

    /// Trigger periodic netork scan.
    fn periodic_network_scan(&mut self) {
        let t = time::precise_time_s();

        if (self.last_nw_scan + NETWORK_SCAN_PERIOD) < t {
            self.scan_network();
        }
    }

    #[cfg(feature="discovery")]
    /// Trigger a network scan.
    fn scan_network(&mut self) {
        if self.scanner.is_some() {
            return;
        }

        let app_context = self.app_context.clone();
        let cmd_sender  = self.cmd_sender.clone();

        let handle = thread::spawn(move || {
            network_scanner_thread(app_context);

            cmd_sender.send(Event::ScanCompleted)
                .unwrap();
        });

        self.scanner = Some(handle);
    }

    #[cfg(not(feature="discovery"))]
    /// Dummy network scan.
    fn scan_network(&mut self) {
    }

    /// Cleanup the scanner context.
    fn scan_completed(&mut self) {
        if let Some(handle) = self.scanner.take() {
            if let Err(_) = handle.join() {
                log_warn!(self.logger, "network scanner thread panicked");
            }
        }

        self.last_nw_scan = time::precise_time_s();
    }
}

/// Command handler. It implements the future trait and it's designed to be used in combination
/// with tokio event loop.
pub struct CommandHandler {
    handler: BoxFuture<(), ()>,
}

impl CommandHandler {
    /// Create a new command handler.
    fn new(
        app_context: ApplicationContext,
        rx: CommandReceiver,
        tx: CommandSender) -> CommandHandler {
        let mut context = CommandHandlerContext::new(app_context, tx);

        let handler = rx.for_each(move |event| {
            context.proces_event(event);
            Ok(())
        });

        CommandHandler {
            handler: handler.boxed(),
        }
    }
}

impl Future for CommandHandler {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        self.handler.poll()
    }
}

/// Create a new channel-handler pair.
pub fn new(app_context: ApplicationContext) -> (CommandChannel, CommandHandler) {
    let (tx, rx) = mpsc::unbounded();

    let rx = CommandHandler::new(app_context, rx, tx.clone());
    let tx = CommandChannel::new(tx);

    (tx, rx)
}

#[cfg(feature = "discovery")]
/// Run device discovery and update the service table.
fn network_scanner_thread(mut app_context: ApplicationContext) {
    let mut logger = app_context.get_logger();

    let rtsp_paths_file = app_context.get_rtsp_paths_file();
    let mjpeg_paths_file = app_context.get_mjpeg_paths_file();

    app_context.set_scanning(true);

    log_info!(logger, "looking for local services...");

    let result = utils::result_or_log(&mut logger, Severity::WARN,
        "network scanner error",
        discovery::scan_network(
            &rtsp_paths_file,
            &mjpeg_paths_file));

    if let Some(result) = result {
        let services = result.services()
            .map(|svc| svc.clone())
            .collect::<Vec<_>>();

        let count = services.len();

        app_context.update_service_table(services);
        app_context.set_scan_result(result);

        log_info!(logger, "{} services found, current service table: {}",
            count, app_context.get_service_table());
    }

    app_context.set_scanning(false);
}
<|endoftext|>


<commit_before>use ffi;
use error::YamlError;
use event::{YamlVersionDirective, YamlTagDirective};

use std::str;
use std::slice;
use std::ptr;
use std::mem;
use std::ffi::{c_str_to_bytes, CString};
use std::old_io::IoError;
use libc;

pub struct YamlBaseEmitter {
    emitter_mem: ffi::yaml_emitter_t
}

impl YamlBaseEmitter {
    unsafe fn new() -> YamlBaseEmitter {
        YamlBaseEmitter {
            emitter_mem: mem::uninitialized()
        }
    }
}

impl Drop for YamlBaseEmitter {
    fn drop(&mut self) {
        unsafe {
            ffi::yaml_emitter_delete(&mut self.emitter_mem);
        }
    }
}

pub struct YamlEmitter<'r> {
    base_emitter: YamlBaseEmitter,
    writer: &'r mut (Writer+'r),
    io_error: Option<IoError>,
}

impl<'r> YamlEmitter<'r> {
    pub fn init<'a>(writer: &'a mut Writer) -> Box<YamlEmitter<'a>> {
        unsafe {
            let mut emitter = box YamlEmitter {
                base_emitter: YamlBaseEmitter::new(),
                writer: writer,
                io_error: None
            };

            if ffi::yaml_emitter_initialize(&mut emitter.base_emitter.emitter_mem) == 0 {
                panic!("failed to initialize yaml_emitter_t");
            }

            ffi::yaml_emitter_set_output(&mut emitter.base_emitter.emitter_mem, handle_writer_cb, mem::transmute(&mut *emitter));

            emitter
        }
    }

    fn get_error(&mut self) -> YamlError {
        let emitter_mem = &self.base_emitter.emitter_mem;
        unsafe {
            let c_problem = c_str_to_bytes(&emitter_mem.problem);
            let mut error = YamlError {
                kind: emitter_mem.error,
                problem: str::from_utf8(c_problem).map(|s| s.to_string()).ok(),
                io_error: None,
                context: None
            };

            mem::swap(&mut self.io_error, &mut error.io_error);

            return error;
        }
    }

    pub fn emit_stream<F>(&mut self, encoding: ffi::YamlEncoding, f: F) -> Result<(), YamlError>
        where F: Fn(&mut YamlEmitter) -> Result<(), YamlError>
    {
        try!(self.emit_stream_start_event(encoding));
        try!(f(self));
        try!(self.emit_stream_end_event());
        self.flush()
    }

    fn emit_stream_start_event(&mut self, encoding: ffi::YamlEncoding) -> Result<(), YamlError> {
        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_stream_start_event_initialize(&mut event, encoding) == 0 {
                panic!("yaml_stream_start_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    fn emit_stream_end_event(&mut self) -> Result<(), YamlError> {
        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_stream_end_event_initialize(&mut event) == 0 {
                panic!("yaml_stream_end_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_document<F>(&mut self,
            version_directive: Option<YamlVersionDirective>,
            tag_directives: &[YamlTagDirective],
            implicit: bool,
            f: F) -> Result<(), YamlError> where
        F: Fn(&mut YamlEmitter) -> Result<(), YamlError>
    {
        try!(self.emit_document_start_event(version_directive, tag_directives, implicit));
        try!(f(self));
        self.emit_document_end_event(implicit)
    }

    fn emit_document_start_event(&mut self,
            version_directive: Option<YamlVersionDirective>,
            tag_directives: &[YamlTagDirective],
            implicit: bool)
        -> Result<(), YamlError>
    {
        let mut vsn_dir = ffi::yaml_version_directive_t { major: 0, minor: 0 };
        let c_vsn_dir = match version_directive {
            Some(directive) => {
                vsn_dir.major = directive.major as libc::c_int;
                vsn_dir.minor = directive.minor as libc::c_int;
                &vsn_dir as *const ffi::yaml_version_directive_t
            },
            None => ptr::null()
        };

        let c_strs: Vec<(CString, CString)> = tag_directives.iter().map(|tag| {
            (CString::from_slice(tag.handle.as_bytes()), CString::from_slice(tag.prefix.as_bytes()))
        }).collect();
        let c_tag_dirs: Vec<ffi::yaml_tag_directive_t> = c_strs.iter().map(|tuple| {
            ffi::yaml_tag_directive_t {
                handle: tuple.0.as_ptr(),
                prefix: tuple.1.as_ptr(),
            }
        }).collect();
        let tag_dir_start = c_tag_dirs.as_ptr();
        unsafe {
            let mut event = mem::uninitialized();
            let tag_dir_end = tag_dir_start.offset(c_tag_dirs.len() as isize);
            let c_implicit = if implicit { 1 } else { 0 };

            if ffi::yaml_document_start_event_initialize(&mut event, c_vsn_dir, tag_dir_start, tag_dir_end, c_implicit) == 0 {
                panic!("yaml_document_start_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    fn emit_document_end_event(&mut self, implicit: bool) -> Result<(), YamlError> {
        let c_implicit = if implicit { 1 } else { 0 };
        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_document_end_event_initialize(&mut event, c_implicit) == 0 {
                panic!("yaml_stream_end_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_alias_event(&mut self, anchor: &str) -> Result<(), YamlError> {
        let c_anchor = CString::from_slice(anchor.as_bytes());

        unsafe {
            let mut event = mem::uninitialized();

            let ptr = c_anchor.as_ptr();
            if ffi::yaml_alias_event_initialize(&mut event, ptr as *const ffi::yaml_char_t) != 0 {
                panic!("yaml_stream_end_event_initialize failed!")
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_scalar_event(&mut self, anchor: Option<&str>, tag: Option<&str>,
        value: &str, plain_implicit: bool, quoted_implicit: bool,
        style: ffi::YamlScalarStyle) -> Result<(), YamlError>
    {
        let c_anchor = anchor.map(|s| CString::from_slice(s.as_bytes()));
        let anchor_ptr = match c_anchor {
            Some(s) => s.as_ptr(),
            None => ptr::null()
        };
        let c_tag = tag.map(|s| CString::from_slice(s.as_bytes()));
        let tag_ptr = match c_tag {
            Some(s) => s.as_ptr(),
            None => ptr::null()
        };
        let c_plain_implicit = if plain_implicit { 1 } else { 0 };
        let c_quoted_implicit = if quoted_implicit { 1 } else { 0 };

        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_scalar_event_initialize(&mut event,
                    anchor_ptr as *const ffi::yaml_char_t, tag_ptr as *const ffi::yaml_char_t,
                    value.as_ptr(), value.len() as libc::c_int,
                    c_plain_implicit, c_quoted_implicit,
                    style) == 0
            {
                panic!("yaml_scalar_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_sequence<F>(&mut self, anchor: Option<&str>, tag: Option<&str>, implicit: bool,
            style: ffi::YamlSequenceStyle,
            f: F) -> Result<(), YamlError> where
        F: Fn(&mut YamlEmitter) -> Result<(), YamlError>
    {
        try!(self.emit_sequence_start_event(anchor, tag, implicit, style));
        try!(f(self));
        self.emit_sequence_end_event()
    }

    fn emit_sequence_start_event(&mut self, anchor: Option<&str>, tag: Option<&str>, implicit: bool,
        style: ffi::YamlSequenceStyle) -> Result<(), YamlError>
    {
        let c_anchor = anchor.map(|s| CString::from_slice(s.as_bytes()));
        let anchor_ptr = match c_anchor {
            Some(s) => s.as_ptr(),
            None => ptr::null()
        };
        let c_tag = tag.map(|s| CString::from_slice(s.as_bytes()));
        let tag_ptr = match c_tag {
            Some(s) => s.as_ptr(),
            None => ptr::null()
        };
        let c_implicit = if implicit { 1 } else { 0 };

        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_sequence_start_event_initialize(&mut event,
                    anchor_ptr as *const ffi::yaml_char_t, tag_ptr as *const ffi::yaml_char_t,
                    c_implicit, style) == 0
            {
                panic!("yaml_sequence_start_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    fn emit_sequence_end_event(&mut self) -> Result<(), YamlError> {
        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_sequence_end_event_initialize(&mut event) == 0 {
                panic!("yaml_sequence_end_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_mapping<F>(&mut self, anchor: Option<&str>, tag: Option<&str>, implicit: bool,
            style: ffi::YamlSequenceStyle,
            f: F) -> Result<(), YamlError> where
        F: Fn(&mut YamlEmitter) -> Result<(), YamlError>
    {
        try!(self.emit_mapping_start_event(anchor, tag, implicit, style));
        try!(f(self));
        self.emit_mapping_end_event()
    }

    fn emit_mapping_start_event(&mut self, anchor: Option<&str>, tag: Option<&str>, implicit: bool,
        style: ffi::YamlSequenceStyle) -> Result<(), YamlError>
    {
        let c_anchor = anchor.map(|s| CString::from_slice(s.as_bytes()));
        let anchor_ptr = match c_anchor {
            Some(s) => s.as_ptr(),
            None => ptr::null()
        };
        let c_tag = tag.map(|s| CString::from_slice(s.as_bytes()));
        let tag_ptr = match c_tag {
            Some(s) => s.as_ptr(),
            None => ptr::null()
        };
        let c_implicit = if implicit { 1 } else { 0 };

        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_mapping_start_event_initialize(&mut event,
                    anchor_ptr as *const ffi::yaml_char_t, tag_ptr as *const ffi::yaml_char_t,
                    c_implicit, style) == 0
            {
                panic!("yaml_mapping_start_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    fn emit_mapping_end_event(&mut self) -> Result<(), YamlError> {
        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_mapping_end_event_initialize(&mut event) == 0 {
                panic!("yaml_mapping_end_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn flush(&mut self) -> Result<(), YamlError> {
        unsafe {
            if ffi::yaml_emitter_flush(&mut self.base_emitter.emitter_mem) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }
}

extern fn handle_writer_cb(data: *mut YamlEmitter, buffer: *const u8, size: libc::size_t) -> libc::c_int {
    unsafe {
        let buf = slice::from_raw_parts(buffer, size as usize);
        let emitter = &mut *data;
        match emitter.writer.write_all(buf) {
            Ok(()) => 1,
            Err(err) => {
                emitter.io_error = Some(err);
                0
            }
        }
    }
}

#[cfg(test)]
mod test {
    use std::old_io::MemWriter;
    use emitter::YamlEmitter;
    use ffi::YamlEncoding::YamlUtf8Encoding;
    use ffi::YamlScalarStyle::*;
    use ffi::YamlSequenceStyle::*;

    #[test]
    #[allow(unused_must_use)]
    fn event_emitter_sequence_test() {
        let mut writer = MemWriter::new();
        {
            let mut emitter = YamlEmitter::init(&mut writer);
            emitter.emit_stream(YamlUtf8Encoding, |e| {
                e.emit_document(None, &[], true, |e| {
                    e.emit_sequence(None, None, true, YamlFlowSequenceStyle, |e| {
                        try!(e.emit_scalar_event(None, None, "1", true, false, YamlPlainScalarStyle));
                        e.emit_scalar_event(None, None, "2", true, false, YamlPlainScalarStyle)
                    })
                })
            });
            emitter.flush();
        }
        assert_eq!(writer.get_ref(), "[1, 2]\n".as_bytes());
    }

    #[test]
    #[allow(unused_must_use)]
    fn event_emitter_mapping_test() {
        let mut writer = MemWriter::new();
        {
            let mut emitter = YamlEmitter::init(&mut writer);
            emitter.emit_stream(YamlUtf8Encoding, |e| {
                e.emit_document(None, &[], true, |e| {
                    e.emit_mapping(None, None, true, YamlFlowSequenceStyle, |e| {
                        try!(e.emit_scalar_event(None, None, "a", true, false, YamlPlainScalarStyle));
                        try!(e.emit_scalar_event(None, None, "1", true, false, YamlPlainScalarStyle));
                        try!(e.emit_scalar_event(None, None, "b", true, false, YamlPlainScalarStyle));
                        e.emit_scalar_event(None, None, "2", true, false, YamlPlainScalarStyle)
                    })
                })
            });
            emitter.flush();
        }
        assert_eq!(writer.get_ref(), "{a: 1, b: 2}\n".as_bytes());
    }
}
<commit_msg>Rust changes: MemWriter deprecated<commit_after>use ffi;
use error::YamlError;
use event::{YamlVersionDirective, YamlTagDirective};

use std::str;
use std::slice;
use std::ptr;
use std::mem;
use std::ffi::{c_str_to_bytes, CString};
use std::old_io::IoError;
use libc;

pub struct YamlBaseEmitter {
    emitter_mem: ffi::yaml_emitter_t
}

impl YamlBaseEmitter {
    unsafe fn new() -> YamlBaseEmitter {
        YamlBaseEmitter {
            emitter_mem: mem::uninitialized()
        }
    }
}

impl Drop for YamlBaseEmitter {
    fn drop(&mut self) {
        unsafe {
            ffi::yaml_emitter_delete(&mut self.emitter_mem);
        }
    }
}

pub struct YamlEmitter<'r> {
    base_emitter: YamlBaseEmitter,
    writer: &'r mut (Writer+'r),
    io_error: Option<IoError>,
}

impl<'r> YamlEmitter<'r> {
    pub fn init<'a>(writer: &'a mut Writer) -> Box<YamlEmitter<'a>> {
        unsafe {
            let mut emitter = box YamlEmitter {
                base_emitter: YamlBaseEmitter::new(),
                writer: writer,
                io_error: None
            };

            if ffi::yaml_emitter_initialize(&mut emitter.base_emitter.emitter_mem) == 0 {
                panic!("failed to initialize yaml_emitter_t");
            }

            ffi::yaml_emitter_set_output(&mut emitter.base_emitter.emitter_mem, handle_writer_cb, mem::transmute(&mut *emitter));

            emitter
        }
    }

    fn get_error(&mut self) -> YamlError {
        let emitter_mem = &self.base_emitter.emitter_mem;
        unsafe {
            let c_problem = c_str_to_bytes(&emitter_mem.problem);
            let mut error = YamlError {
                kind: emitter_mem.error,
                problem: str::from_utf8(c_problem).map(|s| s.to_string()).ok(),
                io_error: None,
                context: None
            };

            mem::swap(&mut self.io_error, &mut error.io_error);

            return error;
        }
    }

    pub fn emit_stream<F>(&mut self, encoding: ffi::YamlEncoding, f: F) -> Result<(), YamlError>
        where F: Fn(&mut YamlEmitter) -> Result<(), YamlError>
    {
        try!(self.emit_stream_start_event(encoding));
        try!(f(self));
        try!(self.emit_stream_end_event());
        self.flush()
    }

    fn emit_stream_start_event(&mut self, encoding: ffi::YamlEncoding) -> Result<(), YamlError> {
        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_stream_start_event_initialize(&mut event, encoding) == 0 {
                panic!("yaml_stream_start_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    fn emit_stream_end_event(&mut self) -> Result<(), YamlError> {
        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_stream_end_event_initialize(&mut event) == 0 {
                panic!("yaml_stream_end_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_document<F>(&mut self,
            version_directive: Option<YamlVersionDirective>,
            tag_directives: &[YamlTagDirective],
            implicit: bool,
            f: F) -> Result<(), YamlError> where
        F: Fn(&mut YamlEmitter) -> Result<(), YamlError>
    {
        try!(self.emit_document_start_event(version_directive, tag_directives, implicit));
        try!(f(self));
        self.emit_document_end_event(implicit)
    }

    fn emit_document_start_event(&mut self,
            version_directive: Option<YamlVersionDirective>,
            tag_directives: &[YamlTagDirective],
            implicit: bool)
        -> Result<(), YamlError>
    {
        let mut vsn_dir = ffi::yaml_version_directive_t { major: 0, minor: 0 };
        let c_vsn_dir = match version_directive {
            Some(directive) => {
                vsn_dir.major = directive.major as libc::c_int;
                vsn_dir.minor = directive.minor as libc::c_int;
                &vsn_dir as *const ffi::yaml_version_directive_t
            },
            None => ptr::null()
        };

        let c_strs: Vec<(CString, CString)> = tag_directives.iter().map(|tag| {
            (CString::from_slice(tag.handle.as_bytes()), CString::from_slice(tag.prefix.as_bytes()))
        }).collect();
        let c_tag_dirs: Vec<ffi::yaml_tag_directive_t> = c_strs.iter().map(|tuple| {
            ffi::yaml_tag_directive_t {
                handle: tuple.0.as_ptr(),
                prefix: tuple.1.as_ptr(),
            }
        }).collect();
        let tag_dir_start = c_tag_dirs.as_ptr();
        unsafe {
            let mut event = mem::uninitialized();
            let tag_dir_end = tag_dir_start.offset(c_tag_dirs.len() as isize);
            let c_implicit = if implicit { 1 } else { 0 };

            if ffi::yaml_document_start_event_initialize(&mut event, c_vsn_dir, tag_dir_start, tag_dir_end, c_implicit) == 0 {
                panic!("yaml_document_start_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    fn emit_document_end_event(&mut self, implicit: bool) -> Result<(), YamlError> {
        let c_implicit = if implicit { 1 } else { 0 };
        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_document_end_event_initialize(&mut event, c_implicit) == 0 {
                panic!("yaml_stream_end_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_alias_event(&mut self, anchor: &str) -> Result<(), YamlError> {
        let c_anchor = CString::from_slice(anchor.as_bytes());

        unsafe {
            let mut event = mem::uninitialized();

            let ptr = c_anchor.as_ptr();
            if ffi::yaml_alias_event_initialize(&mut event, ptr as *const ffi::yaml_char_t) != 0 {
                panic!("yaml_stream_end_event_initialize failed!")
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_scalar_event(&mut self, anchor: Option<&str>, tag: Option<&str>,
        value: &str, plain_implicit: bool, quoted_implicit: bool,
        style: ffi::YamlScalarStyle) -> Result<(), YamlError>
    {
        let c_anchor = anchor.map(|s| CString::from_slice(s.as_bytes()));
        let anchor_ptr = match c_anchor {
            Some(s) => s.as_ptr(),
            None => ptr::null()
        };
        let c_tag = tag.map(|s| CString::from_slice(s.as_bytes()));
        let tag_ptr = match c_tag {
            Some(s) => s.as_ptr(),
            None => ptr::null()
        };
        let c_plain_implicit = if plain_implicit { 1 } else { 0 };
        let c_quoted_implicit = if quoted_implicit { 1 } else { 0 };

        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_scalar_event_initialize(&mut event,
                    anchor_ptr as *const ffi::yaml_char_t, tag_ptr as *const ffi::yaml_char_t,
                    value.as_ptr(), value.len() as libc::c_int,
                    c_plain_implicit, c_quoted_implicit,
                    style) == 0
            {
                panic!("yaml_scalar_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_sequence<F>(&mut self, anchor: Option<&str>, tag: Option<&str>, implicit: bool,
            style: ffi::YamlSequenceStyle,
            f: F) -> Result<(), YamlError> where
        F: Fn(&mut YamlEmitter) -> Result<(), YamlError>
    {
        try!(self.emit_sequence_start_event(anchor, tag, implicit, style));
        try!(f(self));
        self.emit_sequence_end_event()
    }

    fn emit_sequence_start_event(&mut self, anchor: Option<&str>, tag: Option<&str>, implicit: bool,
        style: ffi::YamlSequenceStyle) -> Result<(), YamlError>
    {
        let c_anchor = anchor.map(|s| CString::from_slice(s.as_bytes()));
        let anchor_ptr = match c_anchor {
            Some(s) => s.as_ptr(),
            None => ptr::null()
        };
        let c_tag = tag.map(|s| CString::from_slice(s.as_bytes()));
        let tag_ptr = match c_tag {
            Some(s) => s.as_ptr(),
            None => ptr::null()
        };
        let c_implicit = if implicit { 1 } else { 0 };

        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_sequence_start_event_initialize(&mut event,
                    anchor_ptr as *const ffi::yaml_char_t, tag_ptr as *const ffi::yaml_char_t,
                    c_implicit, style) == 0
            {
                panic!("yaml_sequence_start_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    fn emit_sequence_end_event(&mut self) -> Result<(), YamlError> {
        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_sequence_end_event_initialize(&mut event) == 0 {
                panic!("yaml_sequence_end_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_mapping<F>(&mut self, anchor: Option<&str>, tag: Option<&str>, implicit: bool,
            style: ffi::YamlSequenceStyle,
            f: F) -> Result<(), YamlError> where
        F: Fn(&mut YamlEmitter) -> Result<(), YamlError>
    {
        try!(self.emit_mapping_start_event(anchor, tag, implicit, style));
        try!(f(self));
        self.emit_mapping_end_event()
    }

    fn emit_mapping_start_event(&mut self, anchor: Option<&str>, tag: Option<&str>, implicit: bool,
        style: ffi::YamlSequenceStyle) -> Result<(), YamlError>
    {
        let c_anchor = anchor.map(|s| CString::from_slice(s.as_bytes()));
        let anchor_ptr = match c_anchor {
            Some(s) => s.as_ptr(),
            None => ptr::null()
        };
        let c_tag = tag.map(|s| CString::from_slice(s.as_bytes()));
        let tag_ptr = match c_tag {
            Some(s) => s.as_ptr(),
            None => ptr::null()
        };
        let c_implicit = if implicit { 1 } else { 0 };

        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_mapping_start_event_initialize(&mut event,
                    anchor_ptr as *const ffi::yaml_char_t, tag_ptr as *const ffi::yaml_char_t,
                    c_implicit, style) == 0
            {
                panic!("yaml_mapping_start_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    fn emit_mapping_end_event(&mut self) -> Result<(), YamlError> {
        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_mapping_end_event_initialize(&mut event) == 0 {
                panic!("yaml_mapping_end_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn flush(&mut self) -> Result<(), YamlError> {
        unsafe {
            if ffi::yaml_emitter_flush(&mut self.base_emitter.emitter_mem) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }
}

extern fn handle_writer_cb(data: *mut YamlEmitter, buffer: *const u8, size: libc::size_t) -> libc::c_int {
    unsafe {
        let buf = slice::from_raw_parts(buffer, size as usize);
        let emitter = &mut *data;
        match emitter.writer.write_all(buf) {
            Ok(()) => 1,
            Err(err) => {
                emitter.io_error = Some(err);
                0
            }
        }
    }
}

#[cfg(test)]
mod test {
    use emitter::YamlEmitter;
    use ffi::YamlEncoding::YamlUtf8Encoding;
    use ffi::YamlScalarStyle::*;
    use ffi::YamlSequenceStyle::*;

    #[test]
    #[allow(unused_must_use)]
    fn event_emitter_sequence_test() {
        let mut writer = Vec::new();
        {
            let mut emitter = YamlEmitter::init(&mut writer);
            emitter.emit_stream(YamlUtf8Encoding, |e| {
                e.emit_document(None, &[], true, |e| {
                    e.emit_sequence(None, None, true, YamlFlowSequenceStyle, |e| {
                        try!(e.emit_scalar_event(None, None, "1", true, false, YamlPlainScalarStyle));
                        e.emit_scalar_event(None, None, "2", true, false, YamlPlainScalarStyle)
                    })
                })
            });
            emitter.flush();
        }
        assert_eq!(writer.as_slice(), b"[1, 2]\n");
    }

    #[test]
    #[allow(unused_must_use)]
    fn event_emitter_mapping_test() {
        let mut writer = Vec::new();
        {
            let mut emitter = YamlEmitter::init(&mut writer);
            emitter.emit_stream(YamlUtf8Encoding, |e| {
                e.emit_document(None, &[], true, |e| {
                    e.emit_mapping(None, None, true, YamlFlowSequenceStyle, |e| {
                        try!(e.emit_scalar_event(None, None, "a", true, false, YamlPlainScalarStyle));
                        try!(e.emit_scalar_event(None, None, "1", true, false, YamlPlainScalarStyle));
                        try!(e.emit_scalar_event(None, None, "b", true, false, YamlPlainScalarStyle));
                        e.emit_scalar_event(None, None, "2", true, false, YamlPlainScalarStyle)
                    })
                })
            });
            emitter.flush();
        }
        assert_eq!(writer.as_slice(), b"{a: 1, b: 2}\n");
    }
}
<|endoftext|>


<commit_before>use std::ops::{Add, Sub, Mul, Div, Rem};

// Predefined unit constants
const U_UNITS: usize = 1;

#[derive(Debug, Clone, Copy)]
pub struct RichNumber {
    value: f64,
    unit: usize,
}

impl RichNumber {
    pub fn new(value: f64, unit: usize) -> RichNumber {
        RichNumber {
            value: value as f64,
            unit: unit,
        }
    }

    pub fn zero() -> RichNumber {
        RichNumber::from(0f64)
    }

    /// Attempts to coerce two values into a common unit
    /// Returns (converted self, converted other, common unit)
    fn coerce(&self, other: &RichNumber) -> (f64, f64, usize) {
        //TODO: Convert between units
        (self.value, other.value, U_UNITS)
    }

    /// Applies an operator to two values given the values and their common unit
    fn apply_operator<F, R>(self, other: RichNumber, operator: F) -> R
        where F: FnOnce(f64, f64, usize) -> R {

        let (value, other_value, unit) = self.coerce(&other);
        operator(value, other_value, unit)
    }

    /// Converts self and other into a common or compatible unit and then performs the given operation
    /// operator is given the two values in order and the common unit
    /// Returns a RichNumber with the new value and the common unit
    fn apply_numeric_operator<F>(self, other: RichNumber, operator: F) -> RichNumber
        where F: FnOnce(f64, f64, usize) -> f64 {

        let (value, other_value, unit) = self.coerce(&other);
        RichNumber::new(operator(value, other_value, unit), unit)
    }
}

impl From<i64> for RichNumber {
    fn from(number: i64) -> RichNumber {
        RichNumber::new(number as f64, U_UNITS)
    }
}

impl From<f64> for RichNumber {
    fn from(number: f64) -> RichNumber {
        RichNumber::new(number, U_UNITS)
    }
}

impl PartialEq for RichNumber {
    fn eq(&self, other: &RichNumber) -> bool {
        let (value, other_value, _) = self.coerce(other);

        (value - other_value).abs() < 1e-10
    }
}

impl Add for RichNumber {
    type Output = RichNumber;

    fn add(self, other: RichNumber) -> Self::Output {
        self.apply_numeric_operator(other, |a, b, _| a + b)
    }
}

impl Sub for RichNumber {
    type Output = RichNumber;

    fn sub(self, other: RichNumber) -> Self::Output {
        self.apply_numeric_operator(other, |a, b, _| a - b)
    }
}

impl Mul for RichNumber {
    type Output = RichNumber;

    fn mul(self, other: RichNumber) -> Self::Output {
        self.apply_numeric_operator(other, |a, b, _| a * b)
    }
}

impl Div for RichNumber {
    type Output = RichNumber;

    fn div(self, other: RichNumber) -> Self::Output {
        self.apply_numeric_operator(other, |a, b, _| a / b)
    }
}

impl Rem for RichNumber {
    type Output = RichNumber;

    fn rem(self, other: RichNumber) -> Self::Output {
        self.apply_numeric_operator(other, |a, b, _| a % b)
    }
}

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

    #[test]
    fn equality() {
        let a = RichNumber::from(2);
        let b = RichNumber::from(2);
        let c = RichNumber::from(3.6);

        assert_eq!(a, b);
        assert!(a != c);
    }

    #[test]
    fn basic_operations() {
        let a = RichNumber::from(2);
        let b = RichNumber::from(3.6);

        assert_eq!(a + b, RichNumber::from(5.6f64));
        assert_eq!(b + a, RichNumber::from(5.6f64));

        assert_eq!(a - b, RichNumber::from(-1.6f64));
        assert_eq!(b - a, RichNumber::from(1.6f64));

        assert_eq!(a * b, RichNumber::from(7.2f64));
        assert_eq!(b * a, RichNumber::from(7.2f64));

        assert_eq!(a / b, RichNumber::from(0.55555555555f64));
        assert_eq!(b / a, RichNumber::from(1.8f64));

        assert_eq!(a % b, RichNumber::from(2f64));
        assert_eq!(b % a, RichNumber::from(1.6f64));
    }
}

<commit_msg>Implmemented pow<commit_after>use std::ops::{Add, Sub, Mul, Div, Rem};

// Predefined unit constants
const U_UNITS: usize = 1;

#[derive(Debug, Clone, Copy)]
pub struct RichNumber {
    value: f64,
    unit: usize,
}

impl RichNumber {
    pub fn new(value: f64, unit: usize) -> RichNumber {
        RichNumber {
            value: value as f64,
            unit: unit,
        }
    }

    pub fn zero() -> RichNumber {
        RichNumber::from(0f64)
    }

    pub fn is_unit_units(&self) -> bool {
        self.unit == U_UNITS
    }

    pub fn pow(&self, other: RichNumber) -> RichNumber {
        //TODO: Need to raise units to the power of somehow
        assert!(self.is_unit_units());
        assert!(other.is_unit_units());

        RichNumber::from(self.value.powf(other.value))
    }

    /// Attempts to coerce two values into a common unit
    /// Returns (converted self, converted other, common unit)
    fn coerce(&self, other: &RichNumber) -> (f64, f64, usize) {
        //TODO: Convert between units
        (self.value, other.value, U_UNITS)
    }

    /// Applies an operator to two values given the values and their common unit
    fn apply_operator<F, R>(self, other: RichNumber, operator: F) -> R
        where F: FnOnce(f64, f64, usize) -> R {

        let (value, other_value, unit) = self.coerce(&other);
        operator(value, other_value, unit)
    }

    /// Converts self and other into a common or compatible unit and then performs the given operation
    /// operator is given the two values in order and the common unit
    /// Returns a RichNumber with the new value and the common unit
    fn apply_numeric_operator<F>(self, other: RichNumber, operator: F) -> RichNumber
        where F: FnOnce(f64, f64, usize) -> f64 {

        let (value, other_value, unit) = self.coerce(&other);
        RichNumber::new(operator(value, other_value, unit), unit)
    }
}

impl From<i64> for RichNumber {
    fn from(number: i64) -> RichNumber {
        RichNumber::new(number as f64, U_UNITS)
    }
}

impl From<f64> for RichNumber {
    fn from(number: f64) -> RichNumber {
        RichNumber::new(number, U_UNITS)
    }
}

impl PartialEq for RichNumber {
    fn eq(&self, other: &RichNumber) -> bool {
        let (value, other_value, _) = self.coerce(other);

        (value - other_value).abs() < 1e-10
    }
}

impl Add for RichNumber {
    type Output = RichNumber;

    fn add(self, other: RichNumber) -> Self::Output {
        self.apply_numeric_operator(other, |a, b, _| a + b)
    }
}

impl Sub for RichNumber {
    type Output = RichNumber;

    fn sub(self, other: RichNumber) -> Self::Output {
        self.apply_numeric_operator(other, |a, b, _| a - b)
    }
}

impl Mul for RichNumber {
    type Output = RichNumber;

    fn mul(self, other: RichNumber) -> Self::Output {
        self.apply_numeric_operator(other, |a, b, _| a * b)
    }
}

impl Div for RichNumber {
    type Output = RichNumber;

    fn div(self, other: RichNumber) -> Self::Output {
        self.apply_numeric_operator(other, |a, b, _| a / b)
    }
}

impl Rem for RichNumber {
    type Output = RichNumber;

    fn rem(self, other: RichNumber) -> Self::Output {
        self.apply_numeric_operator(other, |a, b, _| a % b)
    }
}

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

    #[test]
    fn equality() {
        let a = RichNumber::from(2);
        let b = RichNumber::from(2);
        let c = RichNumber::from(3.6);

        assert_eq!(a, b);
        assert!(a != c);
    }

    #[test]
    fn basic_operations() {
        let a = RichNumber::from(2);
        let b = RichNumber::from(3.6);

        assert_eq!(a + b, RichNumber::from(5.6f64));
        assert_eq!(b + a, RichNumber::from(5.6f64));

        assert_eq!(a - b, RichNumber::from(-1.6f64));
        assert_eq!(b - a, RichNumber::from(1.6f64));

        assert_eq!(a * b, RichNumber::from(7.2f64));
        assert_eq!(b * a, RichNumber::from(7.2f64));

        assert_eq!(a / b, RichNumber::from(0.55555555555f64));
        assert_eq!(b / a, RichNumber::from(1.8f64));

        assert_eq!(a % b, RichNumber::from(2f64));
        assert_eq!(b % a, RichNumber::from(1.6f64));
    }
}

<|endoftext|>


<commit_before>// Copyright (c) <2015> <lummax>
// Licensed under MIT (http://opensource.org/licenses/MIT)

#![feature(libc)]

extern crate wayland_client;
extern crate tempfile;
extern crate libc;

use std::{ptr, cmp};
use std::num::Wrapping;
use std::io::Result;
use std::os::unix::io::AsRawFd;

use tempfile::TempFile;

use wayland_client::client::{Display, Compositor, Shell, Shm, ShmFormat, Surface,
                             Registry, RegistryEventHandler,
                             ShellSurface, ShellSurfaceEventHandler,
                             Buffer, BufferEventHandler,
                             Callback, CallbackEventHandler};

struct MyRegistry {
    registry: Registry,
    compositor: Option<Compositor>,
    shell: Option<Shell>,
    shm: Option<Shm>,
}

impl MyRegistry {
    fn new(display: &mut Display) -> Box<MyRegistry> {
        let registry = display.get_registry().unwrap();
        return Box::new(MyRegistry {
            registry: registry,
            compositor: None,
            shell: None,
            shm: None,
        });
    }

    fn take_compositor(&mut self) -> Compositor {
        return self.compositor.take().unwrap();
    }

    fn take_shell(&mut self) -> Shell {
        return self.shell.take().unwrap();
    }

    fn take_shm(&mut self) -> Shm {
        return self.shm.take().unwrap();
    }
}

impl RegistryEventHandler for MyRegistry {
    fn get_registry(&mut self) -> &mut Registry {
        return &mut self.registry;
    }

    fn on_global(&mut self, name: u32, interface: String, version: u32) {
        if interface == "wl_compositor" {
            self.compositor = self.registry.bind(name, version).ok();
        } else if interface == "wl_shell" {
            self.shell = self.registry.bind(name, version).ok();
        } else if interface == "wl_shm" {
            self.shm = self.registry.bind(name, version).ok();
        }
    }
}

struct MyShellSurface {
    pub shell_surface: ShellSurface,
}

impl MyShellSurface {
    fn new(shell: &mut Shell, surface: &mut Surface) -> Box<MyShellSurface> {
        let mut shell_surface = shell.get_shell_surface(surface).unwrap();
        shell_surface.set_title("simple shm");
        shell_surface.set_toplevel();
        return Box::new(MyShellSurface {
            shell_surface: shell_surface,
        });
    }
}

impl ShellSurfaceEventHandler for MyShellSurface {
    fn get_shell_surface(&mut self) -> &mut ShellSurface {
        return &mut self.shell_surface;
    }

    fn on_ping(&mut self, serial: u32) {
        self.shell_surface.pong(serial);
    }
}

struct MyBuffer {
    buffer: Buffer,
    _file: TempFile,
    memory: *mut libc::c_void,
    size: i32,
    busy: bool,
}

impl MyBuffer {
    fn new(width: i32, height: i32, shm: &mut Shm) -> Result<Box<MyBuffer>> {
        let size = width * height * 4;
        let file = try!(TempFile::new());
        file.set_len(size as u64).unwrap();

        let memory = unsafe {
            libc::mmap(ptr::null_mut(), size as libc::size_t,
                       libc::PROT_WRITE | libc::PROT_READ,
                       libc::MAP_SHARED | libc::MAP_FILE,
                       file.as_raw_fd(), 0)
        };

        if memory == libc::MAP_FAILED {
            panic!("Failed to allocate the memory map");
        }

        let mut pool = shm.create_pool(file.as_raw_fd(), size).unwrap();
        let buffer = pool.create_buffer(0, width, height, width * 4,
                                        ShmFormat::Xrgb8888 as u32).unwrap();
        pool.destroy();
        return Ok(Box::new(MyBuffer {
            buffer: buffer,
            _file: file,
            memory: memory,
            size: size,
            busy: false,
        }));
    }

    fn is_not_busy(&self) -> bool {
        return !self.busy;
    }

    fn set_busy(&mut self) {
        self.busy = true;
    }

    fn get_pointer(&mut self) -> *mut u32 {
        return self.memory as *mut u32;
    }
}

impl BufferEventHandler for MyBuffer {
    fn get_buffer(&mut self) -> &mut Buffer {
        return &mut self.buffer;
    }

    fn on_release(&mut self) {
        self.busy = false;
    }
}

impl Drop for MyBuffer {
    fn drop(&mut self) {
        unsafe {
            libc::munmap(self.memory as *mut libc::c_void,
                         self.size as libc::size_t);
        }
    }
}

struct Window {
    width: i32,
    height: i32,
    surface: Surface,
    frame: Option<Callback>,
    first_buffer: Box<MyBuffer>,
    second_buffer: Box<MyBuffer>,
}

impl Window {
    fn new(mut shm: Shm, mut surface: Surface, width: i32, height: i32) -> Window {
        surface.damage(0, 0, width, height);
        let mut first_buffer = MyBuffer::new(width, height, &mut shm).unwrap();
        first_buffer.connect_dispatcher();
        let mut second_buffer = MyBuffer::new(width, height, &mut shm).unwrap();
        second_buffer.connect_dispatcher();
        return Window {
            width: width,
            height: height,
            surface: surface,
            frame: None,
            first_buffer: first_buffer,
            second_buffer: second_buffer,
        };
    }

    fn paint_pixels(&mut self, use_first_buffer: bool, time: i32) {
        let padding = 20;

        let halfh = padding + (self.height - padding * 2) / 2;
        let halfw = padding + (self.width  - padding * 2) / 2;

        let or = (cmp::min(halfw, halfh) - 8).pow(2);
        let ir = (cmp::min(halfw, halfh) - 40).pow(2);

        let mut pointer = if use_first_buffer { self.first_buffer.get_pointer() }
                          else { self.second_buffer.get_pointer() };

        pointer = unsafe { pointer.offset((padding * self.width) as isize)};

        for y in (20 .. self.height - padding) {
            let y2 = (y - halfh) * (y - halfh);

            pointer = unsafe { pointer.offset(padding as isize)};
            for x in (20 .. self.width - 20) {
                let r2 = (x - halfw) * (x - halfw) + y2;

                let v = Wrapping(if r2 < ir { (r2 / 32 + time / 64) }
                                 else if r2 < or { (y + time / 32) }
                                 else { (x + time / 16) } as u32)
                        * Wrapping(0x0080401);
                let mut v2 = v.0 & 0x00ffffff;

                if (x - y).abs() > 6 && (x + y - self.height).abs() > 6 {
                    v2 |= 0xff000000;
                }

                pointer = unsafe { pointer.offset(1)};
                unsafe { *pointer = v2; }
            }
            pointer = unsafe { pointer.offset(padding as isize)};
        }
    }

    fn redraw(&mut self, time: i32) {
        let use_first_buffer = if self.first_buffer.is_not_busy() { true }
                        else if self.second_buffer.is_not_busy() { false }
                        else { panic!("no buffers free") };

        if use_first_buffer { self.first_buffer.set_busy(); }
        else { self.second_buffer.set_busy(); }

        self.paint_pixels(use_first_buffer, time);

        if use_first_buffer { self.surface.attach(self.first_buffer.get_buffer(), 0, 0); }
        else { self.surface.attach(self.second_buffer.get_buffer(), 0, 0); }

        self.surface.damage(20, 20, self.width - 20, self.height - 20);
        self.frame = Some(self.surface.frame().unwrap());
        self.connect_dispatcher();
        self.surface.commit();
    }
}

impl CallbackEventHandler for Window {
    fn get_callback<'a>(&'a mut self) -> &'a mut Callback {
        return self.frame.as_mut().unwrap();
    }

    fn on_done(&mut self, callback_data: u32) {
        self.frame = None;
        self.redraw(callback_data as i32);
    }
}

fn main() {
    let mut display = Display::connect(None).unwrap();
    let mut registry = MyRegistry::new(&mut display);
    registry.connect_dispatcher();
    display.roundtrip();

    let shm = registry.take_shm();
    let mut shell = registry.take_shell();
    let mut compositor = registry.take_compositor();

    let mut surface = compositor.create_surface().unwrap();
    let mut shell_surface = MyShellSurface::new(&mut shell, &mut surface);
    shell_surface.connect_dispatcher();

    let mut window = Window::new(shm, surface, 250, 250);
    window.redraw(0);

    loop { display.dispatch(); }
}
<commit_msg>simple-shm: fix after allow_null update<commit_after>// Copyright (c) <2015> <lummax>
// Licensed under MIT (http://opensource.org/licenses/MIT)

#![feature(libc)]

extern crate wayland_client;
extern crate tempfile;
extern crate libc;

use std::{ptr, cmp};
use std::num::Wrapping;
use std::io::Result;
use std::os::unix::io::AsRawFd;

use tempfile::TempFile;

use wayland_client::client::{Display, Compositor, Shell, Shm, ShmFormat, Surface,
                             Registry, RegistryEventHandler,
                             ShellSurface, ShellSurfaceEventHandler,
                             Buffer, BufferEventHandler,
                             Callback, CallbackEventHandler};

struct MyRegistry {
    registry: Registry,
    compositor: Option<Compositor>,
    shell: Option<Shell>,
    shm: Option<Shm>,
}

impl MyRegistry {
    fn new(display: &mut Display) -> Box<MyRegistry> {
        let registry = display.get_registry().unwrap();
        return Box::new(MyRegistry {
            registry: registry,
            compositor: None,
            shell: None,
            shm: None,
        });
    }

    fn take_compositor(&mut self) -> Compositor {
        return self.compositor.take().unwrap();
    }

    fn take_shell(&mut self) -> Shell {
        return self.shell.take().unwrap();
    }

    fn take_shm(&mut self) -> Shm {
        return self.shm.take().unwrap();
    }
}

impl RegistryEventHandler for MyRegistry {
    fn get_registry(&mut self) -> &mut Registry {
        return &mut self.registry;
    }

    fn on_global(&mut self, name: u32, interface: String, version: u32) {
        if interface == "wl_compositor" {
            self.compositor = self.registry.bind(name, version).ok();
        } else if interface == "wl_shell" {
            self.shell = self.registry.bind(name, version).ok();
        } else if interface == "wl_shm" {
            self.shm = self.registry.bind(name, version).ok();
        }
    }
}

struct MyShellSurface {
    pub shell_surface: ShellSurface,
}

impl MyShellSurface {
    fn new(shell: &mut Shell, surface: &mut Surface) -> Box<MyShellSurface> {
        let mut shell_surface = shell.get_shell_surface(surface).unwrap();
        shell_surface.set_title("simple shm");
        shell_surface.set_toplevel();
        return Box::new(MyShellSurface {
            shell_surface: shell_surface,
        });
    }
}

impl ShellSurfaceEventHandler for MyShellSurface {
    fn get_shell_surface(&mut self) -> &mut ShellSurface {
        return &mut self.shell_surface;
    }

    fn on_ping(&mut self, serial: u32) {
        self.shell_surface.pong(serial);
    }
}

struct MyBuffer {
    buffer: Buffer,
    _file: TempFile,
    memory: *mut libc::c_void,
    size: i32,
    busy: bool,
}

impl MyBuffer {
    fn new(width: i32, height: i32, shm: &mut Shm) -> Result<Box<MyBuffer>> {
        let size = width * height * 4;
        let file = try!(TempFile::new());
        file.set_len(size as u64).unwrap();

        let memory = unsafe {
            libc::mmap(ptr::null_mut(), size as libc::size_t,
                       libc::PROT_WRITE | libc::PROT_READ,
                       libc::MAP_SHARED | libc::MAP_FILE,
                       file.as_raw_fd(), 0)
        };

        if memory == libc::MAP_FAILED {
            panic!("Failed to allocate the memory map");
        }

        let mut pool = shm.create_pool(file.as_raw_fd(), size).unwrap();
        let buffer = pool.create_buffer(0, width, height, width * 4,
                                        ShmFormat::Xrgb8888 as u32).unwrap();
        pool.destroy();
        return Ok(Box::new(MyBuffer {
            buffer: buffer,
            _file: file,
            memory: memory,
            size: size,
            busy: false,
        }));
    }

    fn is_not_busy(&self) -> bool {
        return !self.busy;
    }

    fn set_busy(&mut self) {
        self.busy = true;
    }

    fn get_pointer(&mut self) -> *mut u32 {
        return self.memory as *mut u32;
    }
}

impl BufferEventHandler for MyBuffer {
    fn get_buffer(&mut self) -> &mut Buffer {
        return &mut self.buffer;
    }

    fn on_release(&mut self) {
        self.busy = false;
    }
}

impl Drop for MyBuffer {
    fn drop(&mut self) {
        unsafe {
            libc::munmap(self.memory as *mut libc::c_void,
                         self.size as libc::size_t);
        }
    }
}

struct Window {
    width: i32,
    height: i32,
    surface: Surface,
    frame: Option<Callback>,
    first_buffer: Box<MyBuffer>,
    second_buffer: Box<MyBuffer>,
}

impl Window {
    fn new(mut shm: Shm, mut surface: Surface, width: i32, height: i32) -> Window {
        surface.damage(0, 0, width, height);
        let mut first_buffer = MyBuffer::new(width, height, &mut shm).unwrap();
        first_buffer.connect_dispatcher();
        let mut second_buffer = MyBuffer::new(width, height, &mut shm).unwrap();
        second_buffer.connect_dispatcher();
        return Window {
            width: width,
            height: height,
            surface: surface,
            frame: None,
            first_buffer: first_buffer,
            second_buffer: second_buffer,
        };
    }

    fn paint_pixels(&mut self, use_first_buffer: bool, time: i32) {
        let padding = 20;

        let halfh = padding + (self.height - padding * 2) / 2;
        let halfw = padding + (self.width  - padding * 2) / 2;

        let or = (cmp::min(halfw, halfh) - 8).pow(2);
        let ir = (cmp::min(halfw, halfh) - 40).pow(2);

        let mut pointer = if use_first_buffer { self.first_buffer.get_pointer() }
                          else { self.second_buffer.get_pointer() };

        pointer = unsafe { pointer.offset((padding * self.width) as isize)};

        for y in (20 .. self.height - padding) {
            let y2 = (y - halfh) * (y - halfh);

            pointer = unsafe { pointer.offset(padding as isize)};
            for x in (20 .. self.width - 20) {
                let r2 = (x - halfw) * (x - halfw) + y2;

                let v = Wrapping(if r2 < ir { (r2 / 32 + time / 64) }
                                 else if r2 < or { (y + time / 32) }
                                 else { (x + time / 16) } as u32)
                        * Wrapping(0x0080401);
                let mut v2 = v.0 & 0x00ffffff;

                if (x - y).abs() > 6 && (x + y - self.height).abs() > 6 {
                    v2 |= 0xff000000;
                }

                pointer = unsafe { pointer.offset(1)};
                unsafe { *pointer = v2; }
            }
            pointer = unsafe { pointer.offset(padding as isize)};
        }
    }

    fn redraw(&mut self, time: i32) {
        let use_first_buffer = if self.first_buffer.is_not_busy() { true }
                        else if self.second_buffer.is_not_busy() { false }
                        else { panic!("no buffers free") };

        if use_first_buffer { self.first_buffer.set_busy(); }
        else { self.second_buffer.set_busy(); }

        self.paint_pixels(use_first_buffer, time);

        if use_first_buffer { self.surface.attach(Some(self.first_buffer.get_buffer()), 0, 0); }
        else { self.surface.attach(Some(self.second_buffer.get_buffer()), 0, 0); }

        self.surface.damage(20, 20, self.width - 20, self.height - 20);
        self.frame = Some(self.surface.frame().unwrap());
        self.connect_dispatcher();
        self.surface.commit();
    }
}

impl CallbackEventHandler for Window {
    fn get_callback<'a>(&'a mut self) -> &'a mut Callback {
        return self.frame.as_mut().unwrap();
    }

    fn on_done(&mut self, callback_data: u32) {
        self.frame = None;
        self.redraw(callback_data as i32);
    }
}

fn main() {
    let mut display = Display::connect(None).unwrap();
    let mut registry = MyRegistry::new(&mut display);
    registry.connect_dispatcher();
    display.roundtrip();

    let shm = registry.take_shm();
    let mut shell = registry.take_shell();
    let mut compositor = registry.take_compositor();

    let mut surface = compositor.create_surface().unwrap();
    let mut shell_surface = MyShellSurface::new(&mut shell, &mut surface);
    shell_surface.connect_dispatcher();

    let mut window = Window::new(shm, surface, 250, 250);
    window.redraw(0);

    loop { display.dispatch(); }
}
<|endoftext|>