<commit_before>use circular::Buffer;
use err_derive::Error;
use nom::{Err, Offset};
use std::env;
use std::fs::File;
use std::io::{self, Read};

use matroska::ebml::ebml_header;
use matroska::elements::{segment, segment_element, SegmentElement};
use matroska::serializer::ebml::EbmlSize;

#[derive(Debug, Error)]
pub enum InfoError {
    #[error(display = "expected file path")]
    NoPathReceived,
    #[error(display = "no more data to read or parse")]
    NoMoreData,
    #[error(display = "unable to parse header")]
    ParseHeader,
    #[error(display = "already got a SeekHead element")]
    SeekHeadElement,
    #[error(display = "already got an Info element")]
    InfoElement,
    #[error(display = "already got a Tracks element")]
    TracksElement,
    #[error(display = "unexpected element: {}", _0)]
    UnexpectedElement(String),
    #[error(display = "offset {:X?}: got unknown element: {:X?} {:#?}", _0, _1, _2)]
    UnknownElement(usize, u64, Option<u64>),
    #[error(display = "failed parsing: {}", _0)]
    Parse(String),
    #[error(display = "could not read the file: {}", _0)]
    Io(#[error(cause)] io::Error),
}

fn main() -> Result<(), InfoError> {
    pretty_env_logger::init();
    let mut args = env::args();
    let _ = args.next().expect("first arg is program path");
    let filename = args.next().ok_or(InfoError::NoPathReceived)?;

    run(&filename)
}

fn run(filename: &str) -> Result<(), InfoError> {
    let mut file = File::open(filename)?;

    let capacity = 5_242_880;
    let mut b = Buffer::with_capacity(capacity);

    // we write into the `&mut[u8]` returned by `space()`
    let sz = file.read(b.space())?;
    b.fill(sz);

    let length = {
        let res = ebml_header(b.data());
        if let Ok((remaining, header)) = res {
            println!("+ EBML head");
            println!("|+ EBML version: {}", header.version);
            println!("|+ EBML read version: {}", header.read_version);
            println!("|+ EBML maximum ID length: {}", header.max_id_length);
            println!("|+ EBML maximum size length: {}", header.max_size_length);
            println!("|+ Document type: {}", header.doc_type);
            println!("|+ Document type version: {}", header.doc_type_version);
            println!(
                "|+ Document type read version: {}",
                header.doc_type_read_version
            );

            b.data().offset(remaining)
        } else {
            return Err(InfoError::ParseHeader);
        }
    };

    let mut _consumed = length;
    b.consume(length);

    let length = {
        let res = segment(b.data());
        if let Ok((remaining, segment)) = res {
            println!("+ Segment, size {}", segment.1.unwrap_or(0));

            b.data().offset(remaining)
        } else {
            return Err(InfoError::ParseHeader);
        }
    };

    b.consume(length);

    // handle first elements
    let mut seek_head = None;
    let mut info = None;
    let mut tracks = None;

    loop {
        if seek_head.is_some() && info.is_some() && tracks.is_some() {
            break;
        }

        if b.available_space() == 0 {
            b.shift();
            if b.available_space() == 0 {
                println!("buffer is already full, cannot refill");
                break;
            }
        }

        // refill the buffer
        let sz = file.read(b.space())?;
        b.fill(sz);

        // if there's no more available data in the buffer after a write, that means we reached
        // the end of the file
        if b.available_data() == 0 {
            return Err(InfoError::NoMoreData);
        }

        let offset = {
            let (i, element) = match segment_element(b.data()) {
                Ok((i, o)) => (i, o),
                Err(Err::Error(e)) | Err(Err::Failure(e)) => {
                    return Err(InfoError::Parse(format!("{:?}", e)))
                }
                Err(Err::Incomplete(_i)) => continue,
            };

            match element {
                SegmentElement::SeekHead(s) => {
                    println!("|+ Seek head at {:#0x} size {}", 0x0, b.data().offset(i));
                    for seek in s.positions.iter() {
                        let _id: u64 = (u64::from(seek.id[0]) << 24)
                            | (u64::from(seek.id[1]) << 16)
                            | (u64::from(seek.id[2]) << 8)
                            | u64::from(seek.id[3]);

                        let element_size = seek.size(0x4DBB);
                        let id_size = seek.id.size(0x53AB);
                        let position_size = seek.position.size(0x53AC);

                        println!("| + Seek entry size {}", element_size);

                        print!("|  + Seek ID:");
                        for id in seek.id.iter() {
                            print!(" {:#0x}", id);
                        }

                        let name = match &seek.id[..] {
                            [0x11, 0x4D, 0x9B, 0x74] => " (KaxSeekHead)",
                            [0x12, 0x54, 0xC3, 0x67] => " (KaxTags)",
                            [0x15, 0x49, 0xA9, 0x66] => " (KaxInfo)",
                            [0x16, 0x54, 0xAE, 0x6B] => " (KaxTracks)",
                            [0x1C, 0x53, 0xBB, 0x6B] => " (KaxCues)",
                            [0x1F, 0x43, 0xB6, 0x75] => " (KaxCluster)",
                            _ => "",
                        };

                        println!("{} at {:#0x} size {}", name, 0x0, id_size);
                        println!(
                            "|  + Seek position: {} size {}",
                            seek.position, position_size
                        );
                    }

                    if seek_head.is_some() {
                        return Err(InfoError::SeekHeadElement);
                    } else {
                        seek_head = Some(s);
                    }
                }
                SegmentElement::Info(i) => {
                    println!("|+ Segment information");
                    println!("| + Timestamp scale: {}", i.timecode_scale);
                    println!("| + Multiplexing application: {}", i.muxing_app);
                    println!("| + Writing application: {}", i.writing_app);
                    println!(
                        "| + Segment UID: {:?}",
                        i.segment_uid.as_ref().unwrap_or(&Vec::new())
                    );
                    println!("| + Duration: {}s", i.duration.unwrap_or(0f64) / 1000f64);
                    if info.is_some() {
                        return Err(InfoError::InfoElement);
                    } else {
                        info = Some(i);
                    }
                }
                SegmentElement::Tracks(t) => {
                    //eprintln!("got tracks: {:#?}", t);
                    println!("|+ Segment tracks");
                    for tr in t.tracks.iter() {
                        println!("| + A track");
                        println!("|  + Track number: {}", tr.track_number);
                        println!("|  + Track UID: {}", tr.track_uid);
                        println!("|  + Track type: {}", tr.track_type);
                        println!("|  + Lacing flag: {}", tr.flag_lacing.unwrap_or(0));
                        println!("|  + Default flag: {}", tr.flag_default.unwrap_or(0));
                        println!(
                            "|  + Language: {}",
                            tr.language.as_ref().unwrap_or(&"".to_string())
                        );
                        println!("|  + Codec ID: {}", tr.codec_id);
                        println!(
                            "|  + Codec private: length {}",
                            tr.codec_private.as_ref().map(|v| v.len()).unwrap_or(0)
                        );

                        if let Some(ref v) = tr.video {
                            println!("|  + Video track");
                            println!("|    + Pixel width: {}", v.pixel_width);
                            println!("|    + Pixel height: {}", v.pixel_height);
                            if let Some(inter) = v.flag_interlaced {
                                println!("|    + Interlaced: {}", inter);
                            }
                            if let Some(width) = v.display_width {
                                println!("|    + Display width: {}", width);
                            }
                            if let Some(height) = v.display_height {
                                println!("|    + Display height: {}", height);
                            }
                            if let Some(unit) = v.display_unit {
                                println!("|    + Display unit: {}", unit);
                            }
                        }

                        if let Some(ref a) = tr.audio {
                            println!("|  + Audio track");
                            println!("|    + Sampling frequency: {}", a.sampling_frequency);
                            if let Some(frequency) = a.output_sampling_frequency {
                                println!("|    + Output sampling freqeuncy: {}", frequency);
                            }
                            println!("|    + Channels: {}", a.channels);
                            if let Some(ref channel_positions) = a.channel_positions {
                                println!("|    + Channel position: {:?}", channel_positions);
                            }
                            if let Some(bit_depth) = a.bit_depth {
                                println!("|    + Bit depth: {}", bit_depth);
                            }
                        }
                    }
                    if tracks.is_some() {
                        return Err(InfoError::TracksElement);
                    } else {
                        tracks = Some(t);
                    }
                }
                SegmentElement::Void(s) => {
                    println!("|+ EbmlVoid (size: {})", s);
                }
                el => return Err(InfoError::UnexpectedElement(format!("{:?}", el))),
            }

            b.data().offset(i)
        };
        _consumed += offset;
        b.consume(offset);
    }

    loop {
        if b.available_space() == 0 {
            b.shift();
            if b.available_space() == 0 {
                println!("buffer is already full,  cannot refill");
                break;
            }
        }

        // refill the buffer
        let sz = file.read(b.space())?;
        b.fill(sz);

        // if there's no more available data in the buffer after a write, that means we reached
        // the end of the file
        if b.available_data() == 0 {
            //panic!("no more data to read or parse, stopping the reading loop");
            break;
        }

        let offset = {
            let (i, element) = match segment_element(b.data()) {
                Ok((i, o)) => (i, o),
                Err(Err::Error(e)) | Err(Err::Failure(e)) => {
                    return Err(InfoError::Parse(format!("{:?}", e)))
                }
                Err(Err::Incomplete(_)) => continue,
            };

            match element {
                SegmentElement::SeekHead(_)
                | SegmentElement::Info(_)
                | SegmentElement::Tracks(_) => {
                    return Err(InfoError::UnexpectedElement(
                        "seek head, info or tracks element".to_string(),
                    ));
                }
                SegmentElement::Cluster(c) => {
                    println!("|+ Cluster");
                    println!("|+   Timecode: {}", c.timecode);
                    println!("|+   Silent_tracks: {:?}", c.silent_tracks);
                    println!("|+   Position: {:?}", c.position);
                    println!("|+   Prev size: {:?}", c.prev_size);
                    println!("|+   Simple block: {} elements", c.simple_block.len());
                    println!("|+   Block group: {} elements", c.block_group.len());
                    println!(
                        "|+   Encrypted block: {:?} bytes",
                        c.encrypted_block.as_ref().map(|s| s.len())
                    );
                }
                SegmentElement::Void(s) => {
                    println!("|+ EbmlVoid (size: {})", s);
                }
                SegmentElement::Tags(_) => {
                    println!("|+ Tags");
                }
                SegmentElement::Cues(_) => {
                    println!("|+ Cues");
                }
                SegmentElement::Unknown(id, data) => {
                    return Err(InfoError::UnknownElement(_consumed, id, data))
                }
                el => return Err(InfoError::UnexpectedElement(format!("{:?}", el))),
            }

            b.data().offset(i)
        };
        _consumed += offset;
        b.consume(offset);
    }

    Ok(())
}
<commit_msg>tools: Reorder crates<commit_after>use std::env;
use std::fs::File;
use std::io::{self, Read};

use circular::Buffer;
use err_derive::Error;
use nom::{Err, Offset};

use matroska::ebml::ebml_header;
use matroska::elements::{segment, segment_element, SegmentElement};
use matroska::serializer::ebml::EbmlSize;

#[derive(Debug, Error)]
pub enum InfoError {
    #[error(display = "expected file path")]
    NoPathReceived,
    #[error(display = "no more data to read or parse")]
    NoMoreData,
    #[error(display = "unable to parse header")]
    ParseHeader,
    #[error(display = "already got a SeekHead element")]
    SeekHeadElement,
    #[error(display = "already got an Info element")]
    InfoElement,
    #[error(display = "already got a Tracks element")]
    TracksElement,
    #[error(display = "unexpected element: {}", _0)]
    UnexpectedElement(String),
    #[error(display = "offset {:X?}: got unknown element: {:X?} {:#?}", _0, _1, _2)]
    UnknownElement(usize, u64, Option<u64>),
    #[error(display = "failed parsing: {}", _0)]
    Parse(String),
    #[error(display = "could not read the file: {}", _0)]
    Io(#[error(cause)] io::Error),
}

fn main() -> Result<(), InfoError> {
    pretty_env_logger::init();
    let mut args = env::args();
    let _ = args.next().expect("first arg is program path");
    let filename = args.next().ok_or(InfoError::NoPathReceived)?;

    run(&filename)
}

fn run(filename: &str) -> Result<(), InfoError> {
    let mut file = File::open(filename)?;

    let capacity = 5_242_880;
    let mut b = Buffer::with_capacity(capacity);

    // we write into the `&mut[u8]` returned by `space()`
    let sz = file.read(b.space())?;
    b.fill(sz);

    let length = {
        let res = ebml_header(b.data());
        if let Ok((remaining, header)) = res {
            println!("+ EBML head");
            println!("|+ EBML version: {}", header.version);
            println!("|+ EBML read version: {}", header.read_version);
            println!("|+ EBML maximum ID length: {}", header.max_id_length);
            println!("|+ EBML maximum size length: {}", header.max_size_length);
            println!("|+ Document type: {}", header.doc_type);
            println!("|+ Document type version: {}", header.doc_type_version);
            println!(
                "|+ Document type read version: {}",
                header.doc_type_read_version
            );

            b.data().offset(remaining)
        } else {
            return Err(InfoError::ParseHeader);
        }
    };

    let mut _consumed = length;
    b.consume(length);

    let length = {
        let res = segment(b.data());
        if let Ok((remaining, segment)) = res {
            println!("+ Segment, size {}", segment.1.unwrap_or(0));

            b.data().offset(remaining)
        } else {
            return Err(InfoError::ParseHeader);
        }
    };

    b.consume(length);

    // handle first elements
    let mut seek_head = None;
    let mut info = None;
    let mut tracks = None;

    loop {
        if seek_head.is_some() && info.is_some() && tracks.is_some() {
            break;
        }

        if b.available_space() == 0 {
            b.shift();
            if b.available_space() == 0 {
                println!("buffer is already full, cannot refill");
                break;
            }
        }

        // refill the buffer
        let sz = file.read(b.space())?;
        b.fill(sz);

        // if there's no more available data in the buffer after a write, that means we reached
        // the end of the file
        if b.available_data() == 0 {
            return Err(InfoError::NoMoreData);
        }

        let offset = {
            let (i, element) = match segment_element(b.data()) {
                Ok((i, o)) => (i, o),
                Err(Err::Error(e)) | Err(Err::Failure(e)) => {
                    return Err(InfoError::Parse(format!("{:?}", e)))
                }
                Err(Err::Incomplete(_i)) => continue,
            };

            match element {
                SegmentElement::SeekHead(s) => {
                    println!("|+ Seek head at {:#0x} size {}", 0x0, b.data().offset(i));
                    for seek in s.positions.iter() {
                        let _id: u64 = (u64::from(seek.id[0]) << 24)
                            | (u64::from(seek.id[1]) << 16)
                            | (u64::from(seek.id[2]) << 8)
                            | u64::from(seek.id[3]);

                        let element_size = seek.size(0x4DBB);
                        let id_size = seek.id.size(0x53AB);
                        let position_size = seek.position.size(0x53AC);

                        println!("| + Seek entry size {}", element_size);

                        print!("|  + Seek ID:");
                        for id in seek.id.iter() {
                            print!(" {:#0x}", id);
                        }

                        let name = match &seek.id[..] {
                            [0x11, 0x4D, 0x9B, 0x74] => " (KaxSeekHead)",
                            [0x12, 0x54, 0xC3, 0x67] => " (KaxTags)",
                            [0x15, 0x49, 0xA9, 0x66] => " (KaxInfo)",
                            [0x16, 0x54, 0xAE, 0x6B] => " (KaxTracks)",
                            [0x1C, 0x53, 0xBB, 0x6B] => " (KaxCues)",
                            [0x1F, 0x43, 0xB6, 0x75] => " (KaxCluster)",
                            _ => "",
                        };

                        println!("{} at {:#0x} size {}", name, 0x0, id_size);
                        println!(
                            "|  + Seek position: {} size {}",
                            seek.position, position_size
                        );
                    }

                    if seek_head.is_some() {
                        return Err(InfoError::SeekHeadElement);
                    } else {
                        seek_head = Some(s);
                    }
                }
                SegmentElement::Info(i) => {
                    println!("|+ Segment information");
                    println!("| + Timestamp scale: {}", i.timecode_scale);
                    println!("| + Multiplexing application: {}", i.muxing_app);
                    println!("| + Writing application: {}", i.writing_app);
                    println!(
                        "| + Segment UID: {:?}",
                        i.segment_uid.as_ref().unwrap_or(&Vec::new())
                    );
                    println!("| + Duration: {}s", i.duration.unwrap_or(0f64) / 1000f64);
                    if info.is_some() {
                        return Err(InfoError::InfoElement);
                    } else {
                        info = Some(i);
                    }
                }
                SegmentElement::Tracks(t) => {
                    //eprintln!("got tracks: {:#?}", t);
                    println!("|+ Segment tracks");
                    for tr in t.tracks.iter() {
                        println!("| + A track");
                        println!("|  + Track number: {}", tr.track_number);
                        println!("|  + Track UID: {}", tr.track_uid);
                        println!("|  + Track type: {}", tr.track_type);
                        println!("|  + Lacing flag: {}", tr.flag_lacing.unwrap_or(0));
                        println!("|  + Default flag: {}", tr.flag_default.unwrap_or(0));
                        println!(
                            "|  + Language: {}",
                            tr.language.as_ref().unwrap_or(&"".to_string())
                        );
                        println!("|  + Codec ID: {}", tr.codec_id);
                        println!(
                            "|  + Codec private: length {}",
                            tr.codec_private.as_ref().map(|v| v.len()).unwrap_or(0)
                        );

                        if let Some(ref v) = tr.video {
                            println!("|  + Video track");
                            println!("|    + Pixel width: {}", v.pixel_width);
                            println!("|    + Pixel height: {}", v.pixel_height);
                            if let Some(inter) = v.flag_interlaced {
                                println!("|    + Interlaced: {}", inter);
                            }
                            if let Some(width) = v.display_width {
                                println!("|    + Display width: {}", width);
                            }
                            if let Some(height) = v.display_height {
                                println!("|    + Display height: {}", height);
                            }
                            if let Some(unit) = v.display_unit {
                                println!("|    + Display unit: {}", unit);
                            }
                        }

                        if let Some(ref a) = tr.audio {
                            println!("|  + Audio track");
                            println!("|    + Sampling frequency: {}", a.sampling_frequency);
                            if let Some(frequency) = a.output_sampling_frequency {
                                println!("|    + Output sampling freqeuncy: {}", frequency);
                            }
                            println!("|    + Channels: {}", a.channels);
                            if let Some(ref channel_positions) = a.channel_positions {
                                println!("|    + Channel position: {:?}", channel_positions);
                            }
                            if let Some(bit_depth) = a.bit_depth {
                                println!("|    + Bit depth: {}", bit_depth);
                            }
                        }
                    }
                    if tracks.is_some() {
                        return Err(InfoError::TracksElement);
                    } else {
                        tracks = Some(t);
                    }
                }
                SegmentElement::Void(s) => {
                    println!("|+ EbmlVoid (size: {})", s);
                }
                el => return Err(InfoError::UnexpectedElement(format!("{:?}", el))),
            }

            b.data().offset(i)
        };
        _consumed += offset;
        b.consume(offset);
    }

    loop {
        if b.available_space() == 0 {
            b.shift();
            if b.available_space() == 0 {
                println!("buffer is already full,  cannot refill");
                break;
            }
        }

        // refill the buffer
        let sz = file.read(b.space())?;
        b.fill(sz);

        // if there's no more available data in the buffer after a write, that means we reached
        // the end of the file
        if b.available_data() == 0 {
            //panic!("no more data to read or parse, stopping the reading loop");
            break;
        }

        let offset = {
            let (i, element) = match segment_element(b.data()) {
                Ok((i, o)) => (i, o),
                Err(Err::Error(e)) | Err(Err::Failure(e)) => {
                    return Err(InfoError::Parse(format!("{:?}", e)))
                }
                Err(Err::Incomplete(_)) => continue,
            };

            match element {
                SegmentElement::SeekHead(_)
                | SegmentElement::Info(_)
                | SegmentElement::Tracks(_) => {
                    return Err(InfoError::UnexpectedElement(
                        "seek head, info or tracks element".to_string(),
                    ));
                }
                SegmentElement::Cluster(c) => {
                    println!("|+ Cluster");
                    println!("|+   Timecode: {}", c.timecode);
                    println!("|+   Silent_tracks: {:?}", c.silent_tracks);
                    println!("|+   Position: {:?}", c.position);
                    println!("|+   Prev size: {:?}", c.prev_size);
                    println!("|+   Simple block: {} elements", c.simple_block.len());
                    println!("|+   Block group: {} elements", c.block_group.len());
                    println!(
                        "|+   Encrypted block: {:?} bytes",
                        c.encrypted_block.as_ref().map(|s| s.len())
                    );
                }
                SegmentElement::Void(s) => {
                    println!("|+ EbmlVoid (size: {})", s);
                }
                SegmentElement::Tags(_) => {
                    println!("|+ Tags");
                }
                SegmentElement::Cues(_) => {
                    println!("|+ Cues");
                }
                SegmentElement::Unknown(id, data) => {
                    return Err(InfoError::UnknownElement(_consumed, id, data))
                }
                el => return Err(InfoError::UnexpectedElement(format!("{:?}", el))),
            }

            b.data().offset(i)
        };
        _consumed += offset;
        b.consume(offset);
    }

    Ok(())
}
<|endoftext|>


<commit_before>use crate::{convert, ops};

/// Used to tell an operation whether it should exit early or go on as usual.
///
/// This is used when exposing things (like graph traversals or visitors) where
/// you want the user to be able to choose whether to exit early.
/// Having the enum makes it clearer -- no more wondering "wait, what did `false`
/// mean again?" -- and allows including a value.
///
/// Similar to [`Option`] and [`Result`], this enum can be used with the `?` operator
/// to return immediatly if the [`Break`] variant is present or to continue normally
/// with the value inside the [`Continue`] variant.
///
/// # Examples
///
/// Early-exiting from [`Iterator::try_for_each`]:
/// ```
/// use std::ops::ControlFlow;
///
/// let r = (2..100).try_for_each(|x| {
///     if 403 % x == 0 {
///         return ControlFlow::Break(x)
///     }
///
///     ControlFlow::Continue(())
/// });
/// assert_eq!(r, ControlFlow::Break(13));
/// ```
///
/// A basic tree traversal:
/// ```no_run
/// use std::ops::ControlFlow;
///
/// pub struct TreeNode<T> {
///     value: T,
///     left: Option<Box<TreeNode<T>>>,
///     right: Option<Box<TreeNode<T>>>,
/// }
///
/// impl<T> TreeNode<T> {
///     pub fn traverse_inorder<B>(&self, mut f: impl FnMut(&T) -> ControlFlow<B>) -> ControlFlow<B> {
///         if let Some(left) = &self.left {
///             left.traverse_inorder(&mut f)?;
///         }
///         f(&self.value)?;
///         if let Some(right) = &self.right {
///             right.traverse_inorder(&mut f)?;
///         }
///         ControlFlow::Continue(())
///     }
/// }
/// ```
///
/// [`Break`]: ControlFlow::Break
/// [`Continue`]: ControlFlow::Continue
#[stable(feature = "control_flow_enum_type", since = "1.55.0")]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ControlFlow<B, C = ()> {
    /// Move on to the next phase of the operation as normal.
    #[stable(feature = "control_flow_enum_type", since = "1.55.0")]
    #[lang = "Continue"]
    Continue(C),
    /// Exit the operation without running subsequent phases.
    #[stable(feature = "control_flow_enum_type", since = "1.55.0")]
    #[lang = "Break"]
    Break(B),
    // Yes, the order of the variants doesn't match the type parameters.
    // They're in this order so that `ControlFlow<A, B>` <-> `Result<B, A>`
    // is a no-op conversion in the `Try` implementation.
}

#[unstable(feature = "try_trait_v2", issue = "84277")]
impl<B, C> ops::Try for ControlFlow<B, C> {
    type Output = C;
    type Residual = ControlFlow<B, convert::Infallible>;

    #[inline]
    fn from_output(output: Self::Output) -> Self {
        ControlFlow::Continue(output)
    }

    #[inline]
    fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
        match self {
            ControlFlow::Continue(c) => ControlFlow::Continue(c),
            ControlFlow::Break(b) => ControlFlow::Break(ControlFlow::Break(b)),
        }
    }
}

#[unstable(feature = "try_trait_v2", issue = "84277")]
impl<B, C> ops::FromResidual for ControlFlow<B, C> {
    #[inline]
    fn from_residual(residual: ControlFlow<B, convert::Infallible>) -> Self {
        match residual {
            ControlFlow::Break(b) => ControlFlow::Break(b),
        }
    }
}

impl<B, C> ControlFlow<B, C> {
    /// Returns `true` if this is a `Break` variant.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// assert!(ControlFlow::<i32, String>::Break(3).is_break());
    /// assert!(!ControlFlow::<String, i32>::Continue(3).is_break());
    /// ```
    #[inline]
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub fn is_break(&self) -> bool {
        matches!(*self, ControlFlow::Break(_))
    }

    /// Returns `true` if this is a `Continue` variant.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// assert!(!ControlFlow::<i32, String>::Break(3).is_continue());
    /// assert!(ControlFlow::<String, i32>::Continue(3).is_continue());
    /// ```
    #[inline]
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub fn is_continue(&self) -> bool {
        matches!(*self, ControlFlow::Continue(_))
    }

    /// Converts the `ControlFlow` into an `Option` which is `Some` if the
    /// `ControlFlow` was `Break` and `None` otherwise.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// assert_eq!(ControlFlow::<i32, String>::Break(3).break_value(), Some(3));
    /// assert_eq!(ControlFlow::<String, i32>::Continue(3).break_value(), None);
    /// ```
    #[inline]
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub fn break_value(self) -> Option<B> {
        match self {
            ControlFlow::Continue(..) => None,
            ControlFlow::Break(x) => Some(x),
        }
    }

    /// Maps `ControlFlow<B, C>` to `ControlFlow<T, C>` by applying a function
    /// to the break value in case it exists.
    #[inline]
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub fn map_break<T, F>(self, f: F) -> ControlFlow<T, C>
    where
        F: FnOnce(B) -> T,
    {
        match self {
            ControlFlow::Continue(x) => ControlFlow::Continue(x),
            ControlFlow::Break(x) => ControlFlow::Break(f(x)),
        }
    }
}

/// These are used only as part of implementing the iterator adapters.
/// They have mediocre names and non-obvious semantics, so aren't
/// currently on a path to potential stabilization.
impl<R: ops::Try> ControlFlow<R, R::Output> {
    /// Create a `ControlFlow` from any type implementing `Try`.
    #[inline]
    pub(crate) fn from_try(r: R) -> Self {
        match R::branch(r) {
            ControlFlow::Continue(v) => ControlFlow::Continue(v),
            ControlFlow::Break(v) => ControlFlow::Break(R::from_residual(v)),
        }
    }

    /// Convert a `ControlFlow` into any type implementing `Try`;
    #[inline]
    pub(crate) fn into_try(self) -> R {
        match self {
            ControlFlow::Continue(v) => R::from_output(v),
            ControlFlow::Break(v) => v,
        }
    }
}

impl<B> ControlFlow<B, ()> {
    /// It's frequently the case that there's no value needed with `Continue`,
    /// so this provides a way to avoid typing `(())`, if you prefer it.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// let mut partial_sum = 0;
    /// let last_used = (1..10).chain(20..25).try_for_each(|x| {
    ///     partial_sum += x;
    ///     if partial_sum > 100 { ControlFlow::Break(x) }
    ///     else { ControlFlow::CONTINUE }
    /// });
    /// assert_eq!(last_used.break_value(), Some(22));
    /// ```
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub const CONTINUE: Self = ControlFlow::Continue(());
}

impl<C> ControlFlow<(), C> {
    /// APIs like `try_for_each` don't need values with `Break`,
    /// so this provides a way to avoid typing `(())`, if you prefer it.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// let mut partial_sum = 0;
    /// (1..10).chain(20..25).try_for_each(|x| {
    ///     if partial_sum > 100 { ControlFlow::BREAK }
    ///     else { partial_sum += x; ControlFlow::CONTINUE }
    /// });
    /// assert_eq!(partial_sum, 108);
    /// ```
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub const BREAK: Self = ControlFlow::Break(());
}
<commit_msg>Fix typo and change a word in ControlFlow docs<commit_after>use crate::{convert, ops};

/// Used to tell an operation whether it should exit early or go on as usual.
///
/// This is used when exposing things (like graph traversals or visitors) where
/// you want the user to be able to choose whether to exit early.
/// Having the enum makes it clearer -- no more wondering "wait, what did `false`
/// mean again?" -- and allows including a value.
///
/// Similar to [`Option`] and [`Result`], this enum can be used with the `?` operator
/// to return immediately if the [`Break`] variant is present or otherwise continue normally
/// with the value inside the [`Continue`] variant.
///
/// # Examples
///
/// Early-exiting from [`Iterator::try_for_each`]:
/// ```
/// use std::ops::ControlFlow;
///
/// let r = (2..100).try_for_each(|x| {
///     if 403 % x == 0 {
///         return ControlFlow::Break(x)
///     }
///
///     ControlFlow::Continue(())
/// });
/// assert_eq!(r, ControlFlow::Break(13));
/// ```
///
/// A basic tree traversal:
/// ```no_run
/// use std::ops::ControlFlow;
///
/// pub struct TreeNode<T> {
///     value: T,
///     left: Option<Box<TreeNode<T>>>,
///     right: Option<Box<TreeNode<T>>>,
/// }
///
/// impl<T> TreeNode<T> {
///     pub fn traverse_inorder<B>(&self, mut f: impl FnMut(&T) -> ControlFlow<B>) -> ControlFlow<B> {
///         if let Some(left) = &self.left {
///             left.traverse_inorder(&mut f)?;
///         }
///         f(&self.value)?;
///         if let Some(right) = &self.right {
///             right.traverse_inorder(&mut f)?;
///         }
///         ControlFlow::Continue(())
///     }
/// }
/// ```
///
/// [`Break`]: ControlFlow::Break
/// [`Continue`]: ControlFlow::Continue
#[stable(feature = "control_flow_enum_type", since = "1.55.0")]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ControlFlow<B, C = ()> {
    /// Move on to the next phase of the operation as normal.
    #[stable(feature = "control_flow_enum_type", since = "1.55.0")]
    #[lang = "Continue"]
    Continue(C),
    /// Exit the operation without running subsequent phases.
    #[stable(feature = "control_flow_enum_type", since = "1.55.0")]
    #[lang = "Break"]
    Break(B),
    // Yes, the order of the variants doesn't match the type parameters.
    // They're in this order so that `ControlFlow<A, B>` <-> `Result<B, A>`
    // is a no-op conversion in the `Try` implementation.
}

#[unstable(feature = "try_trait_v2", issue = "84277")]
impl<B, C> ops::Try for ControlFlow<B, C> {
    type Output = C;
    type Residual = ControlFlow<B, convert::Infallible>;

    #[inline]
    fn from_output(output: Self::Output) -> Self {
        ControlFlow::Continue(output)
    }

    #[inline]
    fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
        match self {
            ControlFlow::Continue(c) => ControlFlow::Continue(c),
            ControlFlow::Break(b) => ControlFlow::Break(ControlFlow::Break(b)),
        }
    }
}

#[unstable(feature = "try_trait_v2", issue = "84277")]
impl<B, C> ops::FromResidual for ControlFlow<B, C> {
    #[inline]
    fn from_residual(residual: ControlFlow<B, convert::Infallible>) -> Self {
        match residual {
            ControlFlow::Break(b) => ControlFlow::Break(b),
        }
    }
}

impl<B, C> ControlFlow<B, C> {
    /// Returns `true` if this is a `Break` variant.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// assert!(ControlFlow::<i32, String>::Break(3).is_break());
    /// assert!(!ControlFlow::<String, i32>::Continue(3).is_break());
    /// ```
    #[inline]
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub fn is_break(&self) -> bool {
        matches!(*self, ControlFlow::Break(_))
    }

    /// Returns `true` if this is a `Continue` variant.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// assert!(!ControlFlow::<i32, String>::Break(3).is_continue());
    /// assert!(ControlFlow::<String, i32>::Continue(3).is_continue());
    /// ```
    #[inline]
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub fn is_continue(&self) -> bool {
        matches!(*self, ControlFlow::Continue(_))
    }

    /// Converts the `ControlFlow` into an `Option` which is `Some` if the
    /// `ControlFlow` was `Break` and `None` otherwise.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// assert_eq!(ControlFlow::<i32, String>::Break(3).break_value(), Some(3));
    /// assert_eq!(ControlFlow::<String, i32>::Continue(3).break_value(), None);
    /// ```
    #[inline]
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub fn break_value(self) -> Option<B> {
        match self {
            ControlFlow::Continue(..) => None,
            ControlFlow::Break(x) => Some(x),
        }
    }

    /// Maps `ControlFlow<B, C>` to `ControlFlow<T, C>` by applying a function
    /// to the break value in case it exists.
    #[inline]
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub fn map_break<T, F>(self, f: F) -> ControlFlow<T, C>
    where
        F: FnOnce(B) -> T,
    {
        match self {
            ControlFlow::Continue(x) => ControlFlow::Continue(x),
            ControlFlow::Break(x) => ControlFlow::Break(f(x)),
        }
    }
}

/// These are used only as part of implementing the iterator adapters.
/// They have mediocre names and non-obvious semantics, so aren't
/// currently on a path to potential stabilization.
impl<R: ops::Try> ControlFlow<R, R::Output> {
    /// Create a `ControlFlow` from any type implementing `Try`.
    #[inline]
    pub(crate) fn from_try(r: R) -> Self {
        match R::branch(r) {
            ControlFlow::Continue(v) => ControlFlow::Continue(v),
            ControlFlow::Break(v) => ControlFlow::Break(R::from_residual(v)),
        }
    }

    /// Convert a `ControlFlow` into any type implementing `Try`;
    #[inline]
    pub(crate) fn into_try(self) -> R {
        match self {
            ControlFlow::Continue(v) => R::from_output(v),
            ControlFlow::Break(v) => v,
        }
    }
}

impl<B> ControlFlow<B, ()> {
    /// It's frequently the case that there's no value needed with `Continue`,
    /// so this provides a way to avoid typing `(())`, if you prefer it.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// let mut partial_sum = 0;
    /// let last_used = (1..10).chain(20..25).try_for_each(|x| {
    ///     partial_sum += x;
    ///     if partial_sum > 100 { ControlFlow::Break(x) }
    ///     else { ControlFlow::CONTINUE }
    /// });
    /// assert_eq!(last_used.break_value(), Some(22));
    /// ```
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub const CONTINUE: Self = ControlFlow::Continue(());
}

impl<C> ControlFlow<(), C> {
    /// APIs like `try_for_each` don't need values with `Break`,
    /// so this provides a way to avoid typing `(())`, if you prefer it.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// let mut partial_sum = 0;
    /// (1..10).chain(20..25).try_for_each(|x| {
    ///     if partial_sum > 100 { ControlFlow::BREAK }
    ///     else { partial_sum += x; ControlFlow::CONTINUE }
    /// });
    /// assert_eq!(partial_sum, 108);
    /// ```
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub const BREAK: Self = ControlFlow::Break(());
}
<|endoftext|>


<commit_before>#[deriving(Eq)]
enum Value {
	List(~[Value]),
	Atom(~str),
	Str(~str),
	Num(float)
}

fn read_nows(input: &str, start: uint) -> Option<char> {
	input.iter().skip(start).skip_while(|&c| c == ' ' || c == '\t').next()
}

fn read_number(input: &str, start: uint) -> Option<(~Value, uint)> {
	let end = input.iter().skip(start).position(|c| c == ' ' || c == ')');
	let pos = match end {
		Some(end) => start+end,
		None => input.len()
	};
	let acc = input.slice(start, pos);
	match std::float::from_str(acc) {
		Some(f) => Some((~Num(f), pos)),
		None => None
	}
}

fn read_list(input: &str, start: uint) -> Option<(~Value, uint)> {
	let mut list = ~[];
	let mut i = start;
	loop {
		match read_value(input, i) {
			Some((v,new_i)) => {
				list.push(*v);
				i = new_i;
			}
			None if read_nows(input, i) == Some(')') => return Some((~List(list), i)),
			None => return None
		}
	}
}

fn read_atom(input: &str, start: uint) -> Option<(~Value, uint)> {
	let atom = std::str::from_chars(input.iter().skip(start).take_while(|&c| c != ' ' && c != ')').to_owned_vec());
	let len = atom.len();
	Some((~Atom(atom), start + len))
}

fn read_value(input: &str, start: uint) -> Option<(~Value, uint)> {
	if(start >= input.len()) {
		return None
	}

	match input[start] as char {
		' ' => read_value(input, start+1),
		'(' => read_list(input, start+1),
		')' => None,
		c if c.is_digit() || c == '.' => read_number(input, start),
		_ => read_atom(input, start)
	}
}

fn parse(input: &str) -> Option<Value> {
	/*do io::with_str_reader(input) |r| {
		//let c =
		println("blah: " + input + " -> " + read_token(r));
		List(~[])
	}*/
	match read_value(input, 0) {
		Some((v,_)) => Some(*v),
		None => None
	}
}

#[test]
fn test_sexpr() {
	assert_eq!(parse(""), None);
	assert_eq!(parse("123"), Some(Num(123.0)));
	assert_eq!(parse("()"), Some(List(~[])));
	assert_eq!(parse("3.14159265358"), Some(Num(3.14159265358)));
	assert_eq!(parse("(hi)"), Some(List(~[Atom(~"hi")])));
	assert_eq!(parse("(1)"), Some(List(~[Num(1.0)])));
	assert_eq!(parse("  (  1  )  "), Some(List(~[Num(1.0)])));
	assert_eq!(parse("(hi there)"), Some(List(~[Atom(~"hi"), Atom(~"there")])));
	assert_eq!(parse("(hi (there))"), Some(List(~[Atom(~"hi"), List(~[Atom(~"there")])])));
	assert_eq!(parse("(hi 123456)"), Some(List(~[Atom(~"hi"), Num(123456.0)])));
	assert_eq!(parse("(())"), Some(List(~[List(~[])])));
	assert_eq!(parse("  (  (  )  )  )"), Some(List(~[List(~[])])));
	assert_eq!(parse("(hi (there (fellow (human-bot!))))"), Some(
		List(~[Atom(~"hi"),
			List(~[Atom(~"there"),
				List(~[Atom(~"fellow"),
					List(~[Atom(~"human-bot!")])])])])
	));
}
<commit_msg>Separate tests into the test module, and add tests for whitespace.<commit_after>#[deriving(Eq)]
enum Value {
	List(~[Value]),
	Atom(~str),
	Str(~str),
	Num(float)
}

fn read_nows(input: &str, start: uint) -> Option<char> {
	input.iter().skip(start).skip_while(|&c| c == ' ' || c == '\t').next()
}

fn read_number(input: &str, start: uint) -> Option<(~Value, uint)> {
	let end = input.iter().skip(start).position(|c| c == ' ' || c == ')');
	let pos = match end {
		Some(end) => start+end,
		None => input.len()
	};
	let acc = input.slice(start, pos);
	match std::float::from_str(acc) {
		Some(f) => Some((~Num(f), pos)),
		None => None
	}
}

fn read_list(input: &str, start: uint) -> Option<(~Value, uint)> {
	let mut list = ~[];
	let mut i = start;
	loop {
		match read_value(input, i) {
			Some((v,new_i)) => {
				list.push(*v);
				i = new_i;
			}
			None if read_nows(input, i) == Some(')') => return Some((~List(list), i)),
			None => return None
		}
	}
}

fn read_atom(input: &str, start: uint) -> Option<(~Value, uint)> {
	let atom = std::str::from_chars(input.iter().skip(start).take_while(|&c| c != ' ' && c != ')').to_owned_vec());
	let len = atom.len();
	Some((~Atom(atom), start + len))
}

fn read_value(input: &str, start: uint) -> Option<(~Value, uint)> {
	if(start >= input.len()) {
		return None
	}

	match input[start] as char {
		' ' => read_value(input, start+1),
		'(' => read_list(input, start+1),
		')' => None,
		c if c.is_digit() || c == '.' => read_number(input, start),
		_ => read_atom(input, start)
	}
}

pub fn parse(input: &str) -> Option<Value> {
	/*do io::with_str_reader(input) |r| {
		//let c =
		println("blah: " + input + " -> " + read_token(r));
		List(~[])
	}*/
	match read_value(input, 0) {
		Some((v,_)) => Some(*v),
		None => None
	}
}

mod test {
	use super::{parse, Value, Num, List, Atom};

	fn parse_some(input: &'static str, expr: Value) {
		match parse(input) {
			Some(ref p) if p == &expr => {}
			Some(ref p) => {
				if(p != &expr) {
					fail!("Expected %?, not %?, for %?", expr, *p, input)
				}
			}
			None => fail!("Got None for %?", input)
		}
	}

	#[test]
	fn test_sexpr() {
		assert_eq!(parse(""), None);
		parse_some("123", Num(123.0));
		parse_some("()", List(~[]));
		parse_some("3.14159265358", Num(3.14159265358));
		parse_some("(hi)", List(~[Atom(~"hi")]));
		parse_some("(1)", List(~[Num(1.0)]));
		parse_some("(hi there)", List(~[Atom(~"hi"), Atom(~"there")]));
		parse_some("(hi (there))", List(~[Atom(~"hi"), List(~[Atom(~"there")])]));
		parse_some("(hi 123456)", List(~[Atom(~"hi"), Num(123456.0)]));
		parse_some("(())", List(~[List(~[])]));
		parse_some("(hi (there (fellow (human-bot!))))",
			List(~[Atom(~"hi"),
				List(~[Atom(~"there"),
					List(~[Atom(~"fellow"),
						List(~[Atom(~"human-bot!")])])])])
		);
	}

	#[test]
	fn test_whitespace() {
		// spaces
		parse_some("  (  1  )  ", List(~[Num(1.0)]));
		parse_some("  (  (  )  )  )", List(~[List(~[])]));

		// newlines
		parse_some("\n\n( \n\n )\n\n", List(~[]));
		parse_some("\n\n(\n\n123\n\n)\n\n", List(~[Num(123.0)]));
	}
}<|endoftext|>


<commit_before>#![feature(phase)]

extern crate cargo;
extern crate hammer;
extern crate serialize;
#[phase(plugin, link)]
extern crate log;

use hammer::{FlagConfig,FlagConfiguration};
use std::os;
use std::io::process::{Command,InheritFd,ExitStatus,ExitSignal};
use serialize::Encodable;
use cargo::{GlobalFlags, NoFlags, execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::important_paths::find_project;
use cargo::util::{CliError, CliResult, Require, config, human};

fn main() {
    execute();
}

#[deriving(Encodable)]
struct ProjectLocation {
    root: String
}

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute() {
    debug!("executing; cmd=cargo; args={}", os::args());

    let (cmd, args) = process(os::args());

    match cmd.as_slice() {
        "config-for-key" => {
            log!(4, "cmd == config-for-key");
            execute_main_without_stdin(config_for_key)
        },
        "config-list" => {
            log!(4, "cmd == config-list");
            execute_main_without_stdin(config_list)
        },
        "locate-project" => {
            log!(4, "cmd == locate-project");
            execute_main_without_stdin(locate_project)
        },
        "--help" | "-h" | "help" | "-?" => {
            println!("Commands:");
            println!("  build          # compile the current project");
            println!("  test           # run the tests\n");

            let (_, options) = hammer::usage::<GlobalFlags>(false);
            println!("Options (for all commands):\n\n{}", options);
        },
        _ => {
            let command = Command::new(format!("cargo-{}", cmd))
                .args(args.as_slice())
                .stdin(InheritFd(0))
                .stdout(InheritFd(1))
                .stderr(InheritFd(2))
                .status();

            match command {
                Ok(ExitStatus(0)) => (),
                Ok(ExitStatus(i)) | Ok(ExitSignal(i)) => {
                    handle_error(CliError::new("", i as uint), &mut shell(false))
                }
                Err(_) => handle_error(CliError::new("No such subcommand", 127), &mut shell(false))
            }
        }
    }
}

fn process(args: Vec<String>) -> (String, Vec<String>) {
    let mut args = Vec::from_slice(args.tail());
    let head = args.shift().unwrap_or("--help".to_str());

    (head, args)
}

#[deriving(Encodable)]
struct ConfigOut {
    values: std::collections::HashMap<String, config::ConfigValue>
}

#[deriving(Decodable)]
struct ConfigForKeyFlags {
    key: String,
    human: bool
}

impl FlagConfig for ConfigForKeyFlags {
    fn config(_: Option<ConfigForKeyFlags>,
              config: FlagConfiguration) -> FlagConfiguration {
        config.short("human", 'h')
    }
}

fn config_for_key(args: ConfigForKeyFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let value = try!(config::get_config(os::getcwd(),
                                        args.key.as_slice()).map_err(|_| {
        CliError::new("Couldn't load configuration",  1)
    }));

    if args.human {
        println!("{}", value);
        Ok(None)
    } else {
        let mut map = std::collections::HashMap::new();
        map.insert(args.key.clone(), value);
        Ok(Some(ConfigOut { values: map }))
    }
}

#[deriving(Decodable)]
struct ConfigListFlags {
    human: bool
}

impl FlagConfig for ConfigListFlags {
    fn config(_: Option<ConfigListFlags>,
              config: FlagConfiguration) -> FlagConfiguration {
        config.short("human", 'h')
    }
}

fn config_list(args: ConfigListFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let configs = try!(config::all_configs(os::getcwd()).map_err(|_|
        CliError::new("Couldn't load configuration", 1)));

    if args.human {
        for (key, value) in configs.iter() {
            println!("{} = {}", key, value);
        }
        Ok(None)
    } else {
        Ok(Some(ConfigOut { values: configs }))
    }
}

fn locate_project(_: NoFlags, _: &mut MultiShell) -> CliResult<Option<ProjectLocation>> {
    let root = try!(find_project(&os::getcwd(), "Cargo.toml").map_err(|e| {
        CliError::from_boxed(e, 1)
    }));

    let string = try!(root.as_str()
                      .require(|| human("Your project path contains characters \
                                         not representable in Unicode"))
                      .map_err(|e| CliError::from_boxed(e, 1)));

    Ok(Some(ProjectLocation { root: string.to_str() }))
}
<commit_msg>auto merge of #106 : alexcrichton/cargo/no-path, r=wycats<commit_after>#![feature(phase)]

extern crate cargo;
extern crate hammer;
extern crate serialize;
#[phase(plugin, link)]
extern crate log;

use hammer::{FlagConfig,FlagConfiguration};
use std::os;
use std::io::process::{Command,InheritFd,ExitStatus,ExitSignal};
use serialize::Encodable;
use cargo::{GlobalFlags, NoFlags, execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::important_paths::find_project;
use cargo::util::{CliError, CliResult, Require, config, human};

fn main() {
    execute();
}

#[deriving(Encodable)]
struct ProjectLocation {
    root: String
}

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute() {
    debug!("executing; cmd=cargo; args={}", os::args());

    let (cmd, args) = process(os::args());

    match cmd.as_slice() {
        "config-for-key" => {
            log!(4, "cmd == config-for-key");
            execute_main_without_stdin(config_for_key)
        },
        "config-list" => {
            log!(4, "cmd == config-list");
            execute_main_without_stdin(config_list)
        },
        "locate-project" => {
            log!(4, "cmd == locate-project");
            execute_main_without_stdin(locate_project)
        },
        "--help" | "-h" | "help" | "-?" => {
            println!("Commands:");
            println!("  build          # compile the current project");
            println!("  test           # run the tests\n");

            let (_, options) = hammer::usage::<GlobalFlags>(false);
            println!("Options (for all commands):\n\n{}", options);
        },
        _ => {
            let command = format!("cargo-{}", cmd);
            let mut command = match os::self_exe_path() {
                Some(path) => Command::new(path.join(command)),
                None => Command::new(command),
            };
            let command = command
                .args(args.as_slice())
                .stdin(InheritFd(0))
                .stdout(InheritFd(1))
                .stderr(InheritFd(2))
                .status();

            match command {
                Ok(ExitStatus(0)) => (),
                Ok(ExitStatus(i)) | Ok(ExitSignal(i)) => {
                    handle_error(CliError::new("", i as uint), &mut shell(false))
                }
                Err(_) => handle_error(CliError::new("No such subcommand", 127), &mut shell(false))
            }
        }
    }
}

fn process(args: Vec<String>) -> (String, Vec<String>) {
    let mut args = Vec::from_slice(args.tail());
    let head = args.shift().unwrap_or("--help".to_str());

    (head, args)
}

#[deriving(Encodable)]
struct ConfigOut {
    values: std::collections::HashMap<String, config::ConfigValue>
}

#[deriving(Decodable)]
struct ConfigForKeyFlags {
    key: String,
    human: bool
}

impl FlagConfig for ConfigForKeyFlags {
    fn config(_: Option<ConfigForKeyFlags>,
              config: FlagConfiguration) -> FlagConfiguration {
        config.short("human", 'h')
    }
}

fn config_for_key(args: ConfigForKeyFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let value = try!(config::get_config(os::getcwd(),
                                        args.key.as_slice()).map_err(|_| {
        CliError::new("Couldn't load configuration",  1)
    }));

    if args.human {
        println!("{}", value);
        Ok(None)
    } else {
        let mut map = std::collections::HashMap::new();
        map.insert(args.key.clone(), value);
        Ok(Some(ConfigOut { values: map }))
    }
}

#[deriving(Decodable)]
struct ConfigListFlags {
    human: bool
}

impl FlagConfig for ConfigListFlags {
    fn config(_: Option<ConfigListFlags>,
              config: FlagConfiguration) -> FlagConfiguration {
        config.short("human", 'h')
    }
}

fn config_list(args: ConfigListFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let configs = try!(config::all_configs(os::getcwd()).map_err(|_|
        CliError::new("Couldn't load configuration", 1)));

    if args.human {
        for (key, value) in configs.iter() {
            println!("{} = {}", key, value);
        }
        Ok(None)
    } else {
        Ok(Some(ConfigOut { values: configs }))
    }
}

fn locate_project(_: NoFlags, _: &mut MultiShell) -> CliResult<Option<ProjectLocation>> {
    let root = try!(find_project(&os::getcwd(), "Cargo.toml").map_err(|e| {
        CliError::from_boxed(e, 1)
    }));

    let string = try!(root.as_str()
                      .require(|| human("Your project path contains characters \
                                         not representable in Unicode"))
                      .map_err(|e| CliError::from_boxed(e, 1)));

    Ok(Some(ProjectLocation { root: string.to_str() }))
}
<|endoftext|>


<commit_before>#![crate_name = "objc"]
#![crate_type = "lib"]

#![feature(default_type_params, globs, macro_rules, unboxed_closures, unsafe_destructor)]

extern crate libc;

#[cfg(test)]
extern crate objc_test_utils;

pub use id::{Id, IdVector, IntoIdVector, Owned, Ownership, Shared, ShareId};
pub use declare::{ClassDecl, MethodDecl};
pub use encode::{encode, Encode, Encoding};
pub use message::{to_obj_ptr, Message, ToMessage};
pub use weak::WeakId;

mod macros;

pub mod runtime;
mod id;
pub mod block;
mod declare;
mod encode;
mod message;
mod weak;

// Shim to re-export under the objc:: path for macros
mod objc {
    pub use runtime;
    pub use super::*;
}
<commit_msg>Fixed unnecessary use for the latest rust.<commit_after>#![crate_name = "objc"]
#![crate_type = "lib"]

#![feature(default_type_params, globs, macro_rules, unboxed_closures, unsafe_destructor)]

extern crate libc;

#[cfg(test)]
extern crate objc_test_utils;

pub use id::{Id, IdVector, IntoIdVector, Owned, Ownership, Shared, ShareId};
pub use declare::{ClassDecl, MethodDecl};
pub use encode::{encode, Encode, Encoding};
pub use message::{to_obj_ptr, Message, ToMessage};
pub use weak::WeakId;

mod macros;

pub mod runtime;
mod id;
pub mod block;
mod declare;
mod encode;
mod message;
mod weak;

// Shim to re-export under the objc:: path for macros
mod objc {
    pub use super::*;
}
<|endoftext|>


<commit_before>use gl;
use glfw::{self, Context, CursorMode, SwapInterval, Window};
pub use glfw::{Action, Key, MouseButton};
use std::cell::RefCell;
use std::os::raw::c_void;
use std::rc::Rc;
use std::sync::mpsc;
use std::thread;
use std::time::{Duration, Instant};

use camera::{Camera, Freefly};
use transform::Translation;

/// Dimension of the window to create.
#[derive(Clone, Copy, Debug)]
pub enum WindowDim {
  Windowed(u32, u32),
  FullScreen,
  FullScreenRestricted(u32, u32)
}

type Keyboard = mpsc::Receiver<(Key, Action)>;
type Mouse = mpsc::Receiver<(MouseButton, Action)>;
type MouseMove = mpsc::Receiver<[f64; 2]>;
type Scroll = mpsc::Receiver<[f64; 2]>;

/// Class of event handlers.
///
/// All functions return a special object of type `EventReport`. An event report gives information
/// about how a handler has handled the event.
pub trait EventHandler {
  /// Implement this function if you want to react to key strokes.
  fn on_key(&mut self, _: Key, _: Action) -> bool { true }
  /// Implement this function if you want to react to mouse button events.
  fn on_mouse_button(&mut self, _: MouseButton, _: Action) -> bool { true }
  /// Implement this function if you want to react to cursor moves.
  fn on_cursor_move(&mut self, _: [f64; 2]) -> bool { true }
  /// Implement this function if you want to react to scroll events.
  fn on_scroll(&mut self, _: [f64; 2]) -> bool { true }
}

/// Empty handler.
///
/// This handler will just let pass all events without doing anything. It’s only useful for debug
/// purposes when you don’t want to bother with interaction – it doesn’t even let you close the
/// application!
#[derive(Clone, Copy, Eq, Debug, PartialEq)]
pub struct Unhandled;

impl EventHandler for Unhandled {}

/// Device object.
///
/// Upon bootstrapping, this type is created to add interaction and context handling.
pub struct Device {
  /// Width of the window.
  w: u32,
  /// Height of the window.
  h: u32,
  /// Some kind of epoch start the application started at.
  start_time: Instant,
  /// Keyboard receiver.
  kbd: Keyboard,
  /// Mouse receiver.
  mouse: Mouse,
  /// Cursor receiver.
  cursor: MouseMove,
  /// Scroll receiver.
  scroll: Scroll,
  /// Window.
  window: Window,
  /// Event thread join handle. Unused and keep around until death.
  #[allow(dead_code)]
  event_thread: thread::JoinHandle<()>
}

impl Device {
  /// Entry point.
  ///
  /// This function is the first one you have to call before anything else related to this crate.
  ///
  /// # Arguments
  ///
  /// - `dim`: dimension of the window to create
  /// - `title`: title to give to the window
  pub fn bootstrap(dim: WindowDim, title: &'static str) -> Self {
    info!("{} starting", title);
    info!("window mode: {:?}", dim);

    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    // OpenGL hints
    glfw.window_hint(glfw::WindowHint::OpenGlProfile(glfw::OpenGlProfileHint::Core));
    glfw.window_hint(glfw::WindowHint::ContextVersionMajor(3));
    glfw.window_hint(glfw::WindowHint::ContextVersionMinor(3));

    // open a window in windowed or fullscreen mode
    let (mut window, events, w, h) = match dim {
      WindowDim::Windowed(w, h) => {
        let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::Windowed).expect("Failed to create GLFW window.");
        (window, events, w, h)
      },
      WindowDim::FullScreen => {
        glfw.with_primary_monitor(|glfw, monitor| {
          let monitor = monitor.unwrap();
          let vmode = monitor.get_video_mode().expect("primary monitor’s video mode");
          let (w, h) = (vmode.width, vmode.height);

          let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::FullScreen(monitor)).expect("Failed to create GLFW window.");
          (window, events, w, h)
        })
      },
      WindowDim::FullScreenRestricted(w, h) => {
        glfw.with_primary_monitor(|glfw, monitor| {
          let monitor = monitor.unwrap();

          let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::FullScreen(monitor)).expect("Failed to create GLFW window.");
          (window, events, w, h)
        })
      }
    };

    deb!("opened window");

    window.make_current();

    // FIXME: use a target instead
    if cfg!(feature = "release") {
      deb!("hiding cursor");
      window.set_cursor_mode(CursorMode::Disabled);
    }

    window.set_key_polling(true);
    window.set_cursor_pos_polling(true);
    window.set_mouse_button_polling(true);
    window.set_scroll_polling(true);
    glfw.set_swap_interval(SwapInterval::Sync(1));

    deb!("initializing OpenGL pointers");

    // init OpenGL
    gl::load_with(|s| window.get_proc_address(s) as *const c_void);

    // create channels to stream keyboard and mouse events
    let (kbd_snd, kbd_rcv) = mpsc::channel();
    let (mouse_snd, mouse_rcv) = mpsc::channel();
    let (cursor_snd, cursor_rcv) = mpsc::channel();
    let (scroll_snd, scroll_rcv) = mpsc::channel();

    deb!("spawning the event thread");
    let event_thread = thread::spawn(move || {
      loop {
        glfw.wait_events();

        for (_, event) in glfw::flush_messages(&events) {
          match event {
            glfw::WindowEvent::Key(key, _, action, _) => {
              let _ = kbd_snd.send((key, action));
            },
            glfw::WindowEvent::MouseButton(button, action, _) => {
              let _ = mouse_snd.send((button, action));
            },
            glfw::WindowEvent::CursorPos(x, y) => {
              let _ = cursor_snd.send([x, y]);
            },
            glfw::WindowEvent::Scroll(x, y) => {
              let _ = scroll_snd.send([x, y]);
            },
            _ => {},
          }
        }
      }
    });

    deb!("bootstrapping finished");

    Device {
      w: w,
      h: h,
      start_time: Instant::now(),
      kbd: kbd_rcv,
      mouse: mouse_rcv,
      cursor: cursor_rcv,
      scroll: scroll_rcv,
      window: window,
      event_thread: event_thread
    }
  }

  /// Width of the attached window.
  #[inline]
  pub fn width(&self) -> u32 {
    self.w
  }

  /// Height of the attached window.
  #[inline]
  pub fn height(&self) -> u32 {
    self.h
  }

  /// Current time, starting from the beginning of the creation of that object.
  pub fn time(&self) -> f64 {
    let elapsed = Instant::now() - self.start_time;
    elapsed.as_secs() as f64 + elapsed.subsec_nanos() as f64 * 1e-9
  }

  /// Dispatch events to a handler.
  pub fn dispatch_events<H>(&self, handler: &mut H) -> bool where H: EventHandler {
    while let Ok((key, action)) = self.kbd.try_recv() {
      if !handler.on_key(key, action) {
        return false;
      }
    }

    while let Ok((button, action)) = self.mouse.try_recv() {
      if !handler.on_mouse_button(button, action) {
        return false;
      }
    }

    while let Ok(xy) = self.cursor.try_recv() {
      if !handler.on_cursor_move(xy) {
        return false;
      }
    }

    while let Ok(xy) = self.scroll.try_recv() {
      if !handler.on_scroll(xy) {
        return false;
      }
    }

    true
  }

  /// Step function.
  ///
  /// This function provides two features:
  ///
  /// - it runs a *drawer* function, responsible of rendering a single frame, by passing it the
  ///   current time
  /// - it performs process idleing if you have requested a certain *framerate* – frame per second.
  ///
  /// The second feature is very neat because it lets you handle the scheduler off your application
  /// and then contribute to better CPU usage.
  ///
  /// > Note: if you pass `None`, no idleing will take place. However, you might be blocked by the
  /// *VSync* if enabled in your driver.
  pub fn step<FPS, R>(&mut self, fps: FPS, mut draw_frame: R) -> bool where FPS: Into<Option<u32>>, R: FnMut(Time) {
    if self.window.should_close() {
      return false;
    }

    let t = self.time();

    draw_frame(t);
    self.window.swap_buffers();

    // wait for next frame according to the wished FPS
    if let Some(fps) = fps.into() {
      let fps = fps as f64;
      let max_time = 1. / fps;
      let elapsed_time = self.time() - t;

      if elapsed_time < max_time {
        let sleep_time = max_time - elapsed_time;
        thread::sleep(Duration::from_millis((sleep_time * 1e3) as u64));
      }
    }

    true
  }
}

/// Freefly handler.
///
/// This handler is very neat as it provides freefly interaction.
pub struct FreeflyHandler {
  camera: Rc<RefCell<Camera<Freefly>>>,
  left_down: bool,
  right_down: bool,
  last_cursor: [f64; 2]
}

impl FreeflyHandler {
  pub fn new(camera: Rc<RefCell<Camera<Freefly>>>) -> Self {
    FreeflyHandler {
      camera: camera,
      left_down: false,
      right_down: false,
      last_cursor: [0., 0.]
    }
  }

  fn move_camera_on_event(&mut self, key: Key) {
    let camera = &mut self.camera.borrow_mut();

    match key {
      Key::W => camera.mv(Translation::new(0., 0., 1.)),
      Key::S => camera.mv(Translation::new(0., 0., -1.)),
      Key::A => camera.mv(Translation::new(1., 0., 0.)),
      Key::D => camera.mv(Translation::new(-1., 0., 0.)),
      Key::Q => camera.mv(Translation::new(0., -1., 0.)),
      Key::E => camera.mv(Translation::new(0., 1., 0.)),
      _ => ()
    }
  }

  fn orient_camera_on_event(&mut self, cursor: [f64; 2]) {
    let camera = &mut self.camera.borrow_mut();

    if self.left_down {
      let (dx, dy) = (cursor[0] - self.last_cursor[0], cursor[1] - self.last_cursor[1]);
      camera.look_around(Translation::new(dy as f32, dx as f32, 0.));
    } else if self.right_down {
      let (dx, _) = (cursor[0] - self.last_cursor[0], cursor[1] - self.last_cursor[1]);
      camera.look_around(Translation::new(0., 0., dx as f32));
    }

    self.last_cursor = cursor;
  }
}

impl EventHandler for FreeflyHandler {
  fn on_key(&mut self, key: Key, action: Action) -> bool {
    match action {
      Action::Press | Action::Repeat => self.move_camera_on_event(key),
      Action::Release => if key == Key::Escape { return false }
    }

    true
  }

  fn on_mouse_button(&mut self, button: MouseButton, action: Action) -> bool {
    match (button, action) {
      (MouseButton::Button1, Action::Press) => {
        self.left_down = true;
      },
      (MouseButton::Button1, Action::Release) => {
        self.left_down = false;
      },
      (MouseButton::Button2, Action::Press) => {
        self.right_down = true;
      },
      (MouseButton::Button2, Action::Release) => {
        self.right_down = false;
      },
      _ => ()
    }

    true
  }

  fn on_cursor_move(&mut self, dir: [f64; 2]) -> bool {
    self.orient_camera_on_event(dir);
    true
  }
}
<commit_msg>Ouh que c’est moche ça…<commit_after>use gl;
use glfw::{self, Context, CursorMode, SwapInterval, Window};
pub use glfw::{Action, Key, MouseButton};
use std::cell::RefCell;
use std::os::raw::c_void;
use std::rc::Rc;
use std::sync::mpsc;
use std::thread;
use std::time::{Duration, Instant};

use camera::{Camera, Freefly};
use transform::Translation;

type Time = f64;

/// Dimension of the window to create.
#[derive(Clone, Copy, Debug)]
pub enum WindowDim {
  Windowed(u32, u32),
  FullScreen,
  FullScreenRestricted(u32, u32)
}

type Keyboard = mpsc::Receiver<(Key, Action)>;
type Mouse = mpsc::Receiver<(MouseButton, Action)>;
type MouseMove = mpsc::Receiver<[f64; 2]>;
type Scroll = mpsc::Receiver<[f64; 2]>;

/// Class of event handlers.
///
/// All functions return a special object of type `EventReport`. An event report gives information
/// about how a handler has handled the event.
pub trait EventHandler {
  /// Implement this function if you want to react to key strokes.
  fn on_key(&mut self, _: Key, _: Action) -> bool { true }
  /// Implement this function if you want to react to mouse button events.
  fn on_mouse_button(&mut self, _: MouseButton, _: Action) -> bool { true }
  /// Implement this function if you want to react to cursor moves.
  fn on_cursor_move(&mut self, _: [f64; 2]) -> bool { true }
  /// Implement this function if you want to react to scroll events.
  fn on_scroll(&mut self, _: [f64; 2]) -> bool { true }
}

/// Empty handler.
///
/// This handler will just let pass all events without doing anything. It’s only useful for debug
/// purposes when you don’t want to bother with interaction – it doesn’t even let you close the
/// application!
#[derive(Clone, Copy, Eq, Debug, PartialEq)]
pub struct Unhandled;

impl EventHandler for Unhandled {}

/// Device object.
///
/// Upon bootstrapping, this type is created to add interaction and context handling.
pub struct Device {
  /// Width of the window.
  w: u32,
  /// Height of the window.
  h: u32,
  /// Some kind of epoch start the application started at.
  start_time: Instant,
  /// Keyboard receiver.
  kbd: Keyboard,
  /// Mouse receiver.
  mouse: Mouse,
  /// Cursor receiver.
  cursor: MouseMove,
  /// Scroll receiver.
  scroll: Scroll,
  /// Window.
  window: Window,
  /// Event thread join handle. Unused and keep around until death.
  #[allow(dead_code)]
  event_thread: thread::JoinHandle<()>
}

impl Device {
  /// Entry point.
  ///
  /// This function is the first one you have to call before anything else related to this crate.
  ///
  /// # Arguments
  ///
  /// - `dim`: dimension of the window to create
  /// - `title`: title to give to the window
  pub fn bootstrap(dim: WindowDim, title: &'static str) -> Self {
    info!("{} starting", title);
    info!("window mode: {:?}", dim);

    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    // OpenGL hints
    glfw.window_hint(glfw::WindowHint::OpenGlProfile(glfw::OpenGlProfileHint::Core));
    glfw.window_hint(glfw::WindowHint::ContextVersionMajor(3));
    glfw.window_hint(glfw::WindowHint::ContextVersionMinor(3));

    // open a window in windowed or fullscreen mode
    let (mut window, events, w, h) = match dim {
      WindowDim::Windowed(w, h) => {
        let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::Windowed).expect("Failed to create GLFW window.");
        (window, events, w, h)
      },
      WindowDim::FullScreen => {
        glfw.with_primary_monitor(|glfw, monitor| {
          let monitor = monitor.unwrap();
          let vmode = monitor.get_video_mode().expect("primary monitor’s video mode");
          let (w, h) = (vmode.width, vmode.height);

          let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::FullScreen(monitor)).expect("Failed to create GLFW window.");
          (window, events, w, h)
        })
      },
      WindowDim::FullScreenRestricted(w, h) => {
        glfw.with_primary_monitor(|glfw, monitor| {
          let monitor = monitor.unwrap();

          let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::FullScreen(monitor)).expect("Failed to create GLFW window.");
          (window, events, w, h)
        })
      }
    };

    deb!("opened window");

    window.make_current();

    // FIXME: use a target instead
    if cfg!(feature = "release") {
      deb!("hiding cursor");
      window.set_cursor_mode(CursorMode::Disabled);
    }

    window.set_key_polling(true);
    window.set_cursor_pos_polling(true);
    window.set_mouse_button_polling(true);
    window.set_scroll_polling(true);
    glfw.set_swap_interval(SwapInterval::Sync(1));

    deb!("initializing OpenGL pointers");

    // init OpenGL
    gl::load_with(|s| window.get_proc_address(s) as *const c_void);

    // create channels to stream keyboard and mouse events
    let (kbd_snd, kbd_rcv) = mpsc::channel();
    let (mouse_snd, mouse_rcv) = mpsc::channel();
    let (cursor_snd, cursor_rcv) = mpsc::channel();
    let (scroll_snd, scroll_rcv) = mpsc::channel();

    deb!("spawning the event thread");
    let event_thread = thread::spawn(move || {
      loop {
        glfw.wait_events();

        for (_, event) in glfw::flush_messages(&events) {
          match event {
            glfw::WindowEvent::Key(key, _, action, _) => {
              let _ = kbd_snd.send((key, action));
            },
            glfw::WindowEvent::MouseButton(button, action, _) => {
              let _ = mouse_snd.send((button, action));
            },
            glfw::WindowEvent::CursorPos(x, y) => {
              let _ = cursor_snd.send([x, y]);
            },
            glfw::WindowEvent::Scroll(x, y) => {
              let _ = scroll_snd.send([x, y]);
            },
            _ => {},
          }
        }
      }
    });

    deb!("bootstrapping finished");

    Device {
      w: w,
      h: h,
      start_time: Instant::now(),
      kbd: kbd_rcv,
      mouse: mouse_rcv,
      cursor: cursor_rcv,
      scroll: scroll_rcv,
      window: window,
      event_thread: event_thread
    }
  }

  /// Width of the attached window.
  #[inline]
  pub fn width(&self) -> u32 {
    self.w
  }

  /// Height of the attached window.
  #[inline]
  pub fn height(&self) -> u32 {
    self.h
  }

  /// Current time, starting from the beginning of the creation of that object.
  pub fn time(&self) -> f64 {
    let elapsed = Instant::now() - self.start_time;
    elapsed.as_secs() as f64 + elapsed.subsec_nanos() as f64 * 1e-9
  }

  /// Dispatch events to a handler.
  pub fn dispatch_events<H>(&self, handler: &mut H) -> bool where H: EventHandler {
    while let Ok((key, action)) = self.kbd.try_recv() {
      if !handler.on_key(key, action) {
        return false;
      }
    }

    while let Ok((button, action)) = self.mouse.try_recv() {
      if !handler.on_mouse_button(button, action) {
        return false;
      }
    }

    while let Ok(xy) = self.cursor.try_recv() {
      if !handler.on_cursor_move(xy) {
        return false;
      }
    }

    while let Ok(xy) = self.scroll.try_recv() {
      if !handler.on_scroll(xy) {
        return false;
      }
    }

    true
  }

  /// Step function.
  ///
  /// This function provides two features:
  ///
  /// - it runs a *drawer* function, responsible of rendering a single frame, by passing it the
  ///   current time
  /// - it performs process idleing if you have requested a certain *framerate* – frame per second.
  ///
  /// The second feature is very neat because it lets you handle the scheduler off your application
  /// and then contribute to better CPU usage.
  ///
  /// > Note: if you pass `None`, no idleing will take place. However, you might be blocked by the
  /// *VSync* if enabled in your driver.
  pub fn step<FPS, R>(&mut self, fps: FPS, mut draw_frame: R) -> bool where FPS: Into<Option<u32>>, R: FnMut(Time) {
    if self.window.should_close() {
      return false;
    }

    let t = self.time();

    draw_frame(t);
    self.window.swap_buffers();

    // wait for next frame according to the wished FPS
    if let Some(fps) = fps.into() {
      let fps = fps as f64;
      let max_time = 1. / fps;
      let elapsed_time = self.time() - t;

      if elapsed_time < max_time {
        let sleep_time = max_time - elapsed_time;
        thread::sleep(Duration::from_millis((sleep_time * 1e3) as u64));
      }
    }

    true
  }
}

/// Freefly handler.
///
/// This handler is very neat as it provides freefly interaction.
pub struct FreeflyHandler {
  camera: Rc<RefCell<Camera<Freefly>>>,
  left_down: bool,
  right_down: bool,
  last_cursor: [f64; 2]
}

impl FreeflyHandler {
  pub fn new(camera: Rc<RefCell<Camera<Freefly>>>) -> Self {
    FreeflyHandler {
      camera: camera,
      left_down: false,
      right_down: false,
      last_cursor: [0., 0.]
    }
  }

  fn move_camera_on_event(&mut self, key: Key) {
    let camera = &mut self.camera.borrow_mut();

    match key {
      Key::W => camera.mv(Translation::new(0., 0., 1.)),
      Key::S => camera.mv(Translation::new(0., 0., -1.)),
      Key::A => camera.mv(Translation::new(1., 0., 0.)),
      Key::D => camera.mv(Translation::new(-1., 0., 0.)),
      Key::Q => camera.mv(Translation::new(0., -1., 0.)),
      Key::E => camera.mv(Translation::new(0., 1., 0.)),
      _ => ()
    }
  }

  fn orient_camera_on_event(&mut self, cursor: [f64; 2]) {
    let camera = &mut self.camera.borrow_mut();

    if self.left_down {
      let (dx, dy) = (cursor[0] - self.last_cursor[0], cursor[1] - self.last_cursor[1]);
      camera.look_around(Translation::new(dy as f32, dx as f32, 0.));
    } else if self.right_down {
      let (dx, _) = (cursor[0] - self.last_cursor[0], cursor[1] - self.last_cursor[1]);
      camera.look_around(Translation::new(0., 0., dx as f32));
    }

    self.last_cursor = cursor;
  }
}

impl EventHandler for FreeflyHandler {
  fn on_key(&mut self, key: Key, action: Action) -> bool {
    match action {
      Action::Press | Action::Repeat => self.move_camera_on_event(key),
      Action::Release => if key == Key::Escape { return false }
    }

    true
  }

  fn on_mouse_button(&mut self, button: MouseButton, action: Action) -> bool {
    match (button, action) {
      (MouseButton::Button1, Action::Press) => {
        self.left_down = true;
      },
      (MouseButton::Button1, Action::Release) => {
        self.left_down = false;
      },
      (MouseButton::Button2, Action::Press) => {
        self.right_down = true;
      },
      (MouseButton::Button2, Action::Release) => {
        self.right_down = false;
      },
      _ => ()
    }

    true
  }

  fn on_cursor_move(&mut self, dir: [f64; 2]) -> bool {
    self.orient_camera_on_event(dir);
    true
  }
}
<|endoftext|>