<commit_before>use crate::types::*;
use crate::types::flags::*;
use crate::types::generation::*;
use crate::types::parsing::*;

use cookie_factory::{GenError, do_gen, gen_call, gen_cond};
use nom::*;

/// Protocol metadata
pub mod metadata {
    use super::*;

    /// The name of the protocol
    pub const NAME:          &str           = "{{protocol.name}}";
    /// The major version of the protocol
    pub const MAJOR_VERSION: ShortShortUInt = {{protocol.major_version}};
    /// The minor version of the protocol
    pub const MINOR_VERSION: ShortShortUInt = {{protocol.minor_version}};
    /// The revision (version) of the protocol
    pub const REVISION:      ShortShortUInt = {{protocol.revision}};
    /// The default port of the protocol
    pub const PORT:          LongUInt       = {{protocol.port}};
    /// The copyright holding the protocol
    pub const COPYRIGHT:     &str           = r#"{{protocol.copyright}}"#;
}

/// Protocol constants
pub mod constants {
    use super::*;

    {{#each protocol.constants as |constant| ~}}
    /// {{constant.name}} (Generated)
    pub const {{sanitize_name constant.name}}: {{constant.type}} = {{constant.value}};
    {{/each ~}}
}

/// An AMQP Error
#[derive(Clone, Debug, PartialEq)]
pub enum AMQPError {
    /// A soft AMQP error
    Soft(AMQPSoftError),
    /// A hard AMQP error
    Hard(AMQPHardError),
}

impl AMQPError {
    /// Get the id of the error
    pub fn get_id(&self) -> ShortUInt {
        match *self {
            AMQPError::Soft(ref s) => s.get_id(),
            AMQPError::Hard(ref h) => h.get_id(),
        }
    }

    /// Get the error corresponding to an id
    pub fn from_id(id: ShortUInt) -> Option<AMQPError> {
        AMQPSoftError::from_id(id).map(AMQPError::Soft).or_else(|| AMQPHardError::from_id(id).map(AMQPError::Hard))
    }
}

/// The available soft AMQP errors
#[derive(Clone, Debug, PartialEq)]
pub enum AMQPSoftError {
    {{#each protocol.soft_errors as |constant| ~}}
    /// {{{constant.name}}} (Generated)
    {{camel constant.name}},
    {{/each ~}}
}

impl AMQPSoftError {
    /// Get the id of the soft error
    pub fn get_id(&self) -> ShortUInt {
        match *self {
            {{#each protocol.soft_errors as |constant| ~}}
            AMQPSoftError::{{camel constant.name}} => {{constant.value}},
            {{/each ~}}
        }
    }

    /// Get the soft error corresponding to an id
    pub fn from_id(id: ShortUInt) -> Option<AMQPSoftError> {
        match id {
            {{#each protocol.soft_errors as |constant| ~}}
            {{constant.value}} => Some(AMQPSoftError::{{camel constant.name}}),
            {{/each ~}}
            _                  => None,
        }
    }
}

/// The available hard AMQP errors
#[derive(Clone, Debug, PartialEq)]
pub enum AMQPHardError {
    {{#each protocol.hard_errors as |constant| ~}}
    /// {{{constant.name}}} (Generated)
    {{camel constant.name}},
    {{/each ~}}
}

impl AMQPHardError {
    /// Get the id of the hard error
    pub fn get_id(&self) -> ShortUInt {
        match *self {
            {{#each protocol.hard_errors as |constant| ~}}
            AMQPHardError::{{camel constant.name}} => {{constant.value}},
            {{/each ~}}
        }
    }

    /// Get the hard error corresponding to an id
    pub fn from_id(id: ShortUInt) -> Option<AMQPHardError> {
        match id {
            {{#each protocol.hard_errors as |constant| ~}}
            {{constant.value}} => Some(AMQPHardError::{{camel constant.name}}),
            {{/each ~}}
            _                  => None,
        }
    }
}

{{#each protocol.classes as |class| ~}}
use self::{{snake class.name}}::parse_{{snake class.name}};
{{/each ~}}

named_attr!(#[doc =  "Parse an AMQP class"], pub parse_class<AMQPClass>, switch!(parse_id,
    {{#each protocol.classes as |class| ~}}
    {{class.id}} => map!(call!(parse_{{snake class.name}}), AMQPClass::{{camel class.name}}) {{#unless @last ~}}|{{/unless ~}}
    {{/each ~}}
));

/// Serialize an AMQP class
pub fn gen_class<'a>(input: (&'a mut [u8], usize), class: &AMQPClass) -> Result<(&'a mut [u8], usize), GenError> {
    match *class {
        {{#each protocol.classes as |class| ~}}
        AMQPClass::{{camel class.name}}(ref {{snake class.name}}) => {{snake class.name}}::gen_{{snake class.name}}(input, {{snake class.name}}),
        {{/each ~}}
    }
}

/// The available AMQP classes
#[derive(Clone, Debug, PartialEq)]
pub enum AMQPClass {
    {{#each protocol.classes as |class| ~}}
    /// {{class.name}} (Generated)
    {{camel class.name}}({{snake class.name}}::AMQPMethod),
    {{/each ~}}
}

{{#each protocol.classes as |class|}}
/// {{class.name}} (generated)
pub mod {{snake class.name}} {
    use super::*;

    named_attr!(#[doc = "Parse {{class.name}} (Generated)"], pub parse_{{snake class.name}}<{{snake class.name}}::AMQPMethod>, switch!(parse_id,
        {{#each class.methods as |method| ~}}
        {{method.id}} => map!(call!(parse_{{snake method.name}}), AMQPMethod::{{camel method.name}}) {{#unless @last ~}}|{{/unless ~}}
        {{/each ~}}
    ));

    /// Serialize {{class.name}} (Generated)
    pub fn gen_{{snake class.name}}<'a>(input: (&'a mut [u8], usize), method: &AMQPMethod) -> Result<(&'a mut [u8], usize), GenError> {
        match *method {
            {{#each class.methods as |method| ~}}
            AMQPMethod::{{camel method.name}}(ref {{snake method.name}}) => {
                do_gen!(input,
                    gen_id(&{{class.id}}) >>
                    gen_{{snake method.name}}({{snake method.name}})
                )
            },
            {{/each ~}}
        }
    }

    /// The available methods in {{class.name}}
    #[derive(Clone, Debug, PartialEq)]
    pub enum AMQPMethod {
        {{#each class.methods as |method| ~}}
        /// {{method.name}} (Generated)
        {{camel method.name}}({{camel method.name}}),
        {{/each ~}}
    }

    {{#each class.methods as |method|}}
    /// {{method.name}} (Generated)
    #[derive(Clone, Debug, PartialEq)]
    pub struct {{camel method.name}} {
        {{#each_argument method.arguments as |argument| ~}}
        {{#if argument_is_value ~}}
        /// {{argument.name}} (Generated)
        pub {{snake argument.name}}: {{argument.type}},
        {{else}}
        {{#each_flag argument as |flag| ~}}
        /// {{flag.name}} (Generated)
        pub {{snake flag.name}}: Boolean,
        {{/each_flag ~}}
        {{/if ~}}
        {{/each_argument ~}}
    }

    named_attr!(#[doc = "Parse {{method.name}} (Generated)"], pub parse_{{snake method.name}}<{{camel method.name}}>, do_parse!(
        {{#each_argument method.arguments as |argument| ~}}
        {{#if argument_is_value ~}}
        {{snake argument.name}}: parse_{{snake_type argument.type}} >>
        {{else}}
        /* FIXME: support multiple flags structs? */
        flags: apply!(parse_flags, &[
            {{#each_flag argument as |flag| ~}}
            "{{flag.name}}",
            {{/each_flag ~}}
        ]) >>
        {{/if ~}}
        {{/each_argument ~}}
        ({{camel method.name}} {
            {{#each_argument method.arguments as |argument| ~}}
            {{#if argument_is_value ~}}
            {{snake argument.name}},
            {{else}}
            {{#each_flag argument as |flag| ~}}
            {{snake flag.name}}: flags.get_flag("{{snake flag.name}}").unwrap_or({{flag.default_value}}),
            {{/each_flag ~}}
            {{/if ~}}
            {{/each_argument ~}}
        })
    ));

    /// Serialize {{method.name}} (Generated)
    pub fn gen_{{snake method.name}}<'a>(input: (&'a mut [u8], usize), {{#if method.arguments ~}}method{{else}}_{{/if ~}}: &{{camel method.name}}) -> Result<(&'a mut [u8],usize), GenError> {
        {{#if (method_has_flags method) ~}}
        /* FIXME: support multiple flags structs? */
        let mut flags = AMQPFlags::default();
        {{#each_argument method.arguments as |argument| ~}}
        {{#unless argument_is_value ~}}
        {{#each_flag argument as |flag| ~}}
        flags.add_flag("{{snake flag.name}}".to_string(), method.{{snake flag.name}});
        {{/each_flag ~}}
        {{/unless ~}}
        {{/each_argument ~}}
        {{/if ~}}
        do_gen!(input,
            gen_id(&{{method.id}})
            {{#each_argument method.arguments as |argument| ~}}
            {{#if argument_is_value ~}}
            >> gen_{{snake_type argument.type}}(&method.{{snake argument.name}})
            {{else}}
            >> gen_flags(&flags)
            {{/if ~}}
            {{/each_argument ~}}
        )
    }
    {{/each ~}}
    {{#if class.properties ~}}
    /// {{class.name}} properties (Generated)
    #[derive(Clone, Debug, PartialEq)]
    pub struct AMQPProperties {
        {{#each class.properties as |property| ~}}
        {{snake property.name}}: Option<{{property.type}}>,
        {{/each ~}}
    }

    impl Default for AMQPProperties {
        fn default() -> AMQPProperties {
            AMQPProperties {
                {{#each class.properties as |property| ~}}
                {{snake property.name}}: None,
                {{/each ~}}
            }
        }
    }

    impl AMQPProperties {
        {{#each class.properties as |property| ~}}
        /// Set {{property.name}} (Generated)
        pub fn with_{{snake property.name}}(mut self, value: {{property.type}}) -> AMQPProperties {
            self.{{snake property.name}} = Some(value);
            self
        }
        {{/each ~}}

        {{#each class.properties as |property| ~}}
        /// Get {{property.name}} (Generated)
        pub fn {{snake property.name}}(&self) -> &Option<{{property.type}}> {
            &self.{{snake property.name}}
        }
        {{/each ~}}

        /// Get the bitpask for serialization (Generated)
        pub fn bitmask(&self) -> ShortUInt {
            {{#each class.properties as |property| ~}}
            (if self.{{snake property.name}}.is_some() { 1 << (15 - {{@index}}) } else { 0 }) {{#unless @last ~}} + {{/unless ~}}
            {{/each ~}}
        }
    }

    named_attr!(#[doc = "Parse {{class.name}} properties (Generated)"], pub parse_properties<AMQPProperties>, do_parse!(
        flags: parse_short_uint >>
        {{#each class.properties as |property| ~}}
        {{snake property.name}}: cond!(flags & (1 << (15 - {{@index}})) != 0, parse_{{snake_type property.type}}) >>
        {{/each ~}}
        (AMQPProperties {
            {{#each class.properties as |property| ~}}
            {{snake property.name}},
            {{/each ~}}
        })
    ));

    /// Serialize {{class.name}} properties (Generated)
    pub fn gen_properties<'a>(input:(&'a mut [u8],usize), props: &AMQPProperties) -> Result<(&'a mut [u8],usize),GenError> {
        do_gen!(input,
            gen_short_uint(&props.bitmask())
            {{#each class.properties as |property| ~}}
            >> gen_cond!(props.{{snake property.name}}.is_some(), gen_call!(gen_{{snake_type property.type}}, &props.{{snake property.name}}.as_ref().unwrap()))
            {{/each ~}}
        )
    }
    {{/if ~}}
}
{{/each ~}}
<commit_msg>protocol: drop useless FIXMEs<commit_after>use crate::types::*;
use crate::types::flags::*;
use crate::types::generation::*;
use crate::types::parsing::*;

use cookie_factory::{GenError, do_gen, gen_call, gen_cond};
use nom::*;

/// Protocol metadata
pub mod metadata {
    use super::*;

    /// The name of the protocol
    pub const NAME:          &str           = "{{protocol.name}}";
    /// The major version of the protocol
    pub const MAJOR_VERSION: ShortShortUInt = {{protocol.major_version}};
    /// The minor version of the protocol
    pub const MINOR_VERSION: ShortShortUInt = {{protocol.minor_version}};
    /// The revision (version) of the protocol
    pub const REVISION:      ShortShortUInt = {{protocol.revision}};
    /// The default port of the protocol
    pub const PORT:          LongUInt       = {{protocol.port}};
    /// The copyright holding the protocol
    pub const COPYRIGHT:     &str           = r#"{{protocol.copyright}}"#;
}

/// Protocol constants
pub mod constants {
    use super::*;

    {{#each protocol.constants as |constant| ~}}
    /// {{constant.name}} (Generated)
    pub const {{sanitize_name constant.name}}: {{constant.type}} = {{constant.value}};
    {{/each ~}}
}

/// An AMQP Error
#[derive(Clone, Debug, PartialEq)]
pub enum AMQPError {
    /// A soft AMQP error
    Soft(AMQPSoftError),
    /// A hard AMQP error
    Hard(AMQPHardError),
}

impl AMQPError {
    /// Get the id of the error
    pub fn get_id(&self) -> ShortUInt {
        match *self {
            AMQPError::Soft(ref s) => s.get_id(),
            AMQPError::Hard(ref h) => h.get_id(),
        }
    }

    /// Get the error corresponding to an id
    pub fn from_id(id: ShortUInt) -> Option<AMQPError> {
        AMQPSoftError::from_id(id).map(AMQPError::Soft).or_else(|| AMQPHardError::from_id(id).map(AMQPError::Hard))
    }
}

/// The available soft AMQP errors
#[derive(Clone, Debug, PartialEq)]
pub enum AMQPSoftError {
    {{#each protocol.soft_errors as |constant| ~}}
    /// {{{constant.name}}} (Generated)
    {{camel constant.name}},
    {{/each ~}}
}

impl AMQPSoftError {
    /// Get the id of the soft error
    pub fn get_id(&self) -> ShortUInt {
        match *self {
            {{#each protocol.soft_errors as |constant| ~}}
            AMQPSoftError::{{camel constant.name}} => {{constant.value}},
            {{/each ~}}
        }
    }

    /// Get the soft error corresponding to an id
    pub fn from_id(id: ShortUInt) -> Option<AMQPSoftError> {
        match id {
            {{#each protocol.soft_errors as |constant| ~}}
            {{constant.value}} => Some(AMQPSoftError::{{camel constant.name}}),
            {{/each ~}}
            _                  => None,
        }
    }
}

/// The available hard AMQP errors
#[derive(Clone, Debug, PartialEq)]
pub enum AMQPHardError {
    {{#each protocol.hard_errors as |constant| ~}}
    /// {{{constant.name}}} (Generated)
    {{camel constant.name}},
    {{/each ~}}
}

impl AMQPHardError {
    /// Get the id of the hard error
    pub fn get_id(&self) -> ShortUInt {
        match *self {
            {{#each protocol.hard_errors as |constant| ~}}
            AMQPHardError::{{camel constant.name}} => {{constant.value}},
            {{/each ~}}
        }
    }

    /// Get the hard error corresponding to an id
    pub fn from_id(id: ShortUInt) -> Option<AMQPHardError> {
        match id {
            {{#each protocol.hard_errors as |constant| ~}}
            {{constant.value}} => Some(AMQPHardError::{{camel constant.name}}),
            {{/each ~}}
            _                  => None,
        }
    }
}

{{#each protocol.classes as |class| ~}}
use self::{{snake class.name}}::parse_{{snake class.name}};
{{/each ~}}

named_attr!(#[doc =  "Parse an AMQP class"], pub parse_class<AMQPClass>, switch!(parse_id,
    {{#each protocol.classes as |class| ~}}
    {{class.id}} => map!(call!(parse_{{snake class.name}}), AMQPClass::{{camel class.name}}) {{#unless @last ~}}|{{/unless ~}}
    {{/each ~}}
));

/// Serialize an AMQP class
pub fn gen_class<'a>(input: (&'a mut [u8], usize), class: &AMQPClass) -> Result<(&'a mut [u8], usize), GenError> {
    match *class {
        {{#each protocol.classes as |class| ~}}
        AMQPClass::{{camel class.name}}(ref {{snake class.name}}) => {{snake class.name}}::gen_{{snake class.name}}(input, {{snake class.name}}),
        {{/each ~}}
    }
}

/// The available AMQP classes
#[derive(Clone, Debug, PartialEq)]
pub enum AMQPClass {
    {{#each protocol.classes as |class| ~}}
    /// {{class.name}} (Generated)
    {{camel class.name}}({{snake class.name}}::AMQPMethod),
    {{/each ~}}
}

{{#each protocol.classes as |class|}}
/// {{class.name}} (generated)
pub mod {{snake class.name}} {
    use super::*;

    named_attr!(#[doc = "Parse {{class.name}} (Generated)"], pub parse_{{snake class.name}}<{{snake class.name}}::AMQPMethod>, switch!(parse_id,
        {{#each class.methods as |method| ~}}
        {{method.id}} => map!(call!(parse_{{snake method.name}}), AMQPMethod::{{camel method.name}}) {{#unless @last ~}}|{{/unless ~}}
        {{/each ~}}
    ));

    /// Serialize {{class.name}} (Generated)
    pub fn gen_{{snake class.name}}<'a>(input: (&'a mut [u8], usize), method: &AMQPMethod) -> Result<(&'a mut [u8], usize), GenError> {
        match *method {
            {{#each class.methods as |method| ~}}
            AMQPMethod::{{camel method.name}}(ref {{snake method.name}}) => {
                do_gen!(input,
                    gen_id(&{{class.id}}) >>
                    gen_{{snake method.name}}({{snake method.name}})
                )
            },
            {{/each ~}}
        }
    }

    /// The available methods in {{class.name}}
    #[derive(Clone, Debug, PartialEq)]
    pub enum AMQPMethod {
        {{#each class.methods as |method| ~}}
        /// {{method.name}} (Generated)
        {{camel method.name}}({{camel method.name}}),
        {{/each ~}}
    }

    {{#each class.methods as |method|}}
    /// {{method.name}} (Generated)
    #[derive(Clone, Debug, PartialEq)]
    pub struct {{camel method.name}} {
        {{#each_argument method.arguments as |argument| ~}}
        {{#if argument_is_value ~}}
        /// {{argument.name}} (Generated)
        pub {{snake argument.name}}: {{argument.type}},
        {{else}}
        {{#each_flag argument as |flag| ~}}
        /// {{flag.name}} (Generated)
        pub {{snake flag.name}}: Boolean,
        {{/each_flag ~}}
        {{/if ~}}
        {{/each_argument ~}}
    }

    named_attr!(#[doc = "Parse {{method.name}} (Generated)"], pub parse_{{snake method.name}}<{{camel method.name}}>, do_parse!(
        {{#each_argument method.arguments as |argument| ~}}
        {{#if argument_is_value ~}}
        {{snake argument.name}}: parse_{{snake_type argument.type}} >>
        {{else}}
        flags: apply!(parse_flags, &[
            {{#each_flag argument as |flag| ~}}
            "{{flag.name}}",
            {{/each_flag ~}}
        ]) >>
        {{/if ~}}
        {{/each_argument ~}}
        ({{camel method.name}} {
            {{#each_argument method.arguments as |argument| ~}}
            {{#if argument_is_value ~}}
            {{snake argument.name}},
            {{else}}
            {{#each_flag argument as |flag| ~}}
            {{snake flag.name}}: flags.get_flag("{{snake flag.name}}").unwrap_or({{flag.default_value}}),
            {{/each_flag ~}}
            {{/if ~}}
            {{/each_argument ~}}
        })
    ));

    /// Serialize {{method.name}} (Generated)
    pub fn gen_{{snake method.name}}<'a>(input: (&'a mut [u8], usize), {{#if method.arguments ~}}method{{else}}_{{/if ~}}: &{{camel method.name}}) -> Result<(&'a mut [u8],usize), GenError> {
        {{#if (method_has_flags method) ~}}
        let mut flags = AMQPFlags::default();
        {{#each_argument method.arguments as |argument| ~}}
        {{#unless argument_is_value ~}}
        {{#each_flag argument as |flag| ~}}
        flags.add_flag("{{snake flag.name}}".to_string(), method.{{snake flag.name}});
        {{/each_flag ~}}
        {{/unless ~}}
        {{/each_argument ~}}
        {{/if ~}}
        do_gen!(input,
            gen_id(&{{method.id}})
            {{#each_argument method.arguments as |argument| ~}}
            {{#if argument_is_value ~}}
            >> gen_{{snake_type argument.type}}(&method.{{snake argument.name}})
            {{else}}
            >> gen_flags(&flags)
            {{/if ~}}
            {{/each_argument ~}}
        )
    }
    {{/each ~}}
    {{#if class.properties ~}}
    /// {{class.name}} properties (Generated)
    #[derive(Clone, Debug, PartialEq)]
    pub struct AMQPProperties {
        {{#each class.properties as |property| ~}}
        {{snake property.name}}: Option<{{property.type}}>,
        {{/each ~}}
    }

    impl Default for AMQPProperties {
        fn default() -> AMQPProperties {
            AMQPProperties {
                {{#each class.properties as |property| ~}}
                {{snake property.name}}: None,
                {{/each ~}}
            }
        }
    }

    impl AMQPProperties {
        {{#each class.properties as |property| ~}}
        /// Set {{property.name}} (Generated)
        pub fn with_{{snake property.name}}(mut self, value: {{property.type}}) -> AMQPProperties {
            self.{{snake property.name}} = Some(value);
            self
        }
        {{/each ~}}

        {{#each class.properties as |property| ~}}
        /// Get {{property.name}} (Generated)
        pub fn {{snake property.name}}(&self) -> &Option<{{property.type}}> {
            &self.{{snake property.name}}
        }
        {{/each ~}}

        /// Get the bitpask for serialization (Generated)
        pub fn bitmask(&self) -> ShortUInt {
            {{#each class.properties as |property| ~}}
            (if self.{{snake property.name}}.is_some() { 1 << (15 - {{@index}}) } else { 0 }) {{#unless @last ~}} + {{/unless ~}}
            {{/each ~}}
        }
    }

    named_attr!(#[doc = "Parse {{class.name}} properties (Generated)"], pub parse_properties<AMQPProperties>, do_parse!(
        flags: parse_short_uint >>
        {{#each class.properties as |property| ~}}
        {{snake property.name}}: cond!(flags & (1 << (15 - {{@index}})) != 0, parse_{{snake_type property.type}}) >>
        {{/each ~}}
        (AMQPProperties {
            {{#each class.properties as |property| ~}}
            {{snake property.name}},
            {{/each ~}}
        })
    ));

    /// Serialize {{class.name}} properties (Generated)
    pub fn gen_properties<'a>(input:(&'a mut [u8],usize), props: &AMQPProperties) -> Result<(&'a mut [u8],usize),GenError> {
        do_gen!(input,
            gen_short_uint(&props.bitmask())
            {{#each class.properties as |property| ~}}
            >> gen_cond!(props.{{snake property.name}}.is_some(), gen_call!(gen_{{snake_type property.type}}, &props.{{snake property.name}}.as_ref().unwrap()))
            {{/each ~}}
        )
    }
    {{/if ~}}
}
{{/each ~}}
<|endoftext|>


<commit_before>//! Unix handling of child processes
//!
//! Right now the only "fancy" thing about this is how we implement the
//! `Future` implementation on `Child` to get the exit status. Unix offers
//! no way to register a child with epoll, and the only real way to get a
//! notification when a process exits is the SIGCHLD signal.
//!
//! Signal handling in general is *super* hairy and complicated, and it's even
//! more complicated here with the fact that signals are coalesced, so we may
//! not get a SIGCHLD-per-child.
//!
//! Our best approximation here is to check *all spawned processes* for all
//! SIGCHLD signals received. To do that we create a `Signal`, implemented in
//! the `tokio-net` crate, which is a stream over signals being received.
//!
//! Later when we poll the process's exit status we simply check to see if a
//! SIGCHLD has happened since we last checked, and while that returns "yes" we
//! keep trying.
//!
//! Note that this means that this isn't really scalable, but then again
//! processes in general aren't scalable (e.g. millions) so it shouldn't be that
//! bad in theory...

pub(crate) mod driver;

pub(crate) mod orphan;
use orphan::{OrphanQueue, OrphanQueueImpl, ReapOrphanQueue, Wait};

mod reap;
use reap::Reaper;

use crate::io::PollEvented;
use crate::process::kill::Kill;
use crate::process::SpawnedChild;
use crate::signal::unix::{signal, Signal, SignalKind};

use mio::event::Source;
use mio::unix::SourceFd;
use std::fmt;
use std::fs::File;
use std::future::Future;
use std::io;
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use std::pin::Pin;
use std::process::{Child as StdChild, ExitStatus};
use std::task::Context;
use std::task::Poll;

impl Wait for StdChild {
    fn id(&self) -> u32 {
        self.id()
    }

    fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
        self.try_wait()
    }
}

impl Kill for StdChild {
    fn kill(&mut self) -> io::Result<()> {
        self.kill()
    }
}

lazy_static::lazy_static! {
    static ref ORPHAN_QUEUE: OrphanQueueImpl<StdChild> = OrphanQueueImpl::new();
}

pub(crate) struct GlobalOrphanQueue;

impl fmt::Debug for GlobalOrphanQueue {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        ORPHAN_QUEUE.fmt(fmt)
    }
}

impl ReapOrphanQueue for GlobalOrphanQueue {
    fn reap_orphans(&self) {
        ORPHAN_QUEUE.reap_orphans()
    }
}

impl OrphanQueue<StdChild> for GlobalOrphanQueue {
    fn push_orphan(&self, orphan: StdChild) {
        ORPHAN_QUEUE.push_orphan(orphan)
    }
}

#[must_use = "futures do nothing unless polled"]
pub(crate) struct Child {
    inner: Reaper<StdChild, GlobalOrphanQueue, Signal>,
}

impl fmt::Debug for Child {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt.debug_struct("Child")
            .field("pid", &self.inner.id())
            .finish()
    }
}

pub(crate) fn spawn_child(cmd: &mut std::process::Command) -> io::Result<SpawnedChild> {
    let mut child = cmd.spawn()?;
    let stdin = stdio(child.stdin.take())?;
    let stdout = stdio(child.stdout.take())?;
    let stderr = stdio(child.stderr.take())?;

    let signal = signal(SignalKind::child())?;

    Ok(SpawnedChild {
        child: Child {
            inner: Reaper::new(child, GlobalOrphanQueue, signal),
        },
        stdin,
        stdout,
        stderr,
    })
}

impl Child {
    pub(crate) fn id(&self) -> u32 {
        self.inner.id()
    }

    pub(crate) fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
        self.inner.inner_mut().try_wait()
    }
}

impl Kill for Child {
    fn kill(&mut self) -> io::Result<()> {
        self.inner.kill()
    }
}

impl Future for Child {
    type Output = io::Result<ExitStatus>;

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        Pin::new(&mut self.inner).poll(cx)
    }
}

#[derive(Debug)]
pub(crate) struct Pipe {
    // Actually a pipe and not a File. However, we are reusing `File` to get
    // close on drop. This is a similar trick as `mio`.
    fd: File,
}

impl<'a> io::Read for &'a Pipe {
    fn read(&mut self, bytes: &mut [u8]) -> io::Result<usize> {
        (&self.fd).read(bytes)
    }
}

impl<'a> io::Write for &'a Pipe {
    fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
        (&self.fd).write(bytes)
    }

    fn flush(&mut self) -> io::Result<()> {
        (&self.fd).flush()
    }
}

impl AsRawFd for Pipe {
    fn as_raw_fd(&self) -> RawFd {
        self.fd.as_raw_fd()
    }
}

impl Source for Pipe {
    fn register(
        &mut self,
        registry: &mio::Registry,
        token: mio::Token,
        interest: mio::Interest,
    ) -> io::Result<()> {
        SourceFd(&self.as_raw_fd()).register(registry, token, interest)
    }

    fn reregister(
        &mut self,
        registry: &mio::Registry,
        token: mio::Token,
        interest: mio::Interest,
    ) -> io::Result<()> {
        SourceFd(&self.as_raw_fd()).reregister(registry, token, interest)
    }

    fn deregister(&mut self, registry: &mio::Registry) -> io::Result<()> {
        SourceFd(&self.as_raw_fd()).deregister(registry)
    }
}

pub(crate) type ChildStdin = PollEvented<Pipe>;
pub(crate) type ChildStdout = PollEvented<Pipe>;
pub(crate) type ChildStderr = PollEvented<Pipe>;

fn stdio<T>(option: Option<T>) -> io::Result<Option<PollEvented<Pipe>>>
where
    T: IntoRawFd,
{
    let io = match option {
        Some(io) => io,
        None => return Ok(None),
    };

    // Set the fd to nonblocking before we pass it to the event loop
    let fd = unsafe {
        let fd = io.into_raw_fd();
        let r = libc::fcntl(fd, libc::F_GETFL);
        if r == -1 {
            return Err(io::Error::last_os_error());
        }
        let r = libc::fcntl(fd, libc::F_SETFL, r | libc::O_NONBLOCK);
        if r == -1 {
            return Err(io::Error::last_os_error());
        }

        File::from_raw_fd(fd)
    };

    Ok(Some(PollEvented::new(Pipe { fd })?))
}
<commit_msg>process: fix potential file descriptor leak (#3129)<commit_after>//! Unix handling of child processes
//!
//! Right now the only "fancy" thing about this is how we implement the
//! `Future` implementation on `Child` to get the exit status. Unix offers
//! no way to register a child with epoll, and the only real way to get a
//! notification when a process exits is the SIGCHLD signal.
//!
//! Signal handling in general is *super* hairy and complicated, and it's even
//! more complicated here with the fact that signals are coalesced, so we may
//! not get a SIGCHLD-per-child.
//!
//! Our best approximation here is to check *all spawned processes* for all
//! SIGCHLD signals received. To do that we create a `Signal`, implemented in
//! the `tokio-net` crate, which is a stream over signals being received.
//!
//! Later when we poll the process's exit status we simply check to see if a
//! SIGCHLD has happened since we last checked, and while that returns "yes" we
//! keep trying.
//!
//! Note that this means that this isn't really scalable, but then again
//! processes in general aren't scalable (e.g. millions) so it shouldn't be that
//! bad in theory...

pub(crate) mod driver;

pub(crate) mod orphan;
use orphan::{OrphanQueue, OrphanQueueImpl, ReapOrphanQueue, Wait};

mod reap;
use reap::Reaper;

use crate::io::PollEvented;
use crate::process::kill::Kill;
use crate::process::SpawnedChild;
use crate::signal::unix::{signal, Signal, SignalKind};

use mio::event::Source;
use mio::unix::SourceFd;
use std::fmt;
use std::fs::File;
use std::future::Future;
use std::io;
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use std::pin::Pin;
use std::process::{Child as StdChild, ExitStatus};
use std::task::Context;
use std::task::Poll;

impl Wait for StdChild {
    fn id(&self) -> u32 {
        self.id()
    }

    fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
        self.try_wait()
    }
}

impl Kill for StdChild {
    fn kill(&mut self) -> io::Result<()> {
        self.kill()
    }
}

lazy_static::lazy_static! {
    static ref ORPHAN_QUEUE: OrphanQueueImpl<StdChild> = OrphanQueueImpl::new();
}

pub(crate) struct GlobalOrphanQueue;

impl fmt::Debug for GlobalOrphanQueue {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        ORPHAN_QUEUE.fmt(fmt)
    }
}

impl ReapOrphanQueue for GlobalOrphanQueue {
    fn reap_orphans(&self) {
        ORPHAN_QUEUE.reap_orphans()
    }
}

impl OrphanQueue<StdChild> for GlobalOrphanQueue {
    fn push_orphan(&self, orphan: StdChild) {
        ORPHAN_QUEUE.push_orphan(orphan)
    }
}

#[must_use = "futures do nothing unless polled"]
pub(crate) struct Child {
    inner: Reaper<StdChild, GlobalOrphanQueue, Signal>,
}

impl fmt::Debug for Child {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt.debug_struct("Child")
            .field("pid", &self.inner.id())
            .finish()
    }
}

pub(crate) fn spawn_child(cmd: &mut std::process::Command) -> io::Result<SpawnedChild> {
    let mut child = cmd.spawn()?;
    let stdin = stdio(child.stdin.take())?;
    let stdout = stdio(child.stdout.take())?;
    let stderr = stdio(child.stderr.take())?;

    let signal = signal(SignalKind::child())?;

    Ok(SpawnedChild {
        child: Child {
            inner: Reaper::new(child, GlobalOrphanQueue, signal),
        },
        stdin,
        stdout,
        stderr,
    })
}

impl Child {
    pub(crate) fn id(&self) -> u32 {
        self.inner.id()
    }

    pub(crate) fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
        self.inner.inner_mut().try_wait()
    }
}

impl Kill for Child {
    fn kill(&mut self) -> io::Result<()> {
        self.inner.kill()
    }
}

impl Future for Child {
    type Output = io::Result<ExitStatus>;

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        Pin::new(&mut self.inner).poll(cx)
    }
}

#[derive(Debug)]
pub(crate) struct Pipe {
    // Actually a pipe and not a File. However, we are reusing `File` to get
    // close on drop. This is a similar trick as `mio`.
    fd: File,
}

impl<T: IntoRawFd> From<T> for Pipe {
    fn from(fd: T) -> Self {
        let fd = unsafe { File::from_raw_fd(fd.into_raw_fd()) };
        Self { fd }
    }
}

impl<'a> io::Read for &'a Pipe {
    fn read(&mut self, bytes: &mut [u8]) -> io::Result<usize> {
        (&self.fd).read(bytes)
    }
}

impl<'a> io::Write for &'a Pipe {
    fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
        (&self.fd).write(bytes)
    }

    fn flush(&mut self) -> io::Result<()> {
        (&self.fd).flush()
    }
}

impl AsRawFd for Pipe {
    fn as_raw_fd(&self) -> RawFd {
        self.fd.as_raw_fd()
    }
}

impl Source for Pipe {
    fn register(
        &mut self,
        registry: &mio::Registry,
        token: mio::Token,
        interest: mio::Interest,
    ) -> io::Result<()> {
        SourceFd(&self.as_raw_fd()).register(registry, token, interest)
    }

    fn reregister(
        &mut self,
        registry: &mio::Registry,
        token: mio::Token,
        interest: mio::Interest,
    ) -> io::Result<()> {
        SourceFd(&self.as_raw_fd()).reregister(registry, token, interest)
    }

    fn deregister(&mut self, registry: &mio::Registry) -> io::Result<()> {
        SourceFd(&self.as_raw_fd()).deregister(registry)
    }
}

pub(crate) type ChildStdin = PollEvented<Pipe>;
pub(crate) type ChildStdout = PollEvented<Pipe>;
pub(crate) type ChildStderr = PollEvented<Pipe>;

fn stdio<T>(option: Option<T>) -> io::Result<Option<PollEvented<Pipe>>>
where
    T: IntoRawFd,
{
    let io = match option {
        Some(io) => io,
        None => return Ok(None),
    };

    // Set the fd to nonblocking before we pass it to the event loop
    let pipe = unsafe {
        let pipe = Pipe::from(io);
        let fd = pipe.as_raw_fd();
        let r = libc::fcntl(fd, libc::F_GETFL);
        if r == -1 {
            return Err(io::Error::last_os_error());
        }
        let r = libc::fcntl(fd, libc::F_SETFL, r | libc::O_NONBLOCK);
        if r == -1 {
            return Err(io::Error::last_os_error());
        }

        pipe
    };

    Ok(Some(PollEvented::new(pipe)?))
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
#![allow(unused_variables)]
#![deny(bare_trait_objects)]
#![feature(allocator_api)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(const_fn)]
#![feature(nll)]
#![feature(vec_remove_item)]
#![no_std]

#[cfg(test)]
#[macro_use]
extern crate std;

extern crate alloc;
use alloc::borrow::ToOwned;
use alloc::boxed::Box;
use alloc::string::String;
use alloc::vec::Vec;

#[cfg(test)]
#[global_allocator]
static A: std::alloc::System = std::alloc::System;

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum NodeType {
    File,
    Directory,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FileSystemError {
    AlreadyExists,
    DoesNotExist,
    FileRequired,
    DirectoryRequired,
    SeekPastEnd,
    IncorrectOpenMode,
}

// TODO: Implement Append mode
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OpenMode {
    Read,
    Write,
    ReadWrite,
}
impl OpenMode {
    fn can_read(self) -> bool {
        use crate::OpenMode::*;
        match self {
            Read => true,
            Write => false,
            ReadWrite => true,
        }
    }
    fn can_write(self) -> bool {
        use crate::OpenMode::*;
        match self {
            Read => false,
            Write => true,
            ReadWrite => true,
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FileDescriptorId(u32);
impl FileDescriptorId {
    pub fn new(id: u32) -> FileDescriptorId {
        assert!(id != 0);
        FileDescriptorId(id)
    }

    pub fn invalid() -> FileDescriptorId {
        FileDescriptorId(0)
    }

    pub fn is_valid(&self) -> bool {
        self.0 != 0
    }
}

#[derive(Debug)]
pub struct FileDescriptor {
    id: FileDescriptorId,
    path: Vec<String>,
    cursor: usize,
    mode: OpenMode,
}
impl FileDescriptor {
    fn new(id: FileDescriptorId, path: Vec<&str>, mode: OpenMode) -> FileDescriptor {
        assert!(id.is_valid());
        FileDescriptor {
            id,
            path: path.iter().map(|v| (*v).to_owned()).collect(),
            cursor: 0,
            mode,
        }
    }

    pub fn close(&mut self) -> Result<(), !> {
        assert!(self.id.is_valid());
        self.id = FileDescriptorId::invalid();
        debug_assert!(!self.id.is_valid());
        Ok(())
    }
}
impl PartialEq for FileDescriptor {
    fn eq(&self, other: &FileDescriptor) -> bool {
        self.id != FileDescriptorId::invalid() && self.id == other.id
    }
}
impl Drop for FileDescriptor {
    fn drop(&mut self) {
        if self.id.is_valid() {
            // println!("{:?}", self);
            // panic!("Close FileDescriptor before it goes out of scope");
        }
    }
}

#[derive(Debug)]
pub struct RamFS {
    tree: Box<Node>,
    open_fds: Vec<FileDescriptor>,
}
impl RamFS {
    pub fn new() -> RamFS {
        RamFS {
            tree: Box::new(Node::root()),
            open_fds: Vec::new(),
        }
    }

    fn focus_rec<T>(
        cont: &mut Node, mut path: Vec<&str>,
        f: &mut dyn FnMut(&mut Node) -> Result<T, FileSystemError>,
    ) -> Result<T, FileSystemError>
    {
        if path.is_empty() {
            return f(cont);
        }

        match cont {
            Node::Leaf(_) => unimplemented!(),
            Node::Branch(ref mut branch) => {
                let name = path.remove(0);

                let mut i = 0;
                while i < branch.branches.len() {
                    if name == branch.branches[i].name() {
                        return Self::focus_rec(&mut branch.branches[i], path, f);
                    }
                    i += 1;
                }
                Err(FileSystemError::DoesNotExist)
            },
        }
    }

    fn focus<T>(
        &mut self, path: Vec<&str>, f: &mut dyn FnMut(&mut Node) -> Result<T, FileSystemError>,
    ) -> Result<T, FileSystemError> {
        RamFS::focus_rec(&mut self.tree, path, f)
    }

    pub fn node_type(&mut self, path: Vec<&str>) -> Result<NodeType, FileSystemError> {
        self.focus(path, &mut |cont| Ok(cont.kind()))
    }

    pub fn exists(&mut self, path: Vec<&str>) -> bool {
        self.node_type(path).is_ok()
    }

    pub fn create_directory(&mut self, path: Vec<&str>) -> Result<(), FileSystemError> {
        assert!(!path.is_empty());

        let mut pre_path: Vec<&str> = path.clone();
        let name = pre_path.pop().unwrap();

        self.focus(pre_path, &mut |cont| match *cont {
            Node::Leaf(_) => unimplemented!(),
            Node::Branch(ref mut b) => {
                b.add_branch(Node::Branch(Branch::new(name)));
                Ok(())
            },
        })
    }

    // pub fn remove_directory(&mut self, path: Vec<&str>, recursive: bool) -> Result<(), FileSystemError>;
    // pub fn rename_directory(&mut self, path: Vec<&str>, new_path: Vec<&str>) -> Result<(), FileSystemError>;

    pub fn create_file(&mut self, path: Vec<&str>, overwrite: bool) -> Result<(), FileSystemError> {
        assert!(!path.is_empty());

        let mut pre_path: Vec<&str> = path.clone();
        let name = pre_path.pop().unwrap();

        self.focus(pre_path, &mut |cont| match *cont {
            Node::Leaf(_) => unimplemented!(),
            Node::Branch(ref mut b) => {
                b.add_branch(Node::Leaf(Leaf::new(name)));
                Ok(())
            },
        })
    }

    // pub fn remove_file(&mut self, path: Vec<&str>, recursive: bool) -> Result<(), FileSystemError>;
    // pub fn rename_file(&mut self, path: Vec<&str>, new_path: Vec<&str>) -> Result<(), FileSystemError>;

    /// Get next free file descriptor id. Suboptimal.
    fn get_free_fd_id(&self) -> FileDescriptorId {
        let mut cand = 1;
        loop {
            let fd_id = FileDescriptorId::new(cand);
            let mut free = true;
            for fd in self.open_fds.iter() {
                if fd.id == fd_id {
                    free = false;
                    break;
                }
            }
            if free {
                return fd_id;
            }

            cand += 1;
        }
    }

    pub fn open_file(
        &mut self, path: Vec<&str>, mode: OpenMode,
    ) -> Result<FileDescriptor, FileSystemError> {
        // TODO: check that path+mode can be opened
        // ^: is it already open? etc.

        Ok(FileDescriptor::new(self.get_free_fd_id(), path, mode))
    }

    fn close_file(&mut self, mut fd: FileDescriptor) -> Result<(), !> {
        self.open_fds.remove_item(&fd);
        fd.id = FileDescriptorId::invalid();
        Ok(())
    }

    pub fn file_size(&mut self, fd: &FileDescriptor) -> Result<usize, FileSystemError> {
        assert!(fd.id.is_valid());

        self.focus(
            fd.path.iter().map(|v| v.as_str()).collect(),
            &mut |cont| match cont {
                Node::Leaf(ref mut leaf) => Ok(leaf.bytes.len()),
                Node::Branch(_) => Err(FileSystemError::FileRequired),
            },
        )
    }

    pub fn file_seek(
        &mut self, fd: &mut FileDescriptor, offset: usize,
    ) -> Result<usize, FileSystemError> {
        assert!(fd.id.is_valid());

        // Prevent lookup when offset == 0
        if offset != 0 && offset > self.file_size(fd)? {
            return Err(FileSystemError::SeekPastEnd);
        }

        fd.cursor = offset;
        Ok(fd.cursor)
    }

    pub fn file_read(
        &mut self, fd: &mut FileDescriptor, count: Option<usize>,
    ) -> Result<Vec<u8>, FileSystemError> {
        assert!(fd.id.is_valid());

        if !fd.mode.can_read() {
            return Err(FileSystemError::IncorrectOpenMode);
        }

        let cursor = fd.cursor;

        let result: Result<Vec<u8>, FileSystemError> = self.focus(
            fd.path.iter().map(|v| v.as_str()).collect(),
            &mut |cont| match cont {
                Node::Leaf(ref mut leaf) => {
                    let iter = leaf.bytes.iter().skip(cursor).copied();
                    if let Some(limit) = count {
                        Ok(iter.take(limit).collect())
                    } else {
                        Ok(iter.collect())
                    }
                },
                Node::Branch(_) => Err(FileSystemError::FileRequired),
            },
        );

        if let Ok(ref bytes) = result {
            fd.cursor = bytes.len();
        }
        result
    }

    pub fn file_write(
        &mut self, fd: &mut FileDescriptor, write_bytes: Vec<u8>,
    ) -> Result<(), FileSystemError> {
        assert!(fd.id.is_valid());

        if !fd.mode.can_write() {
            return Err(FileSystemError::IncorrectOpenMode);
        }

        let mut cursor = fd.cursor;

        let result = self.focus(
            fd.path.iter().map(|v| v.as_str()).collect(),
            &mut |node| match node {
                Node::Leaf(ref mut leaf) => {
                    for byte in &write_bytes {
                        if cursor == leaf.bytes.len() {
                            leaf.bytes.push(*byte);
                        } else {
                            leaf.bytes[cursor] = *byte;
                        }

                        cursor += 1;
                    }
                    Ok(())
                },
                Node::Branch(_) => Err(FileSystemError::FileRequired),
            },
        );

        if result.is_ok() {
            fd.cursor = cursor;
        }
        result
    }
}
impl Default for RamFS {
    fn default() -> Self {
        Self::new()
    }
}

#[derive(Debug)]
enum Node {
    Branch(Branch),
    Leaf(Leaf),
}
impl Node {
    pub const fn root() -> Node {
        Node::Branch(Branch::new_root())
    }

    pub fn name(&self) -> String {
        use crate::Node::*;
        match self {
            Branch(n) => n.name(),
            Leaf(n) => n.name(),
        }
    }

    pub fn kind(&self) -> NodeType {
        use crate::Node::*;
        match self {
            Branch(n) => NodeType::Directory,
            Leaf(n) => NodeType::File,
        }
    }
}

/// Branch, a directory
#[derive(Debug)]
struct Branch {
    name: String,
    branches: Vec<Node>,
}

/// Leaf, a file
#[derive(Debug)]
struct Leaf {
    name: String,
    bytes: Vec<u8>,
}

impl Branch {
    pub const fn new_root() -> Self {
        Self {
            name: String::new(),
            branches: Vec::new(),
        }
    }

    fn new(name: &str) -> Self {
        Self {
            name: name.to_owned(),
            branches: Vec::new(),
        }
    }

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

    pub fn add_branch(&mut self, branch: Node) {
        self.branches.push(branch);
    }
}

impl Leaf {
    fn new(name: &str) -> Self {
        Self {
            name: name.to_owned(),
            bytes: Vec::new(),
        }
    }

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

#[cfg(test)]
mod tests {
    use super::{OpenMode, RamFS};

    #[test]
    fn test_simple_create() {
        let mut fs = RamFS::new();

        assert!(fs.exists(vec![]));
        assert!(!fs.exists(vec!["test"]));
        assert!(!fs.exists(vec!["test", "test_inner"]));

        fs.create_directory(vec!["test"]).unwrap();

        assert!(fs.exists(vec![]));
        assert!(fs.exists(vec!["test"]));
        assert!(!fs.exists(vec!["test", "test_inner"]));

        fs.create_directory(vec!["test", "test_inner"]).unwrap();

        assert!(fs.exists(vec![]));
        assert!(fs.exists(vec!["test"]));
        assert!(fs.exists(vec!["test", "test_inner"]));
        assert!(!fs.exists(vec!["file.txt"]));

        assert!(!fs.exists(vec!["file.txt"]));
        assert!(!fs.exists(vec!["test", "file.txt"]));
        assert!(!fs.exists(vec!["test", "test_inner", "file.txt"]));

        fs.create_file(vec!["test", "file.txt"], false).unwrap();

        assert!(!fs.exists(vec!["file.txt"]));
        assert!(fs.exists(vec!["test", "file.txt"]));
        assert!(!fs.exists(vec!["test", "test_inner", "file.txt"]));

        fs.create_file(vec!["file.txt"], false).unwrap();

        assert!(fs.exists(vec!["file.txt"]));
        assert!(fs.exists(vec!["test", "file.txt"]));
        assert!(!fs.exists(vec!["test", "test_inner", "file.txt"]));

        fs.create_file(vec!["test", "test_inner", "file.txt"], false)
            .unwrap();

        assert!(fs.exists(vec!["file.txt"]));
        assert!(fs.exists(vec!["test", "file.txt"]));
        assert!(fs.exists(vec!["test", "test_inner", "file.txt"]));
    }

    #[test]
    fn test_simple_read_write() {
        let mut fs = RamFS::new();
        fs.create_file(vec!["file.txt"], false).unwrap();

        let fd1 = fs.open_file(vec!["file.txt"], OpenMode::Read).unwrap();
        assert_eq!(fs.file_size(&fd1), Ok(0));
        fs.close_file(fd1).unwrap(); // fd1 moved, cannot be reused

        let mut fd2 = fs.open_file(vec!["file.txt"], OpenMode::Write).unwrap();
        assert_eq!(fs.file_size(&fd2), Ok(0));
        fs.file_write(&mut fd2, "Hello World!".bytes().collect())
            .unwrap();
        assert_eq!(fs.file_size(&fd2), Ok(12));
        fs.close_file(fd2).unwrap(); // fd2 moved, cannot be reused

        let mut fd3 = fs.open_file(vec!["file.txt"], OpenMode::Read).unwrap();
        assert_eq!(fs.file_size(&fd3), Ok(12));
        assert_eq!(
            fs.file_read(&mut fd3, None),
            Ok("Hello World!".bytes().collect())
        );
        fs.close_file(fd3).unwrap(); // fd1 moved, cannot be reused
    }
}
<commit_msg>Fix compilation error in unused code<commit_after>#![allow(dead_code)]
#![allow(unused_variables)]
#![deny(bare_trait_objects)]
#![feature(allocator_api)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(const_fn)]
#![feature(nll)]
#![feature(vec_remove_item)]
#![feature(never_type)]
#![no_std]

#[cfg(test)]
#[macro_use]
extern crate std;

extern crate alloc;
use alloc::borrow::ToOwned;
use alloc::boxed::Box;
use alloc::string::String;
use alloc::vec::Vec;

#[cfg(test)]
#[global_allocator]
static A: std::alloc::System = std::alloc::System;

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum NodeType {
    File,
    Directory,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FileSystemError {
    AlreadyExists,
    DoesNotExist,
    FileRequired,
    DirectoryRequired,
    SeekPastEnd,
    IncorrectOpenMode,
}

// TODO: Implement Append mode
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OpenMode {
    Read,
    Write,
    ReadWrite,
}
impl OpenMode {
    fn can_read(self) -> bool {
        use crate::OpenMode::*;
        match self {
            Read => true,
            Write => false,
            ReadWrite => true,
        }
    }
    fn can_write(self) -> bool {
        use crate::OpenMode::*;
        match self {
            Read => false,
            Write => true,
            ReadWrite => true,
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FileDescriptorId(u32);
impl FileDescriptorId {
    pub fn new(id: u32) -> FileDescriptorId {
        assert!(id != 0);
        FileDescriptorId(id)
    }

    pub fn invalid() -> FileDescriptorId {
        FileDescriptorId(0)
    }

    pub fn is_valid(&self) -> bool {
        self.0 != 0
    }
}

#[derive(Debug)]
pub struct FileDescriptor {
    id: FileDescriptorId,
    path: Vec<String>,
    cursor: usize,
    mode: OpenMode,
}
impl FileDescriptor {
    fn new(id: FileDescriptorId, path: Vec<&str>, mode: OpenMode) -> FileDescriptor {
        assert!(id.is_valid());
        FileDescriptor {
            id,
            path: path.iter().map(|v| (*v).to_owned()).collect(),
            cursor: 0,
            mode,
        }
    }

    pub fn close(&mut self) -> Result<(), !> {
        assert!(self.id.is_valid());
        self.id = FileDescriptorId::invalid();
        debug_assert!(!self.id.is_valid());
        Ok(())
    }
}
impl PartialEq for FileDescriptor {
    fn eq(&self, other: &FileDescriptor) -> bool {
        self.id != FileDescriptorId::invalid() && self.id == other.id
    }
}
impl Drop for FileDescriptor {
    fn drop(&mut self) {
        if self.id.is_valid() {
            // println!("{:?}", self);
            // panic!("Close FileDescriptor before it goes out of scope");
        }
    }
}

#[derive(Debug)]
pub struct RamFS {
    tree: Box<Node>,
    open_fds: Vec<FileDescriptor>,
}
impl RamFS {
    pub fn new() -> RamFS {
        RamFS {
            tree: Box::new(Node::root()),
            open_fds: Vec::new(),
        }
    }

    fn focus_rec<T>(
        cont: &mut Node, mut path: Vec<&str>,
        f: &mut dyn FnMut(&mut Node) -> Result<T, FileSystemError>,
    ) -> Result<T, FileSystemError>
    {
        if path.is_empty() {
            return f(cont);
        }

        match cont {
            Node::Leaf(_) => unimplemented!(),
            Node::Branch(ref mut branch) => {
                let name = path.remove(0);

                let mut i = 0;
                while i < branch.branches.len() {
                    if name == branch.branches[i].name() {
                        return Self::focus_rec(&mut branch.branches[i], path, f);
                    }
                    i += 1;
                }
                Err(FileSystemError::DoesNotExist)
            },
        }
    }

    fn focus<T>(
        &mut self, path: Vec<&str>, f: &mut dyn FnMut(&mut Node) -> Result<T, FileSystemError>,
    ) -> Result<T, FileSystemError> {
        RamFS::focus_rec(&mut self.tree, path, f)
    }

    pub fn node_type(&mut self, path: Vec<&str>) -> Result<NodeType, FileSystemError> {
        self.focus(path, &mut |cont| Ok(cont.kind()))
    }

    pub fn exists(&mut self, path: Vec<&str>) -> bool {
        self.node_type(path).is_ok()
    }

    pub fn create_directory(&mut self, path: Vec<&str>) -> Result<(), FileSystemError> {
        assert!(!path.is_empty());

        let mut pre_path: Vec<&str> = path.clone();
        let name = pre_path.pop().unwrap();

        self.focus(pre_path, &mut |cont| match *cont {
            Node::Leaf(_) => unimplemented!(),
            Node::Branch(ref mut b) => {
                b.add_branch(Node::Branch(Branch::new(name)));
                Ok(())
            },
        })
    }

    // pub fn remove_directory(&mut self, path: Vec<&str>, recursive: bool) -> Result<(), FileSystemError>;
    // pub fn rename_directory(&mut self, path: Vec<&str>, new_path: Vec<&str>) -> Result<(), FileSystemError>;

    pub fn create_file(&mut self, path: Vec<&str>, overwrite: bool) -> Result<(), FileSystemError> {
        assert!(!path.is_empty());

        let mut pre_path: Vec<&str> = path.clone();
        let name = pre_path.pop().unwrap();

        self.focus(pre_path, &mut |cont| match *cont {
            Node::Leaf(_) => unimplemented!(),
            Node::Branch(ref mut b) => {
                b.add_branch(Node::Leaf(Leaf::new(name)));
                Ok(())
            },
        })
    }

    // pub fn remove_file(&mut self, path: Vec<&str>, recursive: bool) -> Result<(), FileSystemError>;
    // pub fn rename_file(&mut self, path: Vec<&str>, new_path: Vec<&str>) -> Result<(), FileSystemError>;

    /// Get next free file descriptor id. Suboptimal.
    fn get_free_fd_id(&self) -> FileDescriptorId {
        let mut cand = 1;
        loop {
            let fd_id = FileDescriptorId::new(cand);
            let mut free = true;
            for fd in self.open_fds.iter() {
                if fd.id == fd_id {
                    free = false;
                    break;
                }
            }
            if free {
                return fd_id;
            }

            cand += 1;
        }
    }

    pub fn open_file(
        &mut self, path: Vec<&str>, mode: OpenMode,
    ) -> Result<FileDescriptor, FileSystemError> {
        // TODO: check that path+mode can be opened
        // ^: is it already open? etc.

        Ok(FileDescriptor::new(self.get_free_fd_id(), path, mode))
    }

    fn close_file(&mut self, mut fd: FileDescriptor) -> Result<(), !> {
        self.open_fds.remove_item(&fd);
        fd.id = FileDescriptorId::invalid();
        Ok(())
    }

    pub fn file_size(&mut self, fd: &FileDescriptor) -> Result<usize, FileSystemError> {
        assert!(fd.id.is_valid());

        self.focus(
            fd.path.iter().map(|v| v.as_str()).collect(),
            &mut |cont| match cont {
                Node::Leaf(ref mut leaf) => Ok(leaf.bytes.len()),
                Node::Branch(_) => Err(FileSystemError::FileRequired),
            },
        )
    }

    pub fn file_seek(
        &mut self, fd: &mut FileDescriptor, offset: usize,
    ) -> Result<usize, FileSystemError> {
        assert!(fd.id.is_valid());

        // Prevent lookup when offset == 0
        if offset != 0 && offset > self.file_size(fd)? {
            return Err(FileSystemError::SeekPastEnd);
        }

        fd.cursor = offset;
        Ok(fd.cursor)
    }

    pub fn file_read(
        &mut self, fd: &mut FileDescriptor, count: Option<usize>,
    ) -> Result<Vec<u8>, FileSystemError> {
        assert!(fd.id.is_valid());

        if !fd.mode.can_read() {
            return Err(FileSystemError::IncorrectOpenMode);
        }

        let cursor = fd.cursor;

        let result: Result<Vec<u8>, FileSystemError> = self.focus(
            fd.path.iter().map(|v| v.as_str()).collect(),
            &mut |cont| match cont {
                Node::Leaf(ref mut leaf) => {
                    let iter = leaf.bytes.iter().skip(cursor).copied();
                    if let Some(limit) = count {
                        Ok(iter.take(limit).collect())
                    } else {
                        Ok(iter.collect())
                    }
                },
                Node::Branch(_) => Err(FileSystemError::FileRequired),
            },
        );

        if let Ok(ref bytes) = result {
            fd.cursor = bytes.len();
        }
        result
    }

    pub fn file_write(
        &mut self, fd: &mut FileDescriptor, write_bytes: Vec<u8>,
    ) -> Result<(), FileSystemError> {
        assert!(fd.id.is_valid());

        if !fd.mode.can_write() {
            return Err(FileSystemError::IncorrectOpenMode);
        }

        let mut cursor = fd.cursor;

        let result = self.focus(
            fd.path.iter().map(|v| v.as_str()).collect(),
            &mut |node| match node {
                Node::Leaf(ref mut leaf) => {
                    for byte in &write_bytes {
                        if cursor == leaf.bytes.len() {
                            leaf.bytes.push(*byte);
                        } else {
                            leaf.bytes[cursor] = *byte;
                        }

                        cursor += 1;
                    }
                    Ok(())
                },
                Node::Branch(_) => Err(FileSystemError::FileRequired),
            },
        );

        if result.is_ok() {
            fd.cursor = cursor;
        }
        result
    }
}
impl Default for RamFS {
    fn default() -> Self {
        Self::new()
    }
}

#[derive(Debug)]
enum Node {
    Branch(Branch),
    Leaf(Leaf),
}
impl Node {
    pub const fn root() -> Node {
        Node::Branch(Branch::new_root())
    }

    pub fn name(&self) -> String {
        use crate::Node::*;
        match self {
            Branch(n) => n.name(),
            Leaf(n) => n.name(),
        }
    }

    pub fn kind(&self) -> NodeType {
        use crate::Node::*;
        match self {
            Branch(n) => NodeType::Directory,
            Leaf(n) => NodeType::File,
        }
    }
}

/// Branch, a directory
#[derive(Debug)]
struct Branch {
    name: String,
    branches: Vec<Node>,
}

/// Leaf, a file
#[derive(Debug)]
struct Leaf {
    name: String,
    bytes: Vec<u8>,
}

impl Branch {
    pub const fn new_root() -> Self {
        Self {
            name: String::new(),
            branches: Vec::new(),
        }
    }

    fn new(name: &str) -> Self {
        Self {
            name: name.to_owned(),
            branches: Vec::new(),
        }
    }

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

    pub fn add_branch(&mut self, branch: Node) {
        self.branches.push(branch);
    }
}

impl Leaf {
    fn new(name: &str) -> Self {
        Self {
            name: name.to_owned(),
            bytes: Vec::new(),
        }
    }

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

#[cfg(test)]
mod tests {
    use super::{OpenMode, RamFS};

    #[test]
    fn test_simple_create() {
        let mut fs = RamFS::new();

        assert!(fs.exists(vec![]));
        assert!(!fs.exists(vec!["test"]));
        assert!(!fs.exists(vec!["test", "test_inner"]));

        fs.create_directory(vec!["test"]).unwrap();

        assert!(fs.exists(vec![]));
        assert!(fs.exists(vec!["test"]));
        assert!(!fs.exists(vec!["test", "test_inner"]));

        fs.create_directory(vec!["test", "test_inner"]).unwrap();

        assert!(fs.exists(vec![]));
        assert!(fs.exists(vec!["test"]));
        assert!(fs.exists(vec!["test", "test_inner"]));
        assert!(!fs.exists(vec!["file.txt"]));

        assert!(!fs.exists(vec!["file.txt"]));
        assert!(!fs.exists(vec!["test", "file.txt"]));
        assert!(!fs.exists(vec!["test", "test_inner", "file.txt"]));

        fs.create_file(vec!["test", "file.txt"], false).unwrap();

        assert!(!fs.exists(vec!["file.txt"]));
        assert!(fs.exists(vec!["test", "file.txt"]));
        assert!(!fs.exists(vec!["test", "test_inner", "file.txt"]));

        fs.create_file(vec!["file.txt"], false).unwrap();

        assert!(fs.exists(vec!["file.txt"]));
        assert!(fs.exists(vec!["test", "file.txt"]));
        assert!(!fs.exists(vec!["test", "test_inner", "file.txt"]));

        fs.create_file(vec!["test", "test_inner", "file.txt"], false)
            .unwrap();

        assert!(fs.exists(vec!["file.txt"]));
        assert!(fs.exists(vec!["test", "file.txt"]));
        assert!(fs.exists(vec!["test", "test_inner", "file.txt"]));
    }

    #[test]
    fn test_simple_read_write() {
        let mut fs = RamFS::new();
        fs.create_file(vec!["file.txt"], false).unwrap();

        let fd1 = fs.open_file(vec!["file.txt"], OpenMode::Read).unwrap();
        assert_eq!(fs.file_size(&fd1), Ok(0));
        fs.close_file(fd1).unwrap(); // fd1 moved, cannot be reused

        let mut fd2 = fs.open_file(vec!["file.txt"], OpenMode::Write).unwrap();
        assert_eq!(fs.file_size(&fd2), Ok(0));
        fs.file_write(&mut fd2, "Hello World!".bytes().collect())
            .unwrap();
        assert_eq!(fs.file_size(&fd2), Ok(12));
        fs.close_file(fd2).unwrap(); // fd2 moved, cannot be reused

        let mut fd3 = fs.open_file(vec!["file.txt"], OpenMode::Read).unwrap();
        assert_eq!(fs.file_size(&fd3), Ok(12));
        assert_eq!(
            fs.file_read(&mut fd3, None),
            Ok("Hello World!".bytes().collect())
        );
        fs.close_file(fd3).unwrap(); // fd1 moved, cannot be reused
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::io::{stderr, Write};
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
use std::str::FromStr;

extern crate clap;
use clap::{App, Arg};

extern crate mio;
use mio::{EventLoop, EventSet, Handler, Token};
use mio::tcp::TcpListener;

const SERVER: Token = Token(0);

struct EchoHandler {
    listener: TcpListener,
    next_token: usize,
}

impl EchoHandler {
    fn new(l: TcpListener) -> EchoHandler {
        EchoHandler {
            listener: l,
            next_token: 1
        }
    }
}

impl Handler for EchoHandler {
    type Message = ();
    type Timeout = ();

    fn ready(&mut self, event_loop: &mut EventLoop<Self>, token: Token, events: EventSet) {
        match token {
            SERVER => {
                let client = match self.listener.accept() {
                    // As per documentation, Ok(None) means WOULDBLOCK.
                    Ok(None) => return,
                    Ok(Some(c)) => {
                        let addr = c.peer_addr().unwrap();
                        write!(stderr(), "Succesful connection from {}\n", addr);
                        c
                    }
                    Err(e) => {
                        write!(stderr(), "Error while accepting: {}\n", e);
                        return;
                    }
                };

                event_loop.register(&client, Token(self.next_token));
                self.next_token += 1;
            }
            _ => {}
        }
    }
}

fn main() {
    let matches = App::new("qotd")
        .author("Justinas Stankevicius")
        .arg(Arg::with_name("port").short("p").takes_value(true))
        .get_matches();

    let port = matches.value_of("port").unwrap_or("7")
        .parse::<u16>().ok().unwrap_or_else(|| {
            write!(stderr(), "An invalid port number supplied, defaulting to 7.\n");
            7
        });

    let ip = Ipv4Addr::new(127, 0, 0, 1);
    let addr = SocketAddrV4::new(ip, port);
    let listener = TcpListener::bind(&SocketAddr::V4(addr)).unwrap();

    let mut event_loop = EventLoop::new().unwrap();
    event_loop.register(&listener, SERVER).unwrap();
    event_loop.run(&mut EchoHandler::new(listener)).unwrap();
}
<commit_msg>[daytime] Accept connections and send a "hello" message.<commit_after>use std::collections::BTreeMap;
use std::io::{stderr, Write};
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};

extern crate clap;
use clap::{App, Arg};

extern crate mio;
use mio::{EventLoop, EventSet, Handler, Token};
use mio::tcp::{TcpListener, TcpStream};

const SERVER: Token = Token(0);

struct EchoHandler {
    connections: BTreeMap<usize, TcpStream>,
    listener: TcpListener,
    next_token: usize,
}

impl EchoHandler {
    fn new(l: TcpListener) -> EchoHandler {
        EchoHandler {
            connections: BTreeMap::new(),
            listener: l,
            next_token: 1
        }
    }

    fn writable(&mut self, event_loop: &mut EventLoop<Self>, token: Token) {
        {
            let conn = self.connections.get_mut(&token.as_usize()).unwrap();
            match conn.write_all("hello".as_bytes()) {
                Ok(_) => {
                    event_loop.deregister(conn).unwrap();
                    let addr = conn.peer_addr().unwrap();
                    write!(stderr(), "Sent the time to {} succesfully\n", addr);
                },
                Err(e) => {
                    write!(stderr(), "Error while writing: {}\n", e);
                }
            }
        }
        self.connections.remove(&token.as_usize()).unwrap();
    }
}

impl Handler for EchoHandler {
    type Message = ();
    type Timeout = ();

    fn ready(&mut self, event_loop: &mut EventLoop<Self>, token: Token, events: EventSet) {
        match token {
            SERVER => {
                let client = match self.listener.accept() {
                    // As per documentation, Ok(None) means WOULDBLOCK.
                    Ok(None) => return,
                    Ok(Some(c)) => {
                        let addr = c.peer_addr().unwrap();
                        write!(stderr(), "Succesful connection from {}\n", addr);
                        c
                    }
                    Err(e) => {
                        write!(stderr(), "Error while accepting: {}\n", e);
                        return;
                    }
                };

                event_loop.register(&client, Token(self.next_token));
                self.connections.insert(self.next_token, client);
                self.next_token += 1;
            }
            _  => {
                if events.is_writable() {
                    self.writable(event_loop, token);
                }
            }
        }
    }
}

fn main() {
    let matches = App::new("qotd")
        .author("Justinas Stankevicius")
        .arg(Arg::with_name("port").short("p").takes_value(true))
        .get_matches();

    let port = matches.value_of("port").unwrap_or("7")
        .parse::<u16>().ok().unwrap_or_else(|| {
            write!(stderr(), "An invalid port number supplied, defaulting to 7.\n");
            7
        });

    let ip = Ipv4Addr::new(127, 0, 0, 1);
    let addr = SocketAddrV4::new(ip, port);
    let listener = TcpListener::bind(&SocketAddr::V4(addr)).unwrap();

    let mut event_loop = EventLoop::new().unwrap();
    event_loop.register(&listener, SERVER).unwrap();
    event_loop.run(&mut EchoHandler::new(listener)).unwrap();
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use app_units::Au;
use font::{Font, FontHandleMethods, FontMetrics, IS_WHITESPACE_SHAPING_FLAG, RunMetrics};
use font::{ShapingOptions};
use platform::font_template::FontTemplateData;
use std::cmp::{Ordering, max};
use std::slice::Iter;
use std::sync::Arc;
use text::glyph::{CharIndex, GlyphStore};
use util::range::Range;
use util::vec::{Comparator, FullBinarySearchMethods};

/// A single "paragraph" of text in one font size and style.
#[derive(Clone, Deserialize, Serialize)]
pub struct TextRun {
    /// The UTF-8 string represented by this text run.
    pub text: Arc<String>,
    pub font_template: Arc<FontTemplateData>,
    pub actual_pt_size: Au,
    pub font_metrics: FontMetrics,
    /// The glyph runs that make up this text run.
    pub glyphs: Arc<Vec<GlyphRun>>,
    pub bidi_level: u8,
}

/// A single series of glyphs within a text run.
#[derive(Clone, Deserialize, Serialize)]
pub struct GlyphRun {
    /// The glyphs.
    pub glyph_store: Arc<GlyphStore>,
    /// The range of characters in the containing run.
    pub range: Range<CharIndex>,
}

pub struct NaturalWordSliceIterator<'a> {
    glyphs: &'a [GlyphRun],
    index: usize,
    range: Range<CharIndex>,
    reverse: bool,
}

struct CharIndexComparator;

impl Comparator<CharIndex, GlyphRun> for CharIndexComparator {
    fn compare(&self, key: &CharIndex, value: &GlyphRun) -> Ordering {
        if *key < value.range.begin() {
            Ordering::Less
        } else if *key >= value.range.end() {
            Ordering::Greater
        } else {
            Ordering::Equal
        }
    }
}

/// A "slice" of a text run is a series of contiguous glyphs that all belong to the same glyph
/// store. Line breaking strategies yield these.
pub struct TextRunSlice<'a> {
    /// The glyph store that the glyphs in this slice belong to.
    pub glyphs: &'a GlyphStore,
    /// The character index that this slice begins at, relative to the start of the *text run*.
    pub offset: CharIndex,
    /// The range that these glyphs encompass, relative to the start of the *glyph store*.
    pub range: Range<CharIndex>,
}

impl<'a> TextRunSlice<'a> {
    /// Returns the range that these glyphs encompass, relative to the start of the *text run*.
    #[inline]
    pub fn text_run_range(&self) -> Range<CharIndex> {
        let mut range = self.range;
        range.shift_by(self.offset);
        range
    }
}

impl<'a> Iterator for NaturalWordSliceIterator<'a> {
    type Item = TextRunSlice<'a>;

    // inline(always) due to the inefficient rt failures messing up inline heuristics, I think.
    #[inline(always)]
    fn next(&mut self) -> Option<TextRunSlice<'a>> {
        let slice_glyphs;
        if self.reverse {
            if self.index == 0 {
                return None;
            }
            self.index -= 1;
            slice_glyphs = &self.glyphs[self.index];
        } else {
            if self.index >= self.glyphs.len() {
                return None;
            }
            slice_glyphs = &self.glyphs[self.index];
            self.index += 1;
        }

        let mut char_range = self.range.intersect(&slice_glyphs.range);
        let slice_range_begin = slice_glyphs.range.begin();
        char_range.shift_by(-slice_range_begin);

        if !char_range.is_empty() {
            Some(TextRunSlice {
                glyphs: &*slice_glyphs.glyph_store,
                offset: slice_range_begin,
                range: char_range,
            })
        } else {
            None
        }
    }
}

pub struct CharacterSliceIterator<'a> {
    glyph_run: Option<&'a GlyphRun>,
    glyph_run_iter: Iter<'a, GlyphRun>,
    range: Range<CharIndex>,
}

impl<'a> Iterator for CharacterSliceIterator<'a> {
    type Item = TextRunSlice<'a>;

    // inline(always) due to the inefficient rt failures messing up inline heuristics, I think.
    #[inline(always)]
    fn next(&mut self) -> Option<TextRunSlice<'a>> {
        let glyph_run = match self.glyph_run {
            None => return None,
            Some(glyph_run) => glyph_run,
        };

        debug_assert!(!self.range.is_empty());
        let index_to_return = self.range.begin();
        self.range.adjust_by(CharIndex(1), CharIndex(-1));
        if self.range.is_empty() {
            // We're done.
            self.glyph_run = None
        } else if self.range.intersect(&glyph_run.range).is_empty() {
            // Move on to the next glyph run.
            self.glyph_run = self.glyph_run_iter.next();
        }

        let index_within_glyph_run = index_to_return - glyph_run.range.begin();
        Some(TextRunSlice {
            glyphs: &*glyph_run.glyph_store,
            offset: glyph_run.range.begin(),
            range: Range::new(index_within_glyph_run, CharIndex(1)),
        })
    }
}

impl<'a> TextRun {
    pub fn new(font: &mut Font, text: String, options: &ShapingOptions, bidi_level: u8) -> TextRun {
        let glyphs = TextRun::break_and_shape(font, &text, options);
        TextRun {
            text: Arc::new(text),
            font_metrics: font.metrics.clone(),
            font_template: font.handle.template(),
            actual_pt_size: font.actual_pt_size,
            glyphs: Arc::new(glyphs),
            bidi_level: bidi_level,
        }
    }

    pub fn break_and_shape(font: &mut Font, text: &str, options: &ShapingOptions)
                           -> Vec<GlyphRun> {
        // TODO(Issue #230): do a better job. See Gecko's LineBreaker.
        let mut glyphs = vec!();
        let (mut byte_i, mut char_i) = (0, CharIndex(0));
        let mut cur_slice_is_whitespace = false;
        let (mut byte_last_boundary, mut char_last_boundary) = (0, CharIndex(0));
        while byte_i < text.len() {
            let range = text.char_range_at(byte_i);
            let ch = range.ch;
            let next = range.next;

            // Slices alternate between whitespace and non-whitespace,
            // representing line break opportunities.
            let can_break_before = if cur_slice_is_whitespace {
                match ch {
                    ' ' | '\t' | '\n' => false,
                    _ => {
                        cur_slice_is_whitespace = false;
                        true
                    }
                }
            } else {
                match ch {
                    ' ' | '\t' | '\n' => {
                        cur_slice_is_whitespace = true;
                        true
                    },
                    _ => false
                }
            };

            // Create a glyph store for this slice if it's nonempty.
            if can_break_before && byte_i > byte_last_boundary {
                let slice = &text[byte_last_boundary .. byte_i];
                debug!("creating glyph store for slice {} (ws? {}), {} - {} in run {}",
                        slice, !cur_slice_is_whitespace, byte_last_boundary, byte_i, text);

                let mut options = *options;
                if !cur_slice_is_whitespace {
                    options.flags.insert(IS_WHITESPACE_SHAPING_FLAG);
                }

                glyphs.push(GlyphRun {
                    glyph_store: font.shape_text(slice, &options),
                    range: Range::new(char_last_boundary, char_i - char_last_boundary),
                });
                byte_last_boundary = byte_i;
                char_last_boundary = char_i;
            }

            byte_i = next;
            char_i = char_i + CharIndex(1);
        }

        // Create a glyph store for the final slice if it's nonempty.
        if byte_i > byte_last_boundary {
            let slice = &text[byte_last_boundary..];
            debug!("creating glyph store for final slice {} (ws? {}), {} - {} in run {}",
                slice, cur_slice_is_whitespace, byte_last_boundary, text.len(), text);

            let mut options = *options;
            if cur_slice_is_whitespace {
                options.flags.insert(IS_WHITESPACE_SHAPING_FLAG);
            }

            glyphs.push(GlyphRun {
                glyph_store: font.shape_text(slice, &options),
                range: Range::new(char_last_boundary, char_i - char_last_boundary),
            });
        }

        glyphs
    }

    pub fn ascent(&self) -> Au {
        self.font_metrics.ascent
    }

    pub fn descent(&self) -> Au {
        self.font_metrics.descent
    }

    pub fn advance_for_range(&self, range: &Range<CharIndex>) -> Au {
        // TODO(Issue #199): alter advance direction for RTL
        // TODO(Issue #98): using inter-char and inter-word spacing settings when measuring text
        self.natural_word_slices_in_range(range)
            .fold(Au(0), |advance, slice| {
                advance + slice.glyphs.advance_for_char_range(&slice.range)
            })
    }

    pub fn metrics_for_range(&self, range: &Range<CharIndex>) -> RunMetrics {
        RunMetrics::new(self.advance_for_range(range),
                        self.font_metrics.ascent,
                        self.font_metrics.descent)
    }

    pub fn metrics_for_slice(&self, glyphs: &GlyphStore, slice_range: &Range<CharIndex>)
                             -> RunMetrics {
        RunMetrics::new(glyphs.advance_for_char_range(slice_range),
                        self.font_metrics.ascent,
                        self.font_metrics.descent)
    }

    pub fn min_width_for_range(&self, range: &Range<CharIndex>) -> Au {
        debug!("iterating outer range {:?}", range);
        self.natural_word_slices_in_range(range).fold(Au(0), |max_piece_width, slice| {
            debug!("iterated on {:?}[{:?}]", slice.offset, slice.range);
            max(max_piece_width, self.advance_for_range(&slice.range))
        })
    }

    /// Returns the index of the first glyph run containing the given character index.
    fn index_of_first_glyph_run_containing(&self, index: CharIndex) -> Option<usize> {
        (&**self.glyphs).binary_search_index_by(&index, CharIndexComparator)
    }

    /// Returns an iterator that will iterate over all slices of glyphs that represent natural
    /// words in the given range.
    pub fn natural_word_slices_in_range(&'a self, range: &Range<CharIndex>)
                                        -> NaturalWordSliceIterator<'a> {
        let index = match self.index_of_first_glyph_run_containing(range.begin()) {
            None => self.glyphs.len(),
            Some(index) => index,
        };
        NaturalWordSliceIterator {
            glyphs: &self.glyphs[..],
            index: index,
            range: *range,
            reverse: false,
        }
    }

    /// Returns an iterator that over natural word slices in visual order (left to right or
    /// right to left, depending on the bidirectional embedding level).
    pub fn natural_word_slices_in_visual_order(&'a self, range: &Range<CharIndex>)
                                        -> NaturalWordSliceIterator<'a> {
        // Iterate in reverse order if bidi level is RTL.
        let reverse = self.bidi_level % 2 == 1;

        let index = if reverse {
            match self.index_of_first_glyph_run_containing(range.end() - CharIndex(1)) {
                Some(i) => i + 1, // In reverse mode, index points one past the next element.
                None => 0
            }
        } else {
            match self.index_of_first_glyph_run_containing(range.begin()) {
                Some(i) => i,
                None => self.glyphs.len()
            }
        };
        NaturalWordSliceIterator {
            glyphs: &self.glyphs[..],
            index: index,
            range: *range,
            reverse: reverse,
        }
    }

    /// Returns an iterator that will iterate over all slices of glyphs that represent individual
    /// characters in the given range.
    pub fn character_slices_in_range(&'a self, range: &Range<CharIndex>)
                                     -> CharacterSliceIterator<'a> {
        let index = match self.index_of_first_glyph_run_containing(range.begin()) {
            None => self.glyphs.len(),
            Some(index) => index,
        };
        let mut glyph_run_iter = self.glyphs[index..].iter();
        let first_glyph_run = glyph_run_iter.next();
        CharacterSliceIterator {
            glyph_run: first_glyph_run,
            glyph_run_iter: glyph_run_iter,
            range: *range,
        }
    }
}
<commit_msg>gfx: Cache the last result of `TextRun::index_of_first_glyph_run_containing` in TLS.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use app_units::Au;
use font::{Font, FontHandleMethods, FontMetrics, IS_WHITESPACE_SHAPING_FLAG, RunMetrics};
use font::{ShapingOptions};
use platform::font_template::FontTemplateData;
use std::cell::Cell;
use std::cmp::{Ordering, max};
use std::slice::Iter;
use std::sync::Arc;
use text::glyph::{CharIndex, GlyphStore};
use util::range::Range;
use util::vec::{Comparator, FullBinarySearchMethods};

thread_local! {
    static INDEX_OF_FIRST_GLYPH_RUN_CACHE: Cell<Option<(*const TextRun, CharIndex, usize)>> =
        Cell::new(None)
}

/// A single "paragraph" of text in one font size and style.
#[derive(Clone, Deserialize, Serialize)]
pub struct TextRun {
    /// The UTF-8 string represented by this text run.
    pub text: Arc<String>,
    pub font_template: Arc<FontTemplateData>,
    pub actual_pt_size: Au,
    pub font_metrics: FontMetrics,
    /// The glyph runs that make up this text run.
    pub glyphs: Arc<Vec<GlyphRun>>,
    pub bidi_level: u8,
}

impl Drop for TextRun {
    fn drop(&mut self) {
        // Invalidate the glyph run cache if it was our text run that got freed.
        INDEX_OF_FIRST_GLYPH_RUN_CACHE.with(|index_of_first_glyph_run_cache| {
            if let Some((text_run_ptr, _, _)) = index_of_first_glyph_run_cache.get() {
                if text_run_ptr == (self as *const TextRun) {
                    index_of_first_glyph_run_cache.set(None);
                }
            }
        })
    }
}

/// A single series of glyphs within a text run.
#[derive(Clone, Deserialize, Serialize)]
pub struct GlyphRun {
    /// The glyphs.
    pub glyph_store: Arc<GlyphStore>,
    /// The range of characters in the containing run.
    pub range: Range<CharIndex>,
}

pub struct NaturalWordSliceIterator<'a> {
    glyphs: &'a [GlyphRun],
    index: usize,
    range: Range<CharIndex>,
    reverse: bool,
}

struct CharIndexComparator;

impl Comparator<CharIndex, GlyphRun> for CharIndexComparator {
    fn compare(&self, key: &CharIndex, value: &GlyphRun) -> Ordering {
        if *key < value.range.begin() {
            Ordering::Less
        } else if *key >= value.range.end() {
            Ordering::Greater
        } else {
            Ordering::Equal
        }
    }
}

/// A "slice" of a text run is a series of contiguous glyphs that all belong to the same glyph
/// store. Line breaking strategies yield these.
pub struct TextRunSlice<'a> {
    /// The glyph store that the glyphs in this slice belong to.
    pub glyphs: &'a GlyphStore,
    /// The character index that this slice begins at, relative to the start of the *text run*.
    pub offset: CharIndex,
    /// The range that these glyphs encompass, relative to the start of the *glyph store*.
    pub range: Range<CharIndex>,
}

impl<'a> TextRunSlice<'a> {
    /// Returns the range that these glyphs encompass, relative to the start of the *text run*.
    #[inline]
    pub fn text_run_range(&self) -> Range<CharIndex> {
        let mut range = self.range;
        range.shift_by(self.offset);
        range
    }
}

impl<'a> Iterator for NaturalWordSliceIterator<'a> {
    type Item = TextRunSlice<'a>;

    // inline(always) due to the inefficient rt failures messing up inline heuristics, I think.
    #[inline(always)]
    fn next(&mut self) -> Option<TextRunSlice<'a>> {
        let slice_glyphs;
        if self.reverse {
            if self.index == 0 {
                return None;
            }
            self.index -= 1;
            slice_glyphs = &self.glyphs[self.index];
        } else {
            if self.index >= self.glyphs.len() {
                return None;
            }
            slice_glyphs = &self.glyphs[self.index];
            self.index += 1;
        }

        let mut char_range = self.range.intersect(&slice_glyphs.range);
        let slice_range_begin = slice_glyphs.range.begin();
        char_range.shift_by(-slice_range_begin);

        if !char_range.is_empty() {
            Some(TextRunSlice {
                glyphs: &*slice_glyphs.glyph_store,
                offset: slice_range_begin,
                range: char_range,
            })
        } else {
            None
        }
    }
}

pub struct CharacterSliceIterator<'a> {
    glyph_run: Option<&'a GlyphRun>,
    glyph_run_iter: Iter<'a, GlyphRun>,
    range: Range<CharIndex>,
}

impl<'a> Iterator for CharacterSliceIterator<'a> {
    type Item = TextRunSlice<'a>;

    // inline(always) due to the inefficient rt failures messing up inline heuristics, I think.
    #[inline(always)]
    fn next(&mut self) -> Option<TextRunSlice<'a>> {
        let glyph_run = match self.glyph_run {
            None => return None,
            Some(glyph_run) => glyph_run,
        };

        debug_assert!(!self.range.is_empty());
        let index_to_return = self.range.begin();
        self.range.adjust_by(CharIndex(1), CharIndex(-1));
        if self.range.is_empty() {
            // We're done.
            self.glyph_run = None
        } else if self.range.intersect(&glyph_run.range).is_empty() {
            // Move on to the next glyph run.
            self.glyph_run = self.glyph_run_iter.next();
        }

        let index_within_glyph_run = index_to_return - glyph_run.range.begin();
        Some(TextRunSlice {
            glyphs: &*glyph_run.glyph_store,
            offset: glyph_run.range.begin(),
            range: Range::new(index_within_glyph_run, CharIndex(1)),
        })
    }
}

impl<'a> TextRun {
    pub fn new(font: &mut Font, text: String, options: &ShapingOptions, bidi_level: u8) -> TextRun {
        let glyphs = TextRun::break_and_shape(font, &text, options);
        TextRun {
            text: Arc::new(text),
            font_metrics: font.metrics.clone(),
            font_template: font.handle.template(),
            actual_pt_size: font.actual_pt_size,
            glyphs: Arc::new(glyphs),
            bidi_level: bidi_level,
        }
    }

    pub fn break_and_shape(font: &mut Font, text: &str, options: &ShapingOptions)
                           -> Vec<GlyphRun> {
        // TODO(Issue #230): do a better job. See Gecko's LineBreaker.
        let mut glyphs = vec!();
        let (mut byte_i, mut char_i) = (0, CharIndex(0));
        let mut cur_slice_is_whitespace = false;
        let (mut byte_last_boundary, mut char_last_boundary) = (0, CharIndex(0));
        while byte_i < text.len() {
            let range = text.char_range_at(byte_i);
            let ch = range.ch;
            let next = range.next;

            // Slices alternate between whitespace and non-whitespace,
            // representing line break opportunities.
            let can_break_before = if cur_slice_is_whitespace {
                match ch {
                    ' ' | '\t' | '\n' => false,
                    _ => {
                        cur_slice_is_whitespace = false;
                        true
                    }
                }
            } else {
                match ch {
                    ' ' | '\t' | '\n' => {
                        cur_slice_is_whitespace = true;
                        true
                    },
                    _ => false
                }
            };

            // Create a glyph store for this slice if it's nonempty.
            if can_break_before && byte_i > byte_last_boundary {
                let slice = &text[byte_last_boundary .. byte_i];
                debug!("creating glyph store for slice {} (ws? {}), {} - {} in run {}",
                        slice, !cur_slice_is_whitespace, byte_last_boundary, byte_i, text);

                let mut options = *options;
                if !cur_slice_is_whitespace {
                    options.flags.insert(IS_WHITESPACE_SHAPING_FLAG);
                }

                glyphs.push(GlyphRun {
                    glyph_store: font.shape_text(slice, &options),
                    range: Range::new(char_last_boundary, char_i - char_last_boundary),
                });
                byte_last_boundary = byte_i;
                char_last_boundary = char_i;
            }

            byte_i = next;
            char_i = char_i + CharIndex(1);
        }

        // Create a glyph store for the final slice if it's nonempty.
        if byte_i > byte_last_boundary {
            let slice = &text[byte_last_boundary..];
            debug!("creating glyph store for final slice {} (ws? {}), {} - {} in run {}",
                slice, cur_slice_is_whitespace, byte_last_boundary, text.len(), text);

            let mut options = *options;
            if cur_slice_is_whitespace {
                options.flags.insert(IS_WHITESPACE_SHAPING_FLAG);
            }

            glyphs.push(GlyphRun {
                glyph_store: font.shape_text(slice, &options),
                range: Range::new(char_last_boundary, char_i - char_last_boundary),
            });
        }

        glyphs
    }

    pub fn ascent(&self) -> Au {
        self.font_metrics.ascent
    }

    pub fn descent(&self) -> Au {
        self.font_metrics.descent
    }

    pub fn advance_for_range(&self, range: &Range<CharIndex>) -> Au {
        if range.is_empty() {
            return Au(0)
        }

        // TODO(Issue #199): alter advance direction for RTL
        // TODO(Issue #98): using inter-char and inter-word spacing settings when measuring text
        self.natural_word_slices_in_range(range)
            .fold(Au(0), |advance, slice| {
                advance + slice.glyphs.advance_for_char_range(&slice.range)
            })
    }

    pub fn metrics_for_range(&self, range: &Range<CharIndex>) -> RunMetrics {
        RunMetrics::new(self.advance_for_range(range),
                        self.font_metrics.ascent,
                        self.font_metrics.descent)
    }

    pub fn metrics_for_slice(&self, glyphs: &GlyphStore, slice_range: &Range<CharIndex>)
                             -> RunMetrics {
        RunMetrics::new(glyphs.advance_for_char_range(slice_range),
                        self.font_metrics.ascent,
                        self.font_metrics.descent)
    }

    pub fn min_width_for_range(&self, range: &Range<CharIndex>) -> Au {
        debug!("iterating outer range {:?}", range);
        self.natural_word_slices_in_range(range).fold(Au(0), |max_piece_width, slice| {
            debug!("iterated on {:?}[{:?}]", slice.offset, slice.range);
            max(max_piece_width, self.advance_for_range(&slice.range))
        })
    }

    /// Returns the index of the first glyph run containing the given character index.
    fn index_of_first_glyph_run_containing(&self, index: CharIndex) -> Option<usize> {
        let self_ptr = self as *const TextRun;
        INDEX_OF_FIRST_GLYPH_RUN_CACHE.with(|index_of_first_glyph_run_cache| {
            if let Some((last_text_run, last_index, last_result)) =
                    index_of_first_glyph_run_cache.get() {
                if last_text_run == self_ptr && last_index == index {
                    return Some(last_result)
                }
            }

            let result = (&**self.glyphs).binary_search_index_by(&index, CharIndexComparator);
            if let Some(result) = result {
                index_of_first_glyph_run_cache.set(Some((self_ptr, index, result)));
            }
            result
        })
    }

    /// Returns an iterator that will iterate over all slices of glyphs that represent natural
    /// words in the given range.
    pub fn natural_word_slices_in_range(&'a self, range: &Range<CharIndex>)
                                        -> NaturalWordSliceIterator<'a> {
        let index = match self.index_of_first_glyph_run_containing(range.begin()) {
            None => self.glyphs.len(),
            Some(index) => index,
        };
        NaturalWordSliceIterator {
            glyphs: &self.glyphs[..],
            index: index,
            range: *range,
            reverse: false,
        }
    }

    /// Returns an iterator that over natural word slices in visual order (left to right or
    /// right to left, depending on the bidirectional embedding level).
    pub fn natural_word_slices_in_visual_order(&'a self, range: &Range<CharIndex>)
                                        -> NaturalWordSliceIterator<'a> {
        // Iterate in reverse order if bidi level is RTL.
        let reverse = self.bidi_level % 2 == 1;

        let index = if reverse {
            match self.index_of_first_glyph_run_containing(range.end() - CharIndex(1)) {
                Some(i) => i + 1, // In reverse mode, index points one past the next element.
                None => 0
            }
        } else {
            match self.index_of_first_glyph_run_containing(range.begin()) {
                Some(i) => i,
                None => self.glyphs.len()
            }
        };
        NaturalWordSliceIterator {
            glyphs: &self.glyphs[..],
            index: index,
            range: *range,
            reverse: reverse,
        }
    }

    /// Returns an iterator that will iterate over all slices of glyphs that represent individual
    /// characters in the given range.
    pub fn character_slices_in_range(&'a self, range: &Range<CharIndex>)
                                     -> CharacterSliceIterator<'a> {
        let index = match self.index_of_first_glyph_run_containing(range.begin()) {
            None => self.glyphs.len(),
            Some(index) => index,
        };
        let mut glyph_run_iter = self.glyphs[index..].iter();
        let first_glyph_run = glyph_run_iter.next();
        CharacterSliceIterator {
            glyph_run: first_glyph_run,
            glyph_run_iter: glyph_run_iter,
            range: *range,
        }
    }
}
<|endoftext|>


<commit_before>use macroquad::prelude::*;

use zombenum_shared::messages::PlayerInputEvent;

pub fn get_input_events() -> Vec<PlayerInputEvent> {
    let mut events = Vec::new();

    if is_key_down(KeyCode::Escape) {
        events.push(PlayerInputEvent::Exit);
    }

    player_movement(&mut events);

    if is_key_pressed(KeyCode::Space) {
        let shoot_vec = glam::f32::vec2(1.0, 1.0);
        events.push(PlayerInputEvent::Shoot(shoot_vec.into()));
    }

    events
}

pub fn player_movement(events: &mut Vec<PlayerInputEvent>) {
    let mut move_vec = glam::f32::Vec2::default();
    let mut player_moved = false;

    // Check movement for each direction.
    // Multiple keys might be pressed.
    if is_key_down(KeyCode::W) {
        move_vec += glam::f32::vec2(0.0, 1.0);
        player_moved = true
    }
    if is_key_down(KeyCode::S) {
        move_vec += glam::f32::vec2(0.0, -1.0);
        player_moved = true
    }
    if is_key_down(KeyCode::A) {
        move_vec += glam::f32::vec2(1.0, 0.0);
        player_moved = true
    }
    if is_key_down(KeyCode::D) {
        move_vec += glam::f32::vec2(-1.0, 0.0);
        player_moved = true
    }

    if player_moved {
        events.push(PlayerInputEvent::Move(move_vec));
    }
}
<commit_msg>More elegant player move logic<commit_after>use macroquad::prelude::*;

use zombenum_shared::messages::PlayerInputEvent;

pub fn get_input_events() -> Vec<PlayerInputEvent> {
    let mut events = Vec::new();

    if is_key_down(KeyCode::Escape) {
        events.push(PlayerInputEvent::Exit);
    }

    player_movement(&mut events);

    if is_key_pressed(KeyCode::Space) {
        let shoot_vec = glam::f32::vec2(1.0, 1.0);
        events.push(PlayerInputEvent::Shoot(shoot_vec.into()));
    }

    events
}

pub fn player_movement(events: &mut Vec<PlayerInputEvent>) {
    let mut move_vec = glam::f32::Vec2::default();

    // Check movement for each direction.
    // Multiple keys might be pressed.
    if is_key_down(KeyCode::W) {
        move_vec += glam::f32::vec2(0.0, 1.0);
    }
    if is_key_down(KeyCode::S) {
        move_vec += glam::f32::vec2(0.0, -1.0);
    }
    if is_key_down(KeyCode::A) {
        move_vec += glam::f32::vec2(1.0, 0.0);
    }
    if is_key_down(KeyCode::D) {
        move_vec += glam::f32::vec2(-1.0, 0.0);
    }

    if move_vec != glam::f32::Vec2::zero() {
        events.push(PlayerInputEvent::Move(move_vec));
    }
}
<|endoftext|>