<commit_before>#![stable(feature = "futures_api", since = "1.36.0")]

use crate::ops::Try;
use crate::result::Result;

/// Indicates whether a value is available or if the current task has been
/// scheduled to receive a wakeup instead.
#[must_use = "this `Poll` may be a `Pending` variant, which should be handled"]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[stable(feature = "futures_api", since = "1.36.0")]
pub enum Poll<T> {
    /// Represents that a value is immediately ready.
    #[lang = "Ready"]
    #[stable(feature = "futures_api", since = "1.36.0")]
    Ready(#[stable(feature = "futures_api", since = "1.36.0")] T),

    /// Represents that a value is not ready yet.
    ///
    /// When a function returns `Pending`, the function *must* also
    /// ensure that the current task is scheduled to be awoken when
    /// progress can be made.
    #[lang = "Pending"]
    #[stable(feature = "futures_api", since = "1.36.0")]
    Pending,
}

impl<T> Poll<T> {
    /// Changes the ready value of this `Poll` with the closure provided.
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn map<U, F>(self, f: F) -> Poll<U>
    where
        F: FnOnce(T) -> U,
    {
        match self {
            Poll::Ready(t) => Poll::Ready(f(t)),
            Poll::Pending => Poll::Pending,
        }
    }

    /// Returns `true` if this is `Poll::Ready`
    #[inline]
    #[rustc_const_stable(feature = "const_poll", since = "1.49.0")]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub const fn is_ready(&self) -> bool {
        matches!(*self, Poll::Ready(_))
    }

    /// Returns `true` if this is `Poll::Pending`
    #[inline]
    #[rustc_const_stable(feature = "const_poll", since = "1.49.0")]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub const fn is_pending(&self) -> bool {
        !self.is_ready()
    }
}

impl<T, E> Poll<Result<T, E>> {
    /// Changes the success value of this `Poll` with the closure provided.
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn map_ok<U, F>(self, f: F) -> Poll<Result<U, E>>
    where
        F: FnOnce(T) -> U,
    {
        match self {
            Poll::Ready(Ok(t)) => Poll::Ready(Ok(f(t))),
            Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
            Poll::Pending => Poll::Pending,
        }
    }

    /// Changes the error value of this `Poll` with the closure provided.
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn map_err<U, F>(self, f: F) -> Poll<Result<T, U>>
    where
        F: FnOnce(E) -> U,
    {
        match self {
            Poll::Ready(Ok(t)) => Poll::Ready(Ok(t)),
            Poll::Ready(Err(e)) => Poll::Ready(Err(f(e))),
            Poll::Pending => Poll::Pending,
        }
    }
}

impl<T, E> Poll<Option<Result<T, E>>> {
    /// Changes the success value of this `Poll` with the closure provided.
    #[unstable(feature = "poll_map", issue = "63514")]
    pub fn map_ok<U, F>(self, f: F) -> Poll<Option<Result<U, E>>>
    where
        F: FnOnce(T) -> U,
    {
        match self {
            Poll::Ready(Some(Ok(t))) => Poll::Ready(Some(Ok(f(t)))),
            Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e))),
            Poll::Ready(None) => Poll::Ready(None),
            Poll::Pending => Poll::Pending,
        }
    }

    /// Changes the error value of this `Poll` with the closure provided.
    #[unstable(feature = "poll_map", issue = "63514")]
    pub fn map_err<U, F>(self, f: F) -> Poll<Option<Result<T, U>>>
    where
        F: FnOnce(E) -> U,
    {
        match self {
            Poll::Ready(Some(Ok(t))) => Poll::Ready(Some(Ok(t))),
            Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(f(e)))),
            Poll::Ready(None) => Poll::Ready(None),
            Poll::Pending => Poll::Pending,
        }
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl<T> From<T> for Poll<T> {
    /// Convert to a `Ready` variant.
    ///
    /// # Example
    ///
    /// ```
    /// # use core::task::Poll;
    /// assert_eq!(Poll::from(true), Poll::Ready(true));
    /// ```
    fn from(t: T) -> Poll<T> {
        Poll::Ready(t)
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl<T, E> Try for Poll<Result<T, E>> {
    type Ok = Poll<T>;
    type Error = E;

    #[inline]
    fn into_result(self) -> Result<Self::Ok, Self::Error> {
        match self {
            Poll::Ready(Ok(x)) => Ok(Poll::Ready(x)),
            Poll::Ready(Err(e)) => Err(e),
            Poll::Pending => Ok(Poll::Pending),
        }
    }

    #[inline]
    fn from_error(e: Self::Error) -> Self {
        Poll::Ready(Err(e))
    }

    #[inline]
    fn from_ok(x: Self::Ok) -> Self {
        x.map(Ok)
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl<T, E> Try for Poll<Option<Result<T, E>>> {
    type Ok = Poll<Option<T>>;
    type Error = E;

    #[inline]
    fn into_result(self) -> Result<Self::Ok, Self::Error> {
        match self {
            Poll::Ready(Some(Ok(x))) => Ok(Poll::Ready(Some(x))),
            Poll::Ready(Some(Err(e))) => Err(e),
            Poll::Ready(None) => Ok(Poll::Ready(None)),
            Poll::Pending => Ok(Poll::Pending),
        }
    }

    #[inline]
    fn from_error(e: Self::Error) -> Self {
        Poll::Ready(Some(Err(e)))
    }

    #[inline]
    fn from_ok(x: Self::Ok) -> Self {
        x.map(|x| x.map(Ok))
    }
}
<commit_msg>stabilize the poll_map feature<commit_after>#![stable(feature = "futures_api", since = "1.36.0")]

use crate::ops::Try;
use crate::result::Result;

/// Indicates whether a value is available or if the current task has been
/// scheduled to receive a wakeup instead.
#[must_use = "this `Poll` may be a `Pending` variant, which should be handled"]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[stable(feature = "futures_api", since = "1.36.0")]
pub enum Poll<T> {
    /// Represents that a value is immediately ready.
    #[lang = "Ready"]
    #[stable(feature = "futures_api", since = "1.36.0")]
    Ready(#[stable(feature = "futures_api", since = "1.36.0")] T),

    /// Represents that a value is not ready yet.
    ///
    /// When a function returns `Pending`, the function *must* also
    /// ensure that the current task is scheduled to be awoken when
    /// progress can be made.
    #[lang = "Pending"]
    #[stable(feature = "futures_api", since = "1.36.0")]
    Pending,
}

impl<T> Poll<T> {
    /// Changes the ready value of this `Poll` with the closure provided.
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn map<U, F>(self, f: F) -> Poll<U>
    where
        F: FnOnce(T) -> U,
    {
        match self {
            Poll::Ready(t) => Poll::Ready(f(t)),
            Poll::Pending => Poll::Pending,
        }
    }

    /// Returns `true` if this is `Poll::Ready`
    #[inline]
    #[rustc_const_stable(feature = "const_poll", since = "1.49.0")]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub const fn is_ready(&self) -> bool {
        matches!(*self, Poll::Ready(_))
    }

    /// Returns `true` if this is `Poll::Pending`
    #[inline]
    #[rustc_const_stable(feature = "const_poll", since = "1.49.0")]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub const fn is_pending(&self) -> bool {
        !self.is_ready()
    }
}

impl<T, E> Poll<Result<T, E>> {
    /// Changes the success value of this `Poll` with the closure provided.
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn map_ok<U, F>(self, f: F) -> Poll<Result<U, E>>
    where
        F: FnOnce(T) -> U,
    {
        match self {
            Poll::Ready(Ok(t)) => Poll::Ready(Ok(f(t))),
            Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
            Poll::Pending => Poll::Pending,
        }
    }

    /// Changes the error value of this `Poll` with the closure provided.
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn map_err<U, F>(self, f: F) -> Poll<Result<T, U>>
    where
        F: FnOnce(E) -> U,
    {
        match self {
            Poll::Ready(Ok(t)) => Poll::Ready(Ok(t)),
            Poll::Ready(Err(e)) => Poll::Ready(Err(f(e))),
            Poll::Pending => Poll::Pending,
        }
    }
}

impl<T, E> Poll<Option<Result<T, E>>> {
    /// Changes the success value of this `Poll` with the closure provided.
    #[stable(feature = "poll_map", since = "1.51.0")]
    pub fn map_ok<U, F>(self, f: F) -> Poll<Option<Result<U, E>>>
    where
        F: FnOnce(T) -> U,
    {
        match self {
            Poll::Ready(Some(Ok(t))) => Poll::Ready(Some(Ok(f(t)))),
            Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e))),
            Poll::Ready(None) => Poll::Ready(None),
            Poll::Pending => Poll::Pending,
        }
    }

    /// Changes the error value of this `Poll` with the closure provided.
    #[stable(feature = "poll_map", since = "1.51.0")]
    pub fn map_err<U, F>(self, f: F) -> Poll<Option<Result<T, U>>>
    where
        F: FnOnce(E) -> U,
    {
        match self {
            Poll::Ready(Some(Ok(t))) => Poll::Ready(Some(Ok(t))),
            Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(f(e)))),
            Poll::Ready(None) => Poll::Ready(None),
            Poll::Pending => Poll::Pending,
        }
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl<T> From<T> for Poll<T> {
    /// Convert to a `Ready` variant.
    ///
    /// # Example
    ///
    /// ```
    /// # use core::task::Poll;
    /// assert_eq!(Poll::from(true), Poll::Ready(true));
    /// ```
    fn from(t: T) -> Poll<T> {
        Poll::Ready(t)
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl<T, E> Try for Poll<Result<T, E>> {
    type Ok = Poll<T>;
    type Error = E;

    #[inline]
    fn into_result(self) -> Result<Self::Ok, Self::Error> {
        match self {
            Poll::Ready(Ok(x)) => Ok(Poll::Ready(x)),
            Poll::Ready(Err(e)) => Err(e),
            Poll::Pending => Ok(Poll::Pending),
        }
    }

    #[inline]
    fn from_error(e: Self::Error) -> Self {
        Poll::Ready(Err(e))
    }

    #[inline]
    fn from_ok(x: Self::Ok) -> Self {
        x.map(Ok)
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl<T, E> Try for Poll<Option<Result<T, E>>> {
    type Ok = Poll<Option<T>>;
    type Error = E;

    #[inline]
    fn into_result(self) -> Result<Self::Ok, Self::Error> {
        match self {
            Poll::Ready(Some(Ok(x))) => Ok(Poll::Ready(Some(x))),
            Poll::Ready(Some(Err(e))) => Err(e),
            Poll::Ready(None) => Ok(Poll::Ready(None)),
            Poll::Pending => Ok(Poll::Pending),
        }
    }

    #[inline]
    fn from_error(e: Self::Error) -> Self {
        Poll::Ready(Some(Err(e)))
    }

    #[inline]
    fn from_ok(x: Self::Ok) -> Self {
        x.map(|x| x.map(Ok))
    }
}
<|endoftext|>


<commit_before>//! CLI tool to compile Cranelift IR files to native code in memory and execute them.

use crate::utils::read_to_string;
use cranelift_codegen::isa::{CallConv, TargetIsa};
use cranelift_filetests::FunctionRunner;
use cranelift_native::builder as host_isa_builder;
use cranelift_reader::{parse_test, Details, IsaSpec, ParseOptions};
use std::path::PathBuf;
use target_lexicon::Triple;
use walkdir::WalkDir;

pub fn run(files: Vec<String>, flag_print: bool) -> Result<(), String> {
    let mut total = 0;
    let mut errors = 0;
    for file in iterate_files(files) {
        total += 1;
        match run_single_file(&file) {
            Ok(_) => {
                if flag_print {
                    println!("{}", file.to_string_lossy());
                }
            }
            Err(e) => {
                if flag_print {
                    println!("{}: {}", file.to_string_lossy(), e);
                }
                errors += 1;
            }
        }
    }

    if flag_print {
        match total {
            0 => println!("0 files"),
            1 => println!("1 file"),
            n => println!("{} files", n),
        }
    }

    match errors {
        0 => Ok(()),
        1 => Err(String::from("1 failure")),
        n => Err(format!("{} failures", n)),
    }
}

/// Iterate over all of the files passed as arguments, recursively iterating through directories
fn iterate_files(files: Vec<String>) -> impl Iterator<Item = PathBuf> {
    files
        .into_iter()
        .flat_map(WalkDir::new)
        .filter(|f| match f {
            Ok(d) => {
                // filter out hidden files (starting with .)
                !d.file_name().to_str().map_or(false, |s| s.starts_with('.'))
                    // filter out directories
                    && !d.file_type().is_dir()
            }
            Err(e) => {
                println!("Unable to read file: {}", e);
                false
            }
        })
        .map(|f| {
            f.expect("This should not happen: we have already filtered out the errors")
                .into_path()
        })
}

/// Run all functions in a file that are succeeded by "run:" comments
fn run_single_file(path: &PathBuf) -> Result<(), String> {
    let file_contents = read_to_string(&path).map_err(|e| e.to_string())?;
    run_file_contents(file_contents)
}

/// Main body of `run_single_file` separated for testing
fn run_file_contents(file_contents: String) -> Result<(), String> {
    let options = ParseOptions {
        default_calling_convention: CallConv::triple_default(&Triple::host()), // use the host's default calling convention
        ..ParseOptions::default()
    };
    let test_file = parse_test(&file_contents, options).map_err(|e| e.to_string())?;
    for (func, Details { comments, .. }) in test_file.functions {
        if comments.iter().any(|c| c.text.contains("run")) {
            let isa = create_target_isa(&test_file.isa_spec)?;
            FunctionRunner::new(func, isa).run()?
        }
    }
    Ok(())
}

/// Build an ISA based on the current machine running this code (the host)
fn create_target_isa(isa_spec: &IsaSpec) -> Result<Box<dyn TargetIsa>, String> {
    if let IsaSpec::None(flags) = isa_spec {
        // build an ISA for the current machine
        let builder = host_isa_builder()?;
        Ok(builder.finish(flags.clone()))
    } else {
        Err(String::from("A target ISA was specified in the file but should not have been--only the host ISA can be used for running CLIF files"))
    }
}

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

    #[test]
    fn nop() {
        let code = String::from(
            "
            function %test() -> b8 {
            ebb0:
                nop
                v1 = bconst.b8 true
                return v1
            }
            ; run
            ",
        );
        run_file_contents(code).unwrap()
    }
}
<commit_msg>Allow 'clif-util run' to read stdin as intended, closes #1004 (#1335)<commit_after>//! CLI tool to compile Cranelift IR files to native code in memory and execute them.

use crate::utils::read_to_string;
use cranelift_codegen::isa::{CallConv, TargetIsa};
use cranelift_filetests::FunctionRunner;
use cranelift_native::builder as host_isa_builder;
use cranelift_reader::{parse_test, Details, IsaSpec, ParseOptions};
use std::path::PathBuf;
use target_lexicon::Triple;
use walkdir::WalkDir;

pub fn run(files: Vec<String>, flag_print: bool) -> Result<(), String> {
    let stdin_exist = files.iter().find(|file| *file == "-").is_some();
    let filtered_files = files
        .iter()
        .filter(|file| *file != "-")
        .map(|file| file.to_string())
        .collect::<Vec<String>>();
    let mut total = 0;
    let mut errors = 0;
    let mut special_files: Vec<PathBuf> = vec![];
    if stdin_exist {
        special_files.push("-".into());
    }
    for file in iterate_files(filtered_files).chain(special_files) {
        total += 1;
        match run_single_file(&file) {
            Ok(_) => {
                if flag_print {
                    println!("{}", file.to_string_lossy());
                }
            }
            Err(e) => {
                if flag_print {
                    println!("{}: {}", file.to_string_lossy(), e);
                }
                errors += 1;
            }
        }
    }

    if flag_print {
        match total {
            0 => println!("0 files"),
            1 => println!("1 file"),
            n => println!("{} files", n),
        }
    }

    match errors {
        0 => Ok(()),
        1 => Err(String::from("1 failure")),
        n => Err(format!("{} failures", n)),
    }
}

/// Iterate over all of the files passed as arguments, recursively iterating through directories
fn iterate_files(files: Vec<String>) -> impl Iterator<Item = PathBuf> {
    files
        .into_iter()
        .flat_map(WalkDir::new)
        .filter(|f| match f {
            Ok(d) => {
                // filter out hidden files (starting with .)
                !d.file_name().to_str().map_or(false, |s| s.starts_with('.'))
                    // filter out directories
                    && !d.file_type().is_dir()
            }
            Err(e) => {
                println!("Unable to read file: {}", e);
                false
            }
        })
        .map(|f| {
            f.expect("This should not happen: we have already filtered out the errors")
                .into_path()
        })
}

/// Run all functions in a file that are succeeded by "run:" comments
fn run_single_file(path: &PathBuf) -> Result<(), String> {
    let file_contents = read_to_string(&path).map_err(|e| e.to_string())?;
    run_file_contents(file_contents)
}

/// Main body of `run_single_file` separated for testing
fn run_file_contents(file_contents: String) -> Result<(), String> {
    let options = ParseOptions {
        default_calling_convention: CallConv::triple_default(&Triple::host()), // use the host's default calling convention
        ..ParseOptions::default()
    };
    let test_file = parse_test(&file_contents, options).map_err(|e| e.to_string())?;
    for (func, Details { comments, .. }) in test_file.functions {
        if comments.iter().any(|c| c.text.contains("run")) {
            let isa = create_target_isa(&test_file.isa_spec)?;
            FunctionRunner::new(func, isa).run()?
        }
    }
    Ok(())
}

/// Build an ISA based on the current machine running this code (the host)
fn create_target_isa(isa_spec: &IsaSpec) -> Result<Box<dyn TargetIsa>, String> {
    if let IsaSpec::None(flags) = isa_spec {
        // build an ISA for the current machine
        let builder = host_isa_builder()?;
        Ok(builder.finish(flags.clone()))
    } else {
        Err(String::from("A target ISA was specified in the file but should not have been--only the host ISA can be used for running CLIF files"))
    }
}

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

    #[test]
    fn nop() {
        let code = String::from(
            "
            function %test() -> b8 {
            ebb0:
                nop
                v1 = bconst.b8 true
                return v1
            }
            ; run
            ",
        );
        run_file_contents(code).unwrap()
    }
}
<|endoftext|>


<commit_before>use ::{Pattern, SearchCursors, Searcher, ReverseSearcher, DoubleEndedSearcher};
use iterators::{Split, RSplit};
use iterators::{SplitTerminator, RSplitTerminator};
use iterators::{SplitN, RSplitN};
use iterators::{Matches, RMatches};
use iterators::{MatchIndices, RMatchIndices};
use ::InverseMatchesAreValid;

pub trait IteratorConstructors: SearchCursors {
    #[inline]
    fn contains<P: Pattern<Self>>(self, pat: P) -> bool {
        pat.is_contained_in(self)
    }

    #[inline]
    fn split<P: Pattern<Self>>(self, pat: P) -> Split<Self, P>
        where Self: InverseMatchesAreValid
    {
        Split::new(self, pat)
    }

    #[inline]
    fn rsplit<P: Pattern<Self>>(self, pat: P) -> RSplit<Self, P>
        where P::Searcher: ReverseSearcher<Self>,
              Self: InverseMatchesAreValid
    {
        RSplit::new(self, pat)
    }

    #[inline]
    fn splitn<P: Pattern<Self>>(self, count: usize, pat: P) -> SplitN<Self, P>
        where Self: InverseMatchesAreValid
    {
        SplitN::new(self, pat, count)
    }

    #[inline]
    fn rsplitn<P: Pattern<Self>>(self, count: usize, pat: P) -> RSplitN<Self, P>
        where P::Searcher: ReverseSearcher<Self>,
              Self: InverseMatchesAreValid
    {
        RSplitN::new(self, pat, count)
    }

    #[inline]
    fn split_terminator<P: Pattern<Self>>(self, pat: P) -> SplitTerminator<Self, P>
        where Self: InverseMatchesAreValid
    {
        SplitTerminator::new(self, pat)
    }

    #[inline]
    fn rsplit_terminator<P: Pattern<Self>>(self, pat: P) -> RSplitTerminator<Self, P>
        where P::Searcher: ReverseSearcher<Self>,
              Self: InverseMatchesAreValid
    {
        RSplitTerminator::new(self, pat)
    }

    #[inline]
    fn matches<P: Pattern<Self>>(self, pat: P) -> Matches<Self, P> {
        Matches::new(self, pat)
    }

    #[inline]
    fn rmatches<P: Pattern<Self>>(self, pat: P) -> RMatches<Self, P>
        where P::Searcher: ReverseSearcher<Self>
    {
        RMatches::new(self, pat)
    }

    #[inline]
    fn match_indices<P: Pattern<Self>>(self, pat: P) -> MatchIndices<Self, P> {
        MatchIndices::new(self, pat)
    }

    #[inline]
    fn rmatch_indices<P: Pattern<Self>>(self, pat: P) -> RMatchIndices<Self, P>
        where P::Searcher: ReverseSearcher<Self>
    {
        RMatchIndices::new(self, pat)
    }

    #[inline]
    fn starts_with<P: Pattern<Self>>(self, pat: P) -> bool {
        pat.is_prefix_of(self)
    }

    #[inline]
    fn ends_with<P: Pattern<Self>>(self, pat: P) -> bool
        where P::Searcher: ReverseSearcher<Self>
    {
        pat.is_suffix_of(self)
    }

    #[inline]
    fn trim_matches<P: Pattern<Self>>(self, pat: P) -> Self::MatchType
        where P::Searcher: DoubleEndedSearcher<Self>
    {
        let mut matcher = pat.into_searcher(self);
        let mut i = Self::cursor_at_front(matcher.haystack());
        let mut j = Self::cursor_at_front(matcher.haystack());
        if let Some((a, b)) = matcher.next_reject() {
            i = a;
            j = b; // Remember earliest known match, correct it below if
                   // last match is different
        }
        if let Some((_, b)) = matcher.next_reject_back() {
            j = b;
        }
        unsafe {
            // Searcher is known to return valid indices
            Self::range_to_self(matcher.haystack(), i, j)
        }
    }

    #[inline]
    fn trim_left_matches<P: Pattern<Self>>(self, pat: P) -> Self::MatchType {
        let mut matcher = pat.into_searcher(self);
        let mut i = Self::cursor_at_back(matcher.haystack());
        let j = Self::cursor_at_back(matcher.haystack());
        if let Some((a, _)) = matcher.next_reject() {
            i = a;
        }
        unsafe {
            // Searcher is known to return valid indices
            Self::range_to_self(matcher.haystack(), i, j)
        }
    }

    #[inline]
    fn trim_right_matches<P: Pattern<Self>>(self, pat: P) -> Self::MatchType
        where P::Searcher: ReverseSearcher<Self>
    {
        let mut matcher = pat.into_searcher(self);
        let i = Self::cursor_at_front(matcher.haystack());
        let mut j = Self::cursor_at_front(matcher.haystack());
        if let Some((_, b)) = matcher.next_reject_back() {
            j = b;
        }
        unsafe {
            // Searcher is known to return valid indices
            Self::range_to_self(matcher.haystack(), i, j)
        }
    }

    fn find<P: Pattern<Self>>(self, pat: P) -> Option<usize> {
        let mut searcher = pat.into_searcher(self);
        let h = searcher.haystack();
        searcher.next_match().map(|(i, _)| Self::offset_from_front(h, i))
    }

    fn rfind<P: Pattern<Self>>(self, pat: P) -> Option<usize>
        where P::Searcher: ReverseSearcher<Self>
    {
        let mut searcher = pat.into_searcher(self);
        let h = searcher.haystack();
        searcher.next_match_back().map(|(i, _)| Self::offset_from_front(h, i))
    }
}

impl<T: SearchCursors> IteratorConstructors for T {}
<commit_msg>Added OSStr Unicode constructors<commit_after>use ::{Pattern, SearchCursors, Searcher, ReverseSearcher, DoubleEndedSearcher};
use iterators::{Split, RSplit};
use iterators::{SplitTerminator, RSplitTerminator};
use iterators::{SplitN, RSplitN};
use iterators::{Matches, RMatches};
use iterators::{MatchIndices, RMatchIndices};
use ::InverseMatchesAreValid;

pub trait IteratorConstructors: SearchCursors {
    #[inline]
    fn contains<P: Pattern<Self>>(self, pat: P) -> bool {
        pat.is_contained_in(self)
    }

    #[inline]
    fn split<P: Pattern<Self>>(self, pat: P) -> Split<Self, P>
        where Self: InverseMatchesAreValid
    {
        Split::new(self, pat)
    }

    #[inline]
    fn rsplit<P: Pattern<Self>>(self, pat: P) -> RSplit<Self, P>
        where P::Searcher: ReverseSearcher<Self>,
              Self: InverseMatchesAreValid
    {
        RSplit::new(self, pat)
    }

    #[inline]
    fn splitn<P: Pattern<Self>>(self, count: usize, pat: P) -> SplitN<Self, P>
        where Self: InverseMatchesAreValid
    {
        SplitN::new(self, pat, count)
    }

    #[inline]
    fn rsplitn<P: Pattern<Self>>(self, count: usize, pat: P) -> RSplitN<Self, P>
        where P::Searcher: ReverseSearcher<Self>,
              Self: InverseMatchesAreValid
    {
        RSplitN::new(self, pat, count)
    }

    #[inline]
    fn split_terminator<P: Pattern<Self>>(self, pat: P) -> SplitTerminator<Self, P>
        where Self: InverseMatchesAreValid
    {
        SplitTerminator::new(self, pat)
    }

    #[inline]
    fn rsplit_terminator<P: Pattern<Self>>(self, pat: P) -> RSplitTerminator<Self, P>
        where P::Searcher: ReverseSearcher<Self>,
              Self: InverseMatchesAreValid
    {
        RSplitTerminator::new(self, pat)
    }

    #[inline]
    fn matches<P: Pattern<Self>>(self, pat: P) -> Matches<Self, P> {
        Matches::new(self, pat)
    }

    #[inline]
    fn rmatches<P: Pattern<Self>>(self, pat: P) -> RMatches<Self, P>
        where P::Searcher: ReverseSearcher<Self>
    {
        RMatches::new(self, pat)
    }

    #[inline]
    fn match_indices<P: Pattern<Self>>(self, pat: P) -> MatchIndices<Self, P> {
        MatchIndices::new(self, pat)
    }

    #[inline]
    fn rmatch_indices<P: Pattern<Self>>(self, pat: P) -> RMatchIndices<Self, P>
        where P::Searcher: ReverseSearcher<Self>
    {
        RMatchIndices::new(self, pat)
    }

    #[inline]
    fn starts_with<P: Pattern<Self>>(self, pat: P) -> bool {
        pat.is_prefix_of(self)
    }

    #[inline]
    fn ends_with<P: Pattern<Self>>(self, pat: P) -> bool
        where P::Searcher: ReverseSearcher<Self>
    {
        pat.is_suffix_of(self)
    }

    #[inline]
    fn trim_matches<P: Pattern<Self>>(self, pat: P) -> Self::MatchType
        where P::Searcher: DoubleEndedSearcher<Self>
    {
        let mut matcher = pat.into_searcher(self);
        let mut i = Self::cursor_at_front(matcher.haystack());
        let mut j = Self::cursor_at_front(matcher.haystack());
        if let Some((a, b)) = matcher.next_reject() {
            i = a;
            j = b; // Remember earliest known match, correct it below if
                   // last match is different
        }
        if let Some((_, b)) = matcher.next_reject_back() {
            j = b;
        }
        unsafe {
            // Searcher is known to return valid indices
            Self::range_to_self(matcher.haystack(), i, j)
        }
    }

    #[inline]
    fn trim_left_matches<P: Pattern<Self>>(self, pat: P) -> Self::MatchType {
        let mut matcher = pat.into_searcher(self);
        let mut i = Self::cursor_at_back(matcher.haystack());
        let j = Self::cursor_at_back(matcher.haystack());
        if let Some((a, _)) = matcher.next_reject() {
            i = a;
        }
        unsafe {
            // Searcher is known to return valid indices
            Self::range_to_self(matcher.haystack(), i, j)
        }
    }

    #[inline]
    fn trim_right_matches<P: Pattern<Self>>(self, pat: P) -> Self::MatchType
        where P::Searcher: ReverseSearcher<Self>
    {
        let mut matcher = pat.into_searcher(self);
        let i = Self::cursor_at_front(matcher.haystack());
        let mut j = Self::cursor_at_front(matcher.haystack());
        if let Some((_, b)) = matcher.next_reject_back() {
            j = b;
        }
        unsafe {
            // Searcher is known to return valid indices
            Self::range_to_self(matcher.haystack(), i, j)
        }
    }

    fn find<P: Pattern<Self>>(self, pat: P) -> Option<usize> {
        let mut searcher = pat.into_searcher(self);
        let h = searcher.haystack();
        searcher.next_match().map(|(i, _)| Self::offset_from_front(h, i))
    }

    fn rfind<P: Pattern<Self>>(self, pat: P) -> Option<usize>
        where P::Searcher: ReverseSearcher<Self>
    {
        let mut searcher = pat.into_searcher(self);
        let h = searcher.haystack();
        searcher.next_match_back().map(|(i, _)| Self::offset_from_front(h, i))
    }
}

impl<T: SearchCursors> IteratorConstructors for T {}

use os_string::shared::PartialUnicode as OsStrPartialUnicode;
use os_string::mutable::PartialUnicode as MutOsStrPartialUnicode;
use std::ffi::OsStr;

pub trait OsStrExtension {
    fn for_unicode(&self) -> OsStrPartialUnicode;
    fn for_unicode_mut(&mut self) -> MutOsStrPartialUnicode;
}

impl OsStrExtension for OsStr {
    fn for_unicode(&self) -> OsStrPartialUnicode {
        OsStrPartialUnicode { os_str: self }
    }
    fn for_unicode_mut(&mut self) -> MutOsStrPartialUnicode {
        MutOsStrPartialUnicode { os_str: self }
    }
}
<|endoftext|>


<commit_before>use collect_slice::CollectSlice;

use bits::{Dibit, DibitBytes};
use buffer::{Buffer, DataPayloadStorage};
use coding::trellis;
use data::{crc, interleave};
use error::{Result, P25Error};

use trunking::decode::*;

pub struct TSBKDecoder {
    dibits: Buffer<DataPayloadStorage>,
}

impl TSBKDecoder {
    pub fn new() -> TSBKDecoder {
        TSBKDecoder {
            dibits: Buffer::new(DataPayloadStorage::new()),
        }
    }

    pub fn feed(&mut self, dibit: Dibit) -> Option<Result<TSBK>> {
        let (count, dibits) = {
            let buf = match self.dibits.feed(dibit) {
                Some(buf) => buf,
                None => return None,
            };

            let mut dibits = [Dibit::default(); 48];
            let count = trellis::DibitDecoder::new(interleave::Deinterleaver::new(buf))
                .filter(|x| x.is_ok()).map(|x| x.unwrap())
                .collect_slice(&mut dibits[..]);

            (count, dibits)
        };

        self.dibits.reset();

        if count != dibits.len() {
            return Some(Err(P25Error::ViterbiUnrecoverable));
        }

        let mut bytes = [0; 12];
        DibitBytes::new(dibits.iter().cloned()).collect_slice_checked(&mut bytes[..]);

        Some(Ok(TSBK::new(bytes)))
    }
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum TSBKOpcode {
    GroupVoiceGrant,
    GroupVoiceUpdate,
    GroupVoiceUpdateExplicit,
    UnitVoiceGrant,
    UnitCallRequest,
    UnitVoiceUpdate,
    PhoneGrant,
    PhoneCallRequest,
    UnitDataGrant,
    GroupDataGrant,
    GroupDataAnnounce,
    GroupDataAnnounceExplicit,
    UnitStatusUpdate,
    UnitStatusQuery,
    UnitShortMessage,
    UnitMonitor,
    UnitCallAlert,
    AckResponse,
    QueuedResponse,
    ExtendedFunctionResponse,
    DenyResponse,
    GroupAffiliationResponse,
    GroupAffiliationQuery,
    LocRegistrationResponse,
    UnitRegistrationResponse,
    UnitRegistrationCommand,
    AuthCommand,
    DeregistrationAck,
    RoamingAddrCommand,
    RoamingAddrUpdate,
    SystemServiceBroadcast,
    AltControlBroadcast,
    RFSSStatusBroadcast,
    NetworkStatusBroadcast,
    AdjacentSiteBroadcast,
    ChannelParamsUpdate,
    ProtectionParamBroadcast,
    ProtectionParamUpdate,
    Reserved,
}

impl TSBKOpcode {
    pub fn from_bits(bits: u8) -> Option<TSBKOpcode> {
        use self::TSBKOpcode::*;

        match bits {
            0b000000 => Some(GroupVoiceGrant),
            0b000001 => Some(Reserved),
            0b000010 => Some(GroupVoiceUpdate),
            0b000011 => Some(GroupVoiceUpdateExplicit),
            0b000100 => Some(UnitVoiceGrant),
            0b000101 => Some(UnitCallRequest),
            0b000110 => Some(UnitVoiceUpdate),
            0b000111 => Some(Reserved),

            0b001000 => Some(PhoneGrant),
            0b001001 => Some(Reserved),
            0b001010 => Some(PhoneCallRequest),
            0b001011...0b001111 => Some(Reserved),

            0b010000 => Some(UnitDataGrant),
            0b010001 => Some(GroupDataGrant),
            0b010010 => Some(GroupDataAnnounce),
            0b010011 => Some(GroupDataAnnounceExplicit),
            0b010100...0b010111 => Some(Reserved),

            0b011000 => Some(UnitStatusUpdate),
            0b011001 => Some(Reserved),
            0b011010 => Some(UnitStatusQuery),
            0b011011 => Some(Reserved),
            0b011100 => Some(UnitShortMessage),
            0b011101 => Some(UnitMonitor),
            0b011110 => Some(Reserved),
            0b011111 => Some(UnitCallAlert),
            0b100000 => Some(AckResponse),
            0b100001 => Some(QueuedResponse),
            0b100010 => Some(Reserved),
            0b100011 => Some(Reserved),
            0b100100 => Some(ExtendedFunctionResponse),
            0b100101 => Some(Reserved),
            0b100110 => Some(Reserved),
            0b100111 => Some(DenyResponse),

            0b101000 => Some(GroupAffiliationResponse),
            0b101001 => Some(Reserved),
            0b101010 => Some(GroupAffiliationQuery),
            0b101011 => Some(LocRegistrationResponse),
            0b101100 => Some(UnitRegistrationResponse),
            0b101101 => Some(UnitRegistrationCommand),
            0b101110 => Some(AuthCommand),
            0b101111 => Some(DeregistrationAck),

            0b110000...0b110101 => Some(Reserved),
            0b110110 => Some(RoamingAddrCommand),
            0b110111 => Some(RoamingAddrUpdate),

            0b111000 => Some(SystemServiceBroadcast),
            0b111001 => Some(AltControlBroadcast),
            0b111010 => Some(RFSSStatusBroadcast),
            0b111011 => Some(NetworkStatusBroadcast),
            0b111100 => Some(AdjacentSiteBroadcast),
            0b111101 => Some(ChannelParamsUpdate),
            0b111110 => Some(ProtectionParamBroadcast),
            0b111111 => Some(ProtectionParamUpdate),

            _ => None,
        }
    }
}

pub type Buf = [u8; 12];

#[derive(Copy, Clone)]
pub struct TSBK(Buf);

impl TSBK {
    pub fn new(buf: Buf) -> TSBK { TSBK(buf) }

    pub fn is_tail(&self) -> bool { self.0[0] >> 7 == 1 }
    pub fn protected(&self) -> bool { self.0[0] >> 6 & 1 == 1 }
    pub fn opcode(&self) -> Option<TSBKOpcode> { TSBKOpcode::from_bits(self.0[0] & 0x3F) }
    pub fn mfg(&self) -> u8 { self.0[1] }
    pub fn crc(&self) -> u16 { slice_u16(&self.0[10..]) }

    pub fn calc_crc(&self) -> u16 {
        crc::CRC16::new()
            .feed_bytes((&self.0[..10]).iter().cloned())
            .finish() as u16
    }
}

pub struct GroupVoiceGrant(Buf);

impl GroupVoiceGrant {
    pub fn new(tsbk: TSBK) -> Self { GroupVoiceGrant(tsbk.0) }

    pub fn opts(&self) -> ServiceOptions { ServiceOptions::new(self.0[2]) }
    pub fn talk_group(&self) -> TalkGroup { TalkGroup::new(&self.0[5..]) }
    pub fn src_unit(&self) -> u32 { slice_u24(&self.0[7..]) }
}

pub struct GroupVoiceUpdate(Buf);

impl GroupVoiceUpdate {
    pub fn new(tsbk: TSBK) -> Self { GroupVoiceUpdate(tsbk.0) }

    pub fn channel_a(&self) -> Channel { Channel::new(&self.0[2..]) }
    pub fn talk_group_a(&self) -> TalkGroup { TalkGroup::new(&self.0[4..]) }
    pub fn channel_b(&self) -> Channel { Channel::new(&self.0[6..]) }
    pub fn talk_group_b(&self) -> TalkGroup { TalkGroup::new(&self.0[8..]) }
}

pub struct GroupVoiceUpdateExplicit(Buf);

impl GroupVoiceUpdateExplicit {
    pub fn new(tsbk: TSBK) -> Self { GroupVoiceUpdateExplicit(tsbk.0) }

    pub fn opts(&self) -> ServiceOptions { ServiceOptions::new(self.0[2]) }
    pub fn tx_channel(&self) -> Channel { Channel::new(&self.0[4..]) }
    pub fn rx_channel(&self) -> Channel { Channel::new(&self.0[6..]) }
    pub fn talk_group(&self) -> TalkGroup { TalkGroup::new(&self.0[8..]) }
}

pub struct UnitVoiceGrant(Buf);

impl UnitVoiceGrant {
    pub fn new(tsbk: TSBK) -> Self { UnitVoiceGrant(tsbk.0) }

    pub fn channel(&self) -> Channel { Channel::new(&self.0[2..]) }
    pub fn dest_unit(&self) -> u32 { slice_u24(&self.0[4..]) }
    pub fn src_unit(&self) -> u32 { slice_u24(&self.0[7..]) }
}

pub struct UnitCallRequest(Buf);

impl UnitCallRequest {
    pub fn new(tsbk: TSBK) -> Self { UnitCallRequest(tsbk.0) }

    pub fn opts(&self) -> ServiceOptions { ServiceOptions::new(self.0[2]) }
    pub fn dest_unit(&self) -> u32 { slice_u24(&self.0[4..]) }
    pub fn src_id(&self) -> u32 { slice_u24(&self.0[7..]) }
}

pub struct UnitVoiceUpdate(Buf);

impl UnitVoiceUpdate {
    pub fn new(tsbk: TSBK) -> Self { UnitVoiceUpdate(tsbk.0) }

    pub fn channel(&self) -> Channel { Channel::new(&self.0[2..]) }
    pub fn dest_unit(&self) -> u32 { slice_u24(&self.0[4..]) }
    pub fn src_unit(&self) -> u32 { slice_u24(&self.0[7..]) }
}

pub struct PhoneGrant(Buf);

impl PhoneGrant {
    pub fn new(tsbk: TSBK) -> Self { PhoneGrant(tsbk.0) }

    pub fn opts(&self) -> ServiceOptions { ServiceOptions::new(self.0[2]) }
    pub fn channel(&self) -> Channel { Channel::new(&self.0[3..]) }
    pub fn call_timer(&self) -> u16 { slice_u16(&self.0[5..]) }
    pub fn unit(&self) -> u32 { slice_u24(&self.0[7..]) }
}

pub struct UnitDataGrant(Buf);

impl UnitDataGrant {
    pub fn new(tsbk: TSBK) -> Self { UnitDataGrant(tsbk.0) }

    pub fn channel(&self) -> Channel { Channel::new(&self.0[2..]) }
    pub fn dest_unit(&self) -> u32 { slice_u24(&self.0[4..]) }
    pub fn src_unit(&self) -> u32 { slice_u24(&self.0[7..]) }
}
pub struct AltControlBroadcast(Buf);

impl AltControlBroadcast {
    pub fn new(tsbk: TSBK) -> Self { AltControlBroadcast(tsbk.0) }

    pub fn rfss(&self) -> u8 { self.0[2] }
    pub fn site(&self) -> u8 { self.0[3] }

    pub fn channel_a(&self) -> Channel { Channel::new(&self.0[4..]) }
    pub fn services_a(&self) -> SystemServices { SystemServices::new(self.0[6]) }

    pub fn channel_b(&self) -> Channel { Channel::new(&self.0[7..]) }
    pub fn serviced_b(&self) -> SystemServices { SystemServices::new(self.0[9]) }
}

pub struct NetworkStatusBroadcast(Buf);

impl NetworkStatusBroadcast {
    pub fn new(tsbk: TSBK) -> Self { NetworkStatusBroadcast(tsbk.0) }

    pub fn area(&self) -> u8 { self.0[2] }
    pub fn wacn(&self) -> u32 { slice_u24(&self.0[3..]) >> 4 }
    pub fn system(&self) -> u16 { slice_u16(&self.0[5..]) & 0xFFF }
    pub fn channel(&self) -> Channel { Channel::new(&self.0[7..]) }
    pub fn services(&self) -> SystemServices { SystemServices::new(self.0[9]) }
}

pub struct SiteStatusBroadcast(Buf);

impl SiteStatusBroadcast {
    pub fn new(tsbk: TSBK) -> Self { SiteStatusBroadcast(tsbk.0) }

    pub fn area(&self) -> u8 { self.0[2] }
    pub fn is_conventional(&self) -> bool { self.0[3] & 0x80 != 0 }
    pub fn is_down(&self) -> bool { self.0[3] & 0x40 != 0 }
    pub fn is_current(&self) -> bool { self.0[3] & 0x20 != 0 }
    pub fn has_network(&self) -> bool { self.0[3] & 0x10 != 0 }
    pub fn system(&self) -> u16 { slice_u16(&self.0[3..]) & 0xFFF }
    pub fn rfss(&self) -> u8 { self.0[5] }
    pub fn site(&self) -> u8 { self.0[6] }
    pub fn channel(&self) -> Channel { Channel::new(&self.0[7..]) }
    pub fn services(&self) -> SystemServices { SystemServices::new(self.0[9]) }
}

pub struct ChannelParamsUpdate(Buf);

impl ChannelParamsUpdate {
    pub fn new(tsbk: TSBK) -> Self { ChannelParamsUpdate(tsbk.0) }

    pub fn ident(&self) -> u8 { self.0[2] >> 4 }
    pub fn bandwidth(&self) -> u16 {
        (self.0[2] as u16 & 0xF) << 5 | (self.0[3] >> 3) as u16
    }
    pub fn offset(&self) -> u16 {
        (self.0[3] as u16 & 0x7) << 6 | (self.0[4] >> 2) as u16
    }
    pub fn spacing(&self) -> u16 {
        (self.0[4] as u16 & 0x3) << 8 | self.0[5] as u16
    }
    pub fn base_freq(&self) -> u32 { slice_u32(&self.0[6..]) }
}
<commit_msg>Use ChannelParams decoder for ChannelParamsUpdate<commit_after>use collect_slice::CollectSlice;

use bits::{Dibit, DibitBytes};
use buffer::{Buffer, DataPayloadStorage};
use coding::trellis;
use data::{crc, interleave};
use error::{Result, P25Error};

use trunking::decode::*;

pub struct TSBKDecoder {
    dibits: Buffer<DataPayloadStorage>,
}

impl TSBKDecoder {
    pub fn new() -> TSBKDecoder {
        TSBKDecoder {
            dibits: Buffer::new(DataPayloadStorage::new()),
        }
    }

    pub fn feed(&mut self, dibit: Dibit) -> Option<Result<TSBK>> {
        let (count, dibits) = {
            let buf = match self.dibits.feed(dibit) {
                Some(buf) => buf,
                None => return None,
            };

            let mut dibits = [Dibit::default(); 48];
            let count = trellis::DibitDecoder::new(interleave::Deinterleaver::new(buf))
                .filter(|x| x.is_ok()).map(|x| x.unwrap())
                .collect_slice(&mut dibits[..]);

            (count, dibits)
        };

        self.dibits.reset();

        if count != dibits.len() {
            return Some(Err(P25Error::ViterbiUnrecoverable));
        }

        let mut bytes = [0; 12];
        DibitBytes::new(dibits.iter().cloned()).collect_slice_checked(&mut bytes[..]);

        Some(Ok(TSBK::new(bytes)))
    }
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum TSBKOpcode {
    GroupVoiceGrant,
    GroupVoiceUpdate,
    GroupVoiceUpdateExplicit,
    UnitVoiceGrant,
    UnitCallRequest,
    UnitVoiceUpdate,
    PhoneGrant,
    PhoneCallRequest,
    UnitDataGrant,
    GroupDataGrant,
    GroupDataAnnounce,
    GroupDataAnnounceExplicit,
    UnitStatusUpdate,
    UnitStatusQuery,
    UnitShortMessage,
    UnitMonitor,
    UnitCallAlert,
    AckResponse,
    QueuedResponse,
    ExtendedFunctionResponse,
    DenyResponse,
    GroupAffiliationResponse,
    GroupAffiliationQuery,
    LocRegistrationResponse,
    UnitRegistrationResponse,
    UnitRegistrationCommand,
    AuthCommand,
    DeregistrationAck,
    RoamingAddrCommand,
    RoamingAddrUpdate,
    SystemServiceBroadcast,
    AltControlBroadcast,
    RFSSStatusBroadcast,
    NetworkStatusBroadcast,
    AdjacentSiteBroadcast,
    ChannelParamsUpdate,
    ProtectionParamBroadcast,
    ProtectionParamUpdate,
    Reserved,
}

impl TSBKOpcode {
    pub fn from_bits(bits: u8) -> Option<TSBKOpcode> {
        use self::TSBKOpcode::*;

        match bits {
            0b000000 => Some(GroupVoiceGrant),
            0b000001 => Some(Reserved),
            0b000010 => Some(GroupVoiceUpdate),
            0b000011 => Some(GroupVoiceUpdateExplicit),
            0b000100 => Some(UnitVoiceGrant),
            0b000101 => Some(UnitCallRequest),
            0b000110 => Some(UnitVoiceUpdate),
            0b000111 => Some(Reserved),

            0b001000 => Some(PhoneGrant),
            0b001001 => Some(Reserved),
            0b001010 => Some(PhoneCallRequest),
            0b001011...0b001111 => Some(Reserved),

            0b010000 => Some(UnitDataGrant),
            0b010001 => Some(GroupDataGrant),
            0b010010 => Some(GroupDataAnnounce),
            0b010011 => Some(GroupDataAnnounceExplicit),
            0b010100...0b010111 => Some(Reserved),

            0b011000 => Some(UnitStatusUpdate),
            0b011001 => Some(Reserved),
            0b011010 => Some(UnitStatusQuery),
            0b011011 => Some(Reserved),
            0b011100 => Some(UnitShortMessage),
            0b011101 => Some(UnitMonitor),
            0b011110 => Some(Reserved),
            0b011111 => Some(UnitCallAlert),
            0b100000 => Some(AckResponse),
            0b100001 => Some(QueuedResponse),
            0b100010 => Some(Reserved),
            0b100011 => Some(Reserved),
            0b100100 => Some(ExtendedFunctionResponse),
            0b100101 => Some(Reserved),
            0b100110 => Some(Reserved),
            0b100111 => Some(DenyResponse),

            0b101000 => Some(GroupAffiliationResponse),
            0b101001 => Some(Reserved),
            0b101010 => Some(GroupAffiliationQuery),
            0b101011 => Some(LocRegistrationResponse),
            0b101100 => Some(UnitRegistrationResponse),
            0b101101 => Some(UnitRegistrationCommand),
            0b101110 => Some(AuthCommand),
            0b101111 => Some(DeregistrationAck),

            0b110000...0b110101 => Some(Reserved),
            0b110110 => Some(RoamingAddrCommand),
            0b110111 => Some(RoamingAddrUpdate),

            0b111000 => Some(SystemServiceBroadcast),
            0b111001 => Some(AltControlBroadcast),
            0b111010 => Some(RFSSStatusBroadcast),
            0b111011 => Some(NetworkStatusBroadcast),
            0b111100 => Some(AdjacentSiteBroadcast),
            0b111101 => Some(ChannelParamsUpdate),
            0b111110 => Some(ProtectionParamBroadcast),
            0b111111 => Some(ProtectionParamUpdate),

            _ => None,
        }
    }
}

pub type Buf = [u8; 12];

#[derive(Copy, Clone)]
pub struct TSBK(Buf);

impl TSBK {
    pub fn new(buf: Buf) -> TSBK { TSBK(buf) }

    pub fn is_tail(&self) -> bool { self.0[0] >> 7 == 1 }
    pub fn protected(&self) -> bool { self.0[0] >> 6 & 1 == 1 }
    pub fn opcode(&self) -> Option<TSBKOpcode> { TSBKOpcode::from_bits(self.0[0] & 0x3F) }
    pub fn mfg(&self) -> u8 { self.0[1] }
    pub fn crc(&self) -> u16 { slice_u16(&self.0[10..]) }

    pub fn calc_crc(&self) -> u16 {
        crc::CRC16::new()
            .feed_bytes((&self.0[..10]).iter().cloned())
            .finish() as u16
    }
}

pub struct GroupVoiceGrant(Buf);

impl GroupVoiceGrant {
    pub fn new(tsbk: TSBK) -> Self { GroupVoiceGrant(tsbk.0) }

    pub fn opts(&self) -> ServiceOptions { ServiceOptions::new(self.0[2]) }
    pub fn talk_group(&self) -> TalkGroup { TalkGroup::new(&self.0[5..]) }
    pub fn src_unit(&self) -> u32 { slice_u24(&self.0[7..]) }
}

pub struct GroupVoiceUpdate(Buf);

impl GroupVoiceUpdate {
    pub fn new(tsbk: TSBK) -> Self { GroupVoiceUpdate(tsbk.0) }

    pub fn channel_a(&self) -> Channel { Channel::new(&self.0[2..]) }
    pub fn talk_group_a(&self) -> TalkGroup { TalkGroup::new(&self.0[4..]) }
    pub fn channel_b(&self) -> Channel { Channel::new(&self.0[6..]) }
    pub fn talk_group_b(&self) -> TalkGroup { TalkGroup::new(&self.0[8..]) }
}

pub struct GroupVoiceUpdateExplicit(Buf);

impl GroupVoiceUpdateExplicit {
    pub fn new(tsbk: TSBK) -> Self { GroupVoiceUpdateExplicit(tsbk.0) }

    pub fn opts(&self) -> ServiceOptions { ServiceOptions::new(self.0[2]) }
    pub fn tx_channel(&self) -> Channel { Channel::new(&self.0[4..]) }
    pub fn rx_channel(&self) -> Channel { Channel::new(&self.0[6..]) }
    pub fn talk_group(&self) -> TalkGroup { TalkGroup::new(&self.0[8..]) }
}

pub struct UnitVoiceGrant(Buf);

impl UnitVoiceGrant {
    pub fn new(tsbk: TSBK) -> Self { UnitVoiceGrant(tsbk.0) }

    pub fn channel(&self) -> Channel { Channel::new(&self.0[2..]) }
    pub fn dest_unit(&self) -> u32 { slice_u24(&self.0[4..]) }
    pub fn src_unit(&self) -> u32 { slice_u24(&self.0[7..]) }
}

pub struct UnitCallRequest(Buf);

impl UnitCallRequest {
    pub fn new(tsbk: TSBK) -> Self { UnitCallRequest(tsbk.0) }

    pub fn opts(&self) -> ServiceOptions { ServiceOptions::new(self.0[2]) }
    pub fn dest_unit(&self) -> u32 { slice_u24(&self.0[4..]) }
    pub fn src_id(&self) -> u32 { slice_u24(&self.0[7..]) }
}

pub struct UnitVoiceUpdate(Buf);

impl UnitVoiceUpdate {
    pub fn new(tsbk: TSBK) -> Self { UnitVoiceUpdate(tsbk.0) }

    pub fn channel(&self) -> Channel { Channel::new(&self.0[2..]) }
    pub fn dest_unit(&self) -> u32 { slice_u24(&self.0[4..]) }
    pub fn src_unit(&self) -> u32 { slice_u24(&self.0[7..]) }
}

pub struct PhoneGrant(Buf);

impl PhoneGrant {
    pub fn new(tsbk: TSBK) -> Self { PhoneGrant(tsbk.0) }

    pub fn opts(&self) -> ServiceOptions { ServiceOptions::new(self.0[2]) }
    pub fn channel(&self) -> Channel { Channel::new(&self.0[3..]) }
    pub fn call_timer(&self) -> u16 { slice_u16(&self.0[5..]) }
    pub fn unit(&self) -> u32 { slice_u24(&self.0[7..]) }
}

pub struct UnitDataGrant(Buf);

impl UnitDataGrant {
    pub fn new(tsbk: TSBK) -> Self { UnitDataGrant(tsbk.0) }

    pub fn channel(&self) -> Channel { Channel::new(&self.0[2..]) }
    pub fn dest_unit(&self) -> u32 { slice_u24(&self.0[4..]) }
    pub fn src_unit(&self) -> u32 { slice_u24(&self.0[7..]) }
}
pub struct AltControlBroadcast(Buf);

impl AltControlBroadcast {
    pub fn new(tsbk: TSBK) -> Self { AltControlBroadcast(tsbk.0) }

    pub fn rfss(&self) -> u8 { self.0[2] }
    pub fn site(&self) -> u8 { self.0[3] }

    pub fn channel_a(&self) -> Channel { Channel::new(&self.0[4..]) }
    pub fn services_a(&self) -> SystemServices { SystemServices::new(self.0[6]) }

    pub fn channel_b(&self) -> Channel { Channel::new(&self.0[7..]) }
    pub fn serviced_b(&self) -> SystemServices { SystemServices::new(self.0[9]) }
}

pub struct NetworkStatusBroadcast(Buf);

impl NetworkStatusBroadcast {
    pub fn new(tsbk: TSBK) -> Self { NetworkStatusBroadcast(tsbk.0) }

    pub fn area(&self) -> u8 { self.0[2] }
    pub fn wacn(&self) -> u32 { slice_u24(&self.0[3..]) >> 4 }
    pub fn system(&self) -> u16 { slice_u16(&self.0[5..]) & 0xFFF }
    pub fn channel(&self) -> Channel { Channel::new(&self.0[7..]) }
    pub fn services(&self) -> SystemServices { SystemServices::new(self.0[9]) }
}

pub struct SiteStatusBroadcast(Buf);

impl SiteStatusBroadcast {
    pub fn new(tsbk: TSBK) -> Self { SiteStatusBroadcast(tsbk.0) }

    pub fn area(&self) -> u8 { self.0[2] }
    pub fn is_conventional(&self) -> bool { self.0[3] & 0x80 != 0 }
    pub fn is_down(&self) -> bool { self.0[3] & 0x40 != 0 }
    pub fn is_current(&self) -> bool { self.0[3] & 0x20 != 0 }
    pub fn has_network(&self) -> bool { self.0[3] & 0x10 != 0 }
    pub fn system(&self) -> u16 { slice_u16(&self.0[3..]) & 0xFFF }
    pub fn rfss(&self) -> u8 { self.0[5] }
    pub fn site(&self) -> u8 { self.0[6] }
    pub fn channel(&self) -> Channel { Channel::new(&self.0[7..]) }
    pub fn services(&self) -> SystemServices { SystemServices::new(self.0[9]) }
}

pub struct ChannelParamsUpdate(Buf);

impl ChannelParamsUpdate {
    pub fn new(tsbk: TSBK) -> Self { ChannelParamsUpdate(tsbk.0) }

    pub fn params(&self) -> ChannelParams {
        ChannelParams::new(self.base_freq(), self.channel(), self.bandwidth(),
                           self.offset(), self.spacing())
    }

    fn channel(&self) -> u8 { self.0[2] >> 4 }
    fn bandwidth(&self) -> u16 {
        (self.0[2] as u16 & 0xF) << 5 | (self.0[3] >> 3) as u16
    }
    fn offset(&self) -> u16 {
        (self.0[3] as u16 & 0x7) << 6 | (self.0[4] >> 2) as u16
    }
    fn spacing(&self) -> u16 {
        (self.0[4] as u16 & 0x3) << 8 | self.0[5] as u16
    }
    fn base_freq(&self) -> u32 { slice_u32(&self.0[6..]) }
}
<|endoftext|>


<commit_before>pub use self::Side::{Left, Right};
pub use self::Color::{Yellow, Blue};

use std::collections::BTreeMap;
use ::prelude::*;
use ::game;

const FIELD_LENGTH: f32    = 9.010;
const CENTER_DIAMETER: f32 = 1.000;
const DEFENSE_RADIUS: f32  = 1.000;
const ROBOT_RADIUS: f32    = 0.090;
const BALL_RADIUS: f32     = 0.023;
const BALL_FRICT_LOSS: f32 = 1.000;

#[derive(Clone, Debug, PartialEq)]
pub struct Vec2d {
    pub x: f32,
    pub y: f32,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Vec3d {
    pub x: f32,
    pub y: f32,
    pub z: f32,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Ball {
    pub pos: Vec3d,
    pub vel: Vec3d,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Robot {
    pub pos: Vec2d,
    pub vel: Vec2d,
    pub w: f32,
    pub vw: f32,
}

impl Robot {
    #[inline]
    pub fn new() -> Robot {
        Robot { pos: Vec2d { x: 0.0, y: 0.0 }, w: 0.0, vel: Vec2d { x: 0.0, y: 0.0 }, vw: 0.0 }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Color {
    Yellow,
    Blue,
}

impl Color {
    #[inline] pub fn is_yellow(&self) -> bool { *self == Yellow }
    #[inline] pub fn is_blue(&self)   -> bool { *self == Blue }
    #[inline] pub fn yellow(is_yellow: bool) -> Color { if is_yellow { Yellow } else { Blue   } }
    #[inline] pub fn blue(is_blue: bool)     -> Color { if is_blue   { Blue   } else { Yellow } }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Side {
    Left,
    Right
}

impl Side {
    #[inline] pub fn is_right(&self) -> bool { *self == Right }
    #[inline] pub fn is_left(&self)  -> bool { *self == Left }
    #[inline] pub fn right(is_right: bool) -> Side { if is_right { Right } else { Left  } }
    #[inline] pub fn left(is_left: bool)   -> Side { if is_left  { Left  } else { Right } }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct TeamSide(pub Color, pub Side);

impl TeamSide {
    #[inline]
    pub fn yellow_is_left(&self) -> bool {
        match *self {
            TeamSide(Yellow, Left)  => true,
            TeamSide(Yellow, Right) => false,
            TeamSide(Blue,   Right) => true,
            TeamSide(Blue,   Left)  => false,
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Id(pub Color, pub u8);

#[derive(Clone, Debug, PartialEq)]
pub struct State {
    pub timestamp: f32,
    pub ball: Ball,
    pub robots: BTreeMap<Id, Robot>,
    pub team_side: TeamSide,
}

trait BTreeMapSimExt {
    fn initial_formation(&mut self, count: u8, color: Color, side: Side);
}

impl BTreeMapSimExt for BTreeMap<Id, Robot> {
    fn initial_formation(&mut self, count: u8, color: Color, side: Side) {
        use std::f32::consts::PI;

        let w_0 = if side.is_right() { 0.0 } else { PI };
        let w_delta = 2.0 * PI / (count as f32) * if side.is_right() { 1.0 } else { -1.0 };
        let x_offset = (CENTER_DIAMETER / 4.0 + FIELD_LENGTH / 4.0 - DEFENSE_RADIUS / 2.0) * if side.is_right() { 1.0 } else { -1.0 };
        //let radius = FIELD_LENGTH / 8.0;
        let radius = (FIELD_LENGTH / 2.0 - CENTER_DIAMETER / 2.0 - DEFENSE_RADIUS) / 3.0 - ROBOT_RADIUS;

        for i in 0..count {
            let robot_id = Id(color, i);
            let robot = self.entry(robot_id).or_insert(Robot::new());
            let w = w_0 + (i as f32) * w_delta;
            robot.pos.x = radius * w.cos() + x_offset;
            robot.pos.y = radius * w.sin();
            robot.w = w + PI;
        }
    }
}

impl State {
    pub fn new(team_side: TeamSide) -> State {
        let mut robots = BTreeMap::new();
        if team_side.yellow_is_left() {
            robots.initial_formation(6, Yellow, Left);
            robots.initial_formation(6, Blue, Right);
        } else {
            robots.initial_formation(6, Yellow, Right);
            robots.initial_formation(6, Blue, Left);
        }
        State {
            timestamp: 0.0,
            //ball: Ball { pos: Vec3d { x: 0.0, y: 0.0, z: 0.0 }, vel: Vec3d { x: 0.0, y: 0.0, z: 0.0 } },
            ball: Ball { pos: Vec3d { x: 0.0, y: 0.05, z: 0.0 }, vel: Vec3d { x: -4.0, y: 0.0, z: 0.0 } },
            robots: robots,
            team_side: team_side,
        }
    }

    pub fn update_game(&self, game_state: &mut game::State) {
        // ball
        {
            let game_ball = game_state.get_ball_mut();
            game_ball.set_x(self.ball.pos.x);
            game_ball.set_y(self.ball.pos.y);
            //game_ball.set_z(self.ball.pos.z);
            game_ball.set_vx(self.ball.vel.x);
            game_ball.set_vy(self.ball.vel.y);
            //game_ball.set_vz(self.ball.vel.z);
        }
        // robots
        for (id, ref robot) in self.robots.iter() {
            let (robot_id, ref mut robots) = match id {
                &Id(Blue, i)   => (i, game_state.get_robots_blue_mut()),
                &Id(Yellow, i) => (i, game_state.get_robots_yellow_mut()),
            };
            let game_robot = robots.entry(robot_id).or_insert(game::Robot::new(robot_id));
            game_robot.set_x(robot.pos.x);
            game_robot.set_y(robot.pos.y);
            game_robot.set_w(robot.w);
            game_robot.set_vx(robot.vel.x);
            game_robot.set_vy(robot.vel.y);
            game_robot.set_vw(robot.vw);
        }
        game_state.inc_counter();
    }

    pub fn step(&mut self, command: game::Command, timestep: f32) {
        self.timestamp += timestep;
        let color = Color::yellow(command.is_yellow);
        let &mut State { ref mut ball, ref mut robots, .. } = self;
        let mut d_time_ball = timestep;

        // XXX: overly simplified physics ahead
        for (id, robot_command) in command.robots {
            let robot_id = &Id(color, id);
            if let Some(mut robot) = robots.get_mut(robot_id) {
                let d_time = timestep;

                let v_tangent = robot_command.v_tangent;
                let v_normal  = robot_command.v_normal;
                let v_angular = robot_command.v_angular;

                let w = robot.w;

                let vx = v_normal * w.sin() + v_tangent * w.cos();
                let vy = v_normal * w.cos() - v_tangent * w.sin();
                let vw = v_angular;

                robot.vel.x = vx;
                robot.vel.y = vy;

                let dx = d_time * vx;
                let dy = d_time * vy;
                let dw = d_time * vw;

                // detect collision with ball
                {
                    let rr = ROBOT_RADIUS;
                    let rb = BALL_RADIUS;
                    let xr  = robot.pos.x;
                    let yr  = robot.pos.y;
                    let vrx = robot.vel.x;
                    let vry = robot.vel.y;
                    let xb  = ball.pos.x;
                    let yb  = ball.pos.y;
                    let vbx = ball.vel.x;
                    let vby = ball.vel.y;

                    // Bhāskara:
                    let a = (vry - vby) * (vry - vby) + (vrx - vbx) * (vrx - vbx);
                    let b = 2.0 * ((xr - xb) * (vrx - vbx) + (yr - yb) * (vry - vby));
                    let c = (xr - xb) * (xr - xb) + (yr - yb) * (yr - yb) - (rr + rb) * (rr + rb);

                    if c > 0.0 && a != 0.0 {
                        //debug!("there may be a collision");
                        let tc = (-b - (b * b - 4.0 * a * c).sqrt()) * (0.5 / a);
                        if tc >= 0.0 && tc <= timestep {
                            use std::f32::consts::PI;

                            let xbc = xb + tc * vbx;
                            let ybc = yb + tc * vby;
                            let xrc = xr + tc * vrx;
                            let yrc = yr + tc * vry;
                            debug!("there is a collision, with robot {:?} at {},{}_{},{}", robot_id, xrc, yrc, xbc, ybc);
                            // TODO: dummy collision
                            ball.pos.x = xbc;
                            ball.pos.y = ybc;
                            let wc = (ybc - yrc).atan2(xbc - xrc);
                            let wb = vby.atan2(vbx);
                            let v = (vbx * vbx + vby * vby).sqrt();
                            let w = PI + wc - wb;
                            ball.vel.x = v * w.cos() + 2.0 * vrx;
                            ball.vel.y = v * w.sin() + 2.0 * vry;
                            d_time_ball -= tc;
                        }
                    }
                }

                //println!("dx: {}", dx);

                robot.pos.x += dx;
                robot.pos.y += dy;
                robot.w += dw;

                // TODO: effect of robot_command.action
            }
        }

        // update ball pos
        {
            ball.pos.x += d_time_ball * ball.vel.x;
            ball.pos.y += d_time_ball * ball.vel.y;
            ball.pos.z += d_time_ball * ball.vel.z;
            let r = 1.0 - BALL_FRICT_LOSS * timestep;
            ball.vel.x *= r;
            ball.vel.y *= r;
            ball.vel.z *= r;
        }
    }
}
<commit_msg>Fix collision result: use relative speed reflection.<commit_after>pub use self::Side::{Left, Right};
pub use self::Color::{Yellow, Blue};

use std::collections::BTreeMap;
use ::prelude::*;
use ::game;

const FIELD_LENGTH: f32    = 9.010;
const CENTER_DIAMETER: f32 = 1.000;
const DEFENSE_RADIUS: f32  = 1.000;
const ROBOT_RADIUS: f32    = 0.090;
const BALL_RADIUS: f32     = 0.023;
const BALL_FRICT_LOSS: f32 = 1.000;

#[derive(Clone, Debug, PartialEq)]
pub struct Vec2d {
    pub x: f32,
    pub y: f32,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Vec3d {
    pub x: f32,
    pub y: f32,
    pub z: f32,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Ball {
    pub pos: Vec3d,
    pub vel: Vec3d,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Robot {
    pub pos: Vec2d,
    pub vel: Vec2d,
    pub w: f32,
    pub vw: f32,
}

impl Robot {
    #[inline]
    pub fn new() -> Robot {
        Robot { pos: Vec2d { x: 0.0, y: 0.0 }, w: 0.0, vel: Vec2d { x: 0.0, y: 0.0 }, vw: 0.0 }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Color {
    Yellow,
    Blue,
}

impl Color {
    #[inline] pub fn is_yellow(&self) -> bool { *self == Yellow }
    #[inline] pub fn is_blue(&self)   -> bool { *self == Blue }
    #[inline] pub fn yellow(is_yellow: bool) -> Color { if is_yellow { Yellow } else { Blue   } }
    #[inline] pub fn blue(is_blue: bool)     -> Color { if is_blue   { Blue   } else { Yellow } }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Side {
    Left,
    Right
}

impl Side {
    #[inline] pub fn is_right(&self) -> bool { *self == Right }
    #[inline] pub fn is_left(&self)  -> bool { *self == Left }
    #[inline] pub fn right(is_right: bool) -> Side { if is_right { Right } else { Left  } }
    #[inline] pub fn left(is_left: bool)   -> Side { if is_left  { Left  } else { Right } }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct TeamSide(pub Color, pub Side);

impl TeamSide {
    #[inline]
    pub fn yellow_is_left(&self) -> bool {
        match *self {
            TeamSide(Yellow, Left)  => true,
            TeamSide(Yellow, Right) => false,
            TeamSide(Blue,   Right) => true,
            TeamSide(Blue,   Left)  => false,
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Id(pub Color, pub u8);

#[derive(Clone, Debug, PartialEq)]
pub struct State {
    pub timestamp: f32,
    pub ball: Ball,
    pub robots: BTreeMap<Id, Robot>,
    pub team_side: TeamSide,
}

trait BTreeMapSimExt {
    fn initial_formation(&mut self, count: u8, color: Color, side: Side);
}

impl BTreeMapSimExt for BTreeMap<Id, Robot> {
    fn initial_formation(&mut self, count: u8, color: Color, side: Side) {
        use std::f32::consts::PI;

        let w_0 = if side.is_right() { 0.0 } else { PI };
        let w_delta = 2.0 * PI / (count as f32) * if side.is_right() { 1.0 } else { -1.0 };
        let x_offset = (CENTER_DIAMETER / 4.0 + FIELD_LENGTH / 4.0 - DEFENSE_RADIUS / 2.0) * if side.is_right() { 1.0 } else { -1.0 };
        //let radius = FIELD_LENGTH / 8.0;
        let radius = (FIELD_LENGTH / 2.0 - CENTER_DIAMETER / 2.0 - DEFENSE_RADIUS) / 3.0 - ROBOT_RADIUS;

        for i in 0..count {
            let robot_id = Id(color, i);
            let robot = self.entry(robot_id).or_insert(Robot::new());
            let w = w_0 + (i as f32) * w_delta;
            robot.pos.x = radius * w.cos() + x_offset;
            robot.pos.y = radius * w.sin();
            robot.w = w + PI;
        }
    }
}

impl State {
    pub fn new(team_side: TeamSide) -> State {
        let mut robots = BTreeMap::new();
        if team_side.yellow_is_left() {
            robots.initial_formation(6, Yellow, Left);
            robots.initial_formation(6, Blue, Right);
        } else {
            robots.initial_formation(6, Yellow, Right);
            robots.initial_formation(6, Blue, Left);
        }
        State {
            timestamp: 0.0,
            //ball: Ball { pos: Vec3d { x: 0.0, y: 0.0, z: 0.0 }, vel: Vec3d { x: 0.0, y: 0.0, z: 0.0 } },
            ball: Ball { pos: Vec3d { x: 0.0, y: 0.05, z: 0.0 }, vel: Vec3d { x: -4.0, y: 0.0, z: 0.0 } },
            robots: robots,
            team_side: team_side,
        }
    }

    pub fn update_game(&self, game_state: &mut game::State) {
        // ball
        {
            let game_ball = game_state.get_ball_mut();
            game_ball.set_x(self.ball.pos.x);
            game_ball.set_y(self.ball.pos.y);
            //game_ball.set_z(self.ball.pos.z);
            game_ball.set_vx(self.ball.vel.x);
            game_ball.set_vy(self.ball.vel.y);
            //game_ball.set_vz(self.ball.vel.z);
        }
        // robots
        for (id, ref robot) in self.robots.iter() {
            let (robot_id, ref mut robots) = match id {
                &Id(Blue, i)   => (i, game_state.get_robots_blue_mut()),
                &Id(Yellow, i) => (i, game_state.get_robots_yellow_mut()),
            };
            let game_robot = robots.entry(robot_id).or_insert(game::Robot::new(robot_id));
            game_robot.set_x(robot.pos.x);
            game_robot.set_y(robot.pos.y);
            game_robot.set_w(robot.w);
            game_robot.set_vx(robot.vel.x);
            game_robot.set_vy(robot.vel.y);
            game_robot.set_vw(robot.vw);
        }
        game_state.inc_counter();
    }

    pub fn step(&mut self, command: game::Command, timestep: f32) {
        self.timestamp += timestep;
        let color = Color::yellow(command.is_yellow);
        let &mut State { ref mut ball, ref mut robots, .. } = self;
        let mut d_time_ball = timestep;

        // XXX: overly simplified physics ahead
        for (id, robot_command) in command.robots {
            let robot_id = &Id(color, id);
            if let Some(mut robot) = robots.get_mut(robot_id) {
                let d_time = timestep;

                let v_tangent = robot_command.v_tangent;
                let v_normal  = robot_command.v_normal;
                let v_angular = robot_command.v_angular;

                let w = robot.w;

                let vx = v_normal * w.sin() + v_tangent * w.cos();
                let vy = v_normal * w.cos() - v_tangent * w.sin();
                let vw = v_angular;

                robot.vel.x = vx;
                robot.vel.y = vy;

                let dx = d_time * vx;
                let dy = d_time * vy;
                let dw = d_time * vw;

                // detect collision with ball
                {
                    let rr = ROBOT_RADIUS;
                    let rb = BALL_RADIUS;
                    let xr  = robot.pos.x;
                    let yr  = robot.pos.y;
                    let vrx = robot.vel.x;
                    let vry = robot.vel.y;
                    let xb  = ball.pos.x;
                    let yb  = ball.pos.y;
                    let vbx = ball.vel.x;
                    let vby = ball.vel.y;

                    // Bhāskara:
                    let a = (vrx - vbx) * (vrx - vbx) + (vry - vby) * (vry - vby);
                    let b = 2.0 * ((xr - xb) * (vrx - vbx) + (yr - yb) * (vry - vby));
                    let c = (xr - xb) * (xr - xb) + (yr - yb) * (yr - yb) - (rr + rb) * (rr + rb);
                    let delta = b * b - 4.0 * a * c;

                    if delta >= 0.0 && a != 0.0 {
                        let tc = (-b - delta.sqrt()) * 0.5 / a;
                        if tc >= 0.0 && tc <= timestep {
                            use std::f32::consts::PI;

                            debug!("collision: ball and robot {:?}", robot_id);

                            let xbc = xb + tc * vbx;
                            let ybc = yb + tc * vby;
                            let xrc = xr + tc * vrx;
                            let yrc = yr + tc * vry;
                            ball.pos.x = xbc;
                            ball.pos.y = ybc;

                            let wc = (ybc - yrc).atan2(xbc - xrc);
                            let vdx = vbx - vrx;
                            let vdy = vby - vry;
                            let wd = vdy.atan2(vdx);
                            let v = (vdx * vdx + vdy * vdy).sqrt();
                            let w = 2.0 * wc - PI + wd;
                            let (sin, cos) = w.sin_cos();
                            ball.vel.x = v * cos + vrx;
                            ball.vel.y = v * sin + vry;

                            d_time_ball -= tc;
                        }
                    }
                }

                //println!("dx: {}", dx);

                robot.pos.x += dx;
                robot.pos.y += dy;
                robot.w += dw;

                // TODO: effect of robot_command.action
            }
        }

        // update ball pos
        {
            ball.pos.x += d_time_ball * ball.vel.x;
            ball.pos.y += d_time_ball * ball.vel.y;
            //ball.pos.z += d_time_ball * ball.vel.z;
            let r = 1.0 - BALL_FRICT_LOSS * timestep;
            ball.vel.x *= r;
            ball.vel.y *= r;
            //ball.vel.z *= r;
        }
    }
}
<|endoftext|>


<commit_before>use super::peresil::StrParseExt;

pub trait XmlStr {
    fn end_of_attribute(&self, quote: &str) -> Option<usize>;
    fn end_of_char_data(&self) -> Option<usize>;
    fn end_of_cdata(&self) -> Option<usize>;
    fn end_of_decimal_chars(&self) -> Option<usize>;
    fn end_of_hex_chars(&self) -> Option<usize>;
    fn end_of_comment(&self) -> Option<usize>;
    fn end_of_pi_value(&self) -> Option<usize>;
    fn end_of_name(&self) -> Option<usize>;
    fn end_of_ncname(&self) -> Option<usize>;
    fn end_of_space(&self) -> Option<usize>;
    fn end_of_start_tag(&self) -> Option<usize>;
}

impl<'a> XmlStr for &'a str {
    fn end_of_attribute(&self, quote: &str) -> Option<usize> {
        if self.len() == 0 ||
           self.starts_with("&") ||
           self.starts_with("<") ||
           self.starts_with(quote)
        {
            return None;
        }

        let (quote_char, _) = quote.slice_shift_char().expect("Cant have null quote");

        let mut positions = self.char_indices().skip_while(|&(_, c)| c != '&' && c != '<' && c != quote_char);

        match positions.next() {
            Some((offset, _)) => Some(offset),
            None => Some(self.len())
        }
    }

    fn end_of_char_data(&self) -> Option<usize> {
        if self.starts_with("<") ||
           self.starts_with("&") ||
           self.starts_with("]]>")
        {
            return None
        }

        // Using a hex literal because emacs' rust-mode doesn't
        // understand ] in a char literal. :-(
        let mut positions = self.char_indices().skip_while(|&(_, c)| c != '<' && c != '&' && c != '\x5d');

        loop {
            match positions.next() {
                None => return Some(self.len()),
                Some((offset, c)) if c == '<' || c == '&' => return Some(offset),
                Some((offset, _)) => {
                    let tail = &self[offset..];
                    if tail.starts_with("]]>") {
                        return Some(offset)
                    } else {
                        // False alarm, resume scanning
                        continue;
                    }
                },
            }
        }
    }

    fn end_of_cdata(&self) -> Option<usize> {
        match self.find_str("]]>") {
            None => None,
            Some(offset) => Some(offset),
        }
    }

    fn end_of_decimal_chars(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_decimal_char(),
                               |c| c.is_decimal_char())
    }

    fn end_of_hex_chars(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_hex_char(),
                               |c| c.is_hex_char())
    }

    fn end_of_comment(&self) -> Option<usize> {
        // This deliberately does not include the >. -- is not allowed
        // in a comment, so we can just test the end if it matches the
        // complete close delimiter.
        match self.find_str("--") {
            None => None,
            Some(offset) => Some(offset),
        }
    }

    fn end_of_pi_value(&self) -> Option<usize> {
        match self.find_str("?>") {
            None => None,
            Some(offset) => Some(offset),
        }
    }

    fn end_of_name(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_name_start_char(), |c| c.is_name_char())
    }

    fn end_of_ncname(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_ncname_start_char(), |c| c.is_ncname_char())
    }

    fn end_of_space(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_space_char(), |c| c.is_space_char())
    }

    fn end_of_start_tag(&self) -> Option<usize> {
        let mut positions = self.char_indices();

        match positions.next() {
            Some((_, c)) if '<' == c => (),
            _ => return None,
        };

        match positions.next() {
            Some((offset, c)) =>
                match c {
                    '?' | '!' | '/' => None,
                    _ => Some(offset),
                },
            None => Some(self.len()),
        }
    }
}

pub trait XmlChar {
    fn is_name_start_char(self) -> bool;
    fn is_name_char(self) -> bool;
    fn is_ncname_start_char(self) -> bool;
    fn is_ncname_char(self) -> bool;
    fn is_space_char(self) -> bool;
    fn is_decimal_char(self) -> bool;
    fn is_hex_char(self) -> bool;
}

impl XmlChar for char {
    fn is_name_start_char(self) -> bool {
        self == ':' || self.is_ncname_start_char()
    }

    fn is_name_char(self) -> bool {
        self.is_name_start_char() || self.is_ncname_char()
    }

    fn is_ncname_start_char(self) -> bool {
        match self {
            'A'...'Z'                   |
            '_'                         |
            'a'...'z'                   |
            '\u{0000C0}'...'\u{0000D6}' |
            '\u{0000D8}'...'\u{0000F6}' |
            '\u{0000F8}'...'\u{0002FF}' |
            '\u{000370}'...'\u{00037D}' |
            '\u{00037F}'...'\u{001FFF}' |
            '\u{00200C}'...'\u{00200D}' |
            '\u{002070}'...'\u{00218F}' |
            '\u{002C00}'...'\u{002FEF}' |
            '\u{003001}'...'\u{00D7FF}' |
            '\u{00F900}'...'\u{00FDCF}' |
            '\u{00FDF0}'...'\u{00FFFD}' |
            '\u{010000}'...'\u{0EFFFF}' => true,
            _ => false,
        }
    }

    fn is_ncname_char(self) -> bool {
        if self.is_ncname_start_char() { return true; }
        match self {
            '-'                     |
            '.'                     |
            '0'...'9'               |
            '\u{00B7}'              |
            '\u{0300}'...'\u{036F}' |
            '\u{203F}'...'\u{2040}' => true,
            _ => false
        }
    }

    fn is_space_char(self) -> bool {
        match self {
            '\x20' |
            '\x09' |
            '\x0D' |
            '\x0A' => true,
            _ => false,
        }
    }

    fn is_decimal_char(self) -> bool {
        match self {
            '0'...'9' => true,
            _ => false,
        }
    }

    fn is_hex_char(self) -> bool {
        match self {
            '0'...'9' |
            'a'...'f' |
            'A'...'F' => true,
            _ => false,
        }
    }
}

#[cfg(test)]
mod test {

use super::XmlStr;

#[test]
fn end_of_char_data_leading_ampersand() {
    assert_eq!("&".end_of_char_data(), None);
}

#[test]
fn end_of_char_data_leading_less_than() {
    assert_eq!("<".end_of_char_data(), None);
}

#[test]
fn end_of_char_data_leading_cdata_end() {
    assert_eq!("]]>".end_of_char_data(), None);
}

#[test]
fn end_of_char_data_until_ampersand() {
    assert_eq!("hello&world".end_of_char_data(), Some("hello".len()));
}

#[test]
fn end_of_char_data_until_less_than() {
    assert_eq!("hello<world".end_of_char_data(), Some("hello".len()));
}

#[test]
fn end_of_char_data_until_cdata_end() {
    assert_eq!("hello]]>world".end_of_char_data(), Some("hello".len()));
}

#[test]
fn end_of_char_data_includes_right_square() {
    assert_eq!("hello]world".end_of_char_data(), Some("hello]world".len()));
}

}
<commit_msg>Remove use of deprecated find_str<commit_after>use super::peresil::StrParseExt;

pub trait XmlStr {
    fn end_of_attribute(&self, quote: &str) -> Option<usize>;
    fn end_of_char_data(&self) -> Option<usize>;
    fn end_of_cdata(&self) -> Option<usize>;
    fn end_of_decimal_chars(&self) -> Option<usize>;
    fn end_of_hex_chars(&self) -> Option<usize>;
    fn end_of_comment(&self) -> Option<usize>;
    fn end_of_pi_value(&self) -> Option<usize>;
    fn end_of_name(&self) -> Option<usize>;
    fn end_of_ncname(&self) -> Option<usize>;
    fn end_of_space(&self) -> Option<usize>;
    fn end_of_start_tag(&self) -> Option<usize>;
}

impl<'a> XmlStr for &'a str {
    fn end_of_attribute(&self, quote: &str) -> Option<usize> {
        if self.len() == 0 ||
           self.starts_with("&") ||
           self.starts_with("<") ||
           self.starts_with(quote)
        {
            return None;
        }

        let (quote_char, _) = quote.slice_shift_char().expect("Cant have null quote");

        let mut positions = self.char_indices().skip_while(|&(_, c)| c != '&' && c != '<' && c != quote_char);

        match positions.next() {
            Some((offset, _)) => Some(offset),
            None => Some(self.len())
        }
    }

    fn end_of_char_data(&self) -> Option<usize> {
        if self.starts_with("<") ||
           self.starts_with("&") ||
           self.starts_with("]]>")
        {
            return None
        }

        // Using a hex literal because emacs' rust-mode doesn't
        // understand ] in a char literal. :-(
        let mut positions = self.char_indices().skip_while(|&(_, c)| c != '<' && c != '&' && c != '\x5d');

        loop {
            match positions.next() {
                None => return Some(self.len()),
                Some((offset, c)) if c == '<' || c == '&' => return Some(offset),
                Some((offset, _)) => {
                    let tail = &self[offset..];
                    if tail.starts_with("]]>") {
                        return Some(offset)
                    } else {
                        // False alarm, resume scanning
                        continue;
                    }
                },
            }
        }
    }

    fn end_of_cdata(&self) -> Option<usize> {
        match self.find("]]>") {
            None => None,
            Some(offset) => Some(offset),
        }
    }

    fn end_of_decimal_chars(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_decimal_char(),
                               |c| c.is_decimal_char())
    }

    fn end_of_hex_chars(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_hex_char(),
                               |c| c.is_hex_char())
    }

    fn end_of_comment(&self) -> Option<usize> {
        // This deliberately does not include the >. -- is not allowed
        // in a comment, so we can just test the end if it matches the
        // complete close delimiter.
        match self.find("--") {
            None => None,
            Some(offset) => Some(offset),
        }
    }

    fn end_of_pi_value(&self) -> Option<usize> {
        match self.find("?>") {
            None => None,
            Some(offset) => Some(offset),
        }
    }

    fn end_of_name(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_name_start_char(), |c| c.is_name_char())
    }

    fn end_of_ncname(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_ncname_start_char(), |c| c.is_ncname_char())
    }

    fn end_of_space(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_space_char(), |c| c.is_space_char())
    }

    fn end_of_start_tag(&self) -> Option<usize> {
        let mut positions = self.char_indices();

        match positions.next() {
            Some((_, c)) if '<' == c => (),
            _ => return None,
        };

        match positions.next() {
            Some((offset, c)) =>
                match c {
                    '?' | '!' | '/' => None,
                    _ => Some(offset),
                },
            None => Some(self.len()),
        }
    }
}

pub trait XmlChar {
    fn is_name_start_char(self) -> bool;
    fn is_name_char(self) -> bool;
    fn is_ncname_start_char(self) -> bool;
    fn is_ncname_char(self) -> bool;
    fn is_space_char(self) -> bool;
    fn is_decimal_char(self) -> bool;
    fn is_hex_char(self) -> bool;
}

impl XmlChar for char {
    fn is_name_start_char(self) -> bool {
        self == ':' || self.is_ncname_start_char()
    }

    fn is_name_char(self) -> bool {
        self.is_name_start_char() || self.is_ncname_char()
    }

    fn is_ncname_start_char(self) -> bool {
        match self {
            'A'...'Z'                   |
            '_'                         |
            'a'...'z'                   |
            '\u{0000C0}'...'\u{0000D6}' |
            '\u{0000D8}'...'\u{0000F6}' |
            '\u{0000F8}'...'\u{0002FF}' |
            '\u{000370}'...'\u{00037D}' |
            '\u{00037F}'...'\u{001FFF}' |
            '\u{00200C}'...'\u{00200D}' |
            '\u{002070}'...'\u{00218F}' |
            '\u{002C00}'...'\u{002FEF}' |
            '\u{003001}'...'\u{00D7FF}' |
            '\u{00F900}'...'\u{00FDCF}' |
            '\u{00FDF0}'...'\u{00FFFD}' |
            '\u{010000}'...'\u{0EFFFF}' => true,
            _ => false,
        }
    }

    fn is_ncname_char(self) -> bool {
        if self.is_ncname_start_char() { return true; }
        match self {
            '-'                     |
            '.'                     |
            '0'...'9'               |
            '\u{00B7}'              |
            '\u{0300}'...'\u{036F}' |
            '\u{203F}'...'\u{2040}' => true,
            _ => false
        }
    }

    fn is_space_char(self) -> bool {
        match self {
            '\x20' |
            '\x09' |
            '\x0D' |
            '\x0A' => true,
            _ => false,
        }
    }

    fn is_decimal_char(self) -> bool {
        match self {
            '0'...'9' => true,
            _ => false,
        }
    }

    fn is_hex_char(self) -> bool {
        match self {
            '0'...'9' |
            'a'...'f' |
            'A'...'F' => true,
            _ => false,
        }
    }
}

#[cfg(test)]
mod test {

use super::XmlStr;

#[test]
fn end_of_char_data_leading_ampersand() {
    assert_eq!("&".end_of_char_data(), None);
}

#[test]
fn end_of_char_data_leading_less_than() {
    assert_eq!("<".end_of_char_data(), None);
}

#[test]
fn end_of_char_data_leading_cdata_end() {
    assert_eq!("]]>".end_of_char_data(), None);
}

#[test]
fn end_of_char_data_until_ampersand() {
    assert_eq!("hello&world".end_of_char_data(), Some("hello".len()));
}

#[test]
fn end_of_char_data_until_less_than() {
    assert_eq!("hello<world".end_of_char_data(), Some("hello".len()));
}

#[test]
fn end_of_char_data_until_cdata_end() {
    assert_eq!("hello]]>world".end_of_char_data(), Some("hello".len()));
}

#[test]
fn end_of_char_data_includes_right_square() {
    assert_eq!("hello]world".end_of_char_data(), Some("hello]world".len()));
}

}
<|endoftext|>