<commit_before>#![allow(unused_imports, unused_variables, dead_code)]
use super::error::ConfigError;
use anyhow::{anyhow, Result};

use serde::de::{Deserializer, Error, MapAccess, SeqAccess, Visitor};
use serde::Deserialize;
use std::collections::HashMap;
use std::fmt;
use std::num::ParseIntError;
use std::path::PathBuf;
use std::vec::Vec;

type Tasks = HashMap<String, Task>;
type Params = HashMap<String, Param>;

#[derive(Debug, Clone, PartialEq)]
pub enum Nargs {
    One,
    Zero,
    OneOrZero,
    OneOrMore,
    ZeroOrMore,
    Range(usize, usize),
}

impl fmt::Display for Nargs {
    fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Nargs::One => write!(fmtr, "Nargs::One[1]"),
            Nargs::Zero => write!(fmtr, "Nargs::Zero[0]"),
            Nargs::OneOrZero => write!(fmtr, "Nargs::OneOrZero[?]"),
            Nargs::OneOrMore => write!(fmtr, "Nargs::OneOrMore[+]"),
            Nargs::ZeroOrMore => write!(fmtr, "Nargs::ZeroOrMore[*]"),
            Nargs::Range(min, max) => write!(fmtr, "Nargs::Range[{}, {}]", min + 1, max),
        }
    }
}

impl Default for Nargs {
    fn default() -> Self {
        Nargs::One
    }
}

impl<'de> Deserialize<'de> for Nargs {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        let result = match &s[..] {
            "1" => Nargs::One,
            "0" => Nargs::Zero,
            "?" => Nargs::OneOrZero,
            "+" => Nargs::OneOrMore,
            "*" => Nargs::ZeroOrMore,
            _ => {
                println!("s={}", s);
                if s.contains(':') {
                    let parts: Vec<&str> = s.split(':').collect();
                    let min = parts[0].parse::<usize>().map_err(Error::custom)?;
                    let max = parts[1].parse::<usize>().map_err(Error::custom)?;
                    Nargs::Range(min - 1, max)
                } else {
                    let num = s.parse::<usize>().map_err(Error::custom)?;
                    Nargs::Range(0, num)
                }
            }
        };
        Ok(result)
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Action {
    Script(String),
    File(PathBuf),
    //URL(Url),
}

#[derive(Debug, Clone, PartialEq)]
pub enum Value {
    Item(String),
    List(Vec<String>),
    Dict(HashMap<String, String>),
    Empty,
}

impl fmt::Display for Value {
    fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Value::Item(s) => write!(fmtr, "Values::Item({})", s),
            Value::List(vs) => write!(fmtr, "Values::List([{}])", vs.join(", ")),
            Value::Dict(ds) => write!(fmtr, "Values::Dict[NOT IMPLEMENTED]"),
            Value::Empty => write!(fmtr, "Value::Empty(\"\")"),
        }
    }
}

impl Default for Value {
    fn default() -> Self {
        Value::Empty
    }
}

fn deserialize_value<'de, D>(deserializer: D) -> Result<Value, D::Error>
where
    D: Deserializer<'de>,
{
    struct ValueEnum;
    impl<'de> Visitor<'de> for ValueEnum {
        type Value = Value;

        fn expecting(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
            fmtr.write_str("string or list of strings")
        }
        fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
        where
            E: Error,
        {
            Ok(Value::Item(value.to_owned()))
        }
        fn visit_seq<S>(self, mut visitor: S) -> Result<Self::Value, S::Error>
        where
            S: SeqAccess<'de>,
        {
            let mut vec: Vec<String> = vec![];
            while let Some(item) = visitor.next_element()? {
                vec.push(item);
            }
            Ok(Value::List(vec))
        }
    }
    deserializer.deserialize_any(ValueEnum)
}

fn default_otto() -> String {
    "otto".to_string()
}

fn default_verbosity() -> i32 {
    1
}

fn default_api() -> i32 {
    1
}

fn default_jobs() -> i32 {
    12
}
fn default_defaults() -> Defaults {
    Defaults {
        api: default_api(),
        verbosity: default_verbosity(),
        jobs: default_jobs(),
        tasks: vec![],
    }
}

#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Spec {
    #[serde(default = "default_defaults")]
    pub defaults: Defaults,

    pub otto: Otto,
}

#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Defaults {
    #[serde(default = "default_api")]
    pub api: i32,

    #[serde(default = "default_verbosity")]
    pub verbosity: i32,

    #[serde(default = "default_jobs")]
    pub jobs: i32,

    #[serde(default)]
    pub tasks: Vec<String>,
}

#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Otto {
    #[serde(skip_deserializing, default = "default_otto")]
    pub name: String,

    #[serde(default)]
    pub author: Option<String>,

    #[serde(default)]
    pub about: Option<String>,

    #[serde(default)]
    pub version: Option<String>,

    #[serde(default, deserialize_with = "deserialize_param_map")]
    pub params: Params,

    #[serde(default, deserialize_with = "deserialize_task_map")]
    pub tasks: Tasks,

    pub action: Option<String>,
}

impl Otto {
    pub fn task_names(&self) -> Vec<&str> {
        self.tasks.keys().map(AsRef::as_ref).collect()
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum ParamType {
    FLG,
    OPT,
    POS,
}

impl Default for ParamType {
    fn default() -> Self {
        ParamType::OPT
    }
}

// FIXME: Flag, Named and Positional Args
#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Param {
    #[serde(skip_deserializing)]
    pub name: String,

    #[serde(skip_deserializing)]
    pub short: Option<char>,

    #[serde(skip_deserializing)]
    pub long: Option<String>,

    #[serde(skip_deserializing, default)]
    pub param_type: ParamType,

    #[serde(default)]
    pub dest: Option<String>,

    #[serde(default)]
    pub metavar: Option<String>,

    #[serde(default)]
    pub default: Option<String>,

    #[serde(default, deserialize_with = "deserialize_value")]
    pub constant: Value,

    #[serde(default)]
    pub choices: Vec<String>,

    #[serde(default)]
    pub nargs: Nargs,

    #[serde(default)]
    pub help: Option<String>,
}

fn divine(title: &str) -> (String, Option<char>, Option<String>) {
    let flags: Vec<String> = title.split('|').map(|f| f.to_string()).collect();
    let short = flags
        .iter()
        .cloned()
        .filter(|i| i.starts_with('-') && i.len() == 2)
        .collect::<String>()
        .trim_matches('-')
        .chars()
        .next();

    let long = Some(String::from(
        flags
            .iter()
            .cloned()
            .filter(|i| i.starts_with("--") && i.len() > 2)
            .collect::<String>()
            .trim_matches('-'),
    ))
    .filter(|s| !s.is_empty());

    let name = match long {
        Some(ref long) => long.to_owned(),
        None => match short {
            Some(ref short) => short.to_string(),
            None => title.to_string(),
        },
    };
    (name, short, long)
}

fn deserialize_param_map<'de, D>(deserializer: D) -> Result<Params, D::Error>
where
    D: Deserializer<'de>,
{
    struct ParamMap;

    impl<'de> Visitor<'de> for ParamMap {
        type Value = Params;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a map of name to Param")
        }

        fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
        where
            M: MapAccess<'de>,
        {
            let mut params = Params::new();
            while let Some((title, mut param)) = map.next_entry::<String, Param>()? {
                (param.name, param.short, param.long) = divine(&title);
                if param.long.is_some() || param.short.is_some() {
                    if let Some(ref value) = param.default {
                        if value == "true" || value == "false" {
                            param.param_type = ParamType::FLG;
                        }
                    }
                } else {
                    param.param_type = ParamType::POS;
                }
                params.insert(title.to_owned(), param);
            }
            Ok(params)
        }
    }
    deserializer.deserialize_map(ParamMap)
}

#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Task {
    #[serde(skip_deserializing)]
    pub name: String,

    #[serde(default)]
    pub help: Option<String>,

    #[serde(default)]
    pub after: Vec<String>,

    #[serde(default)]
    pub before: Vec<String>,

    #[serde(default, deserialize_with = "deserialize_param_map")]
    pub params: Params,

    pub action: Option<String>,

    #[serde(skip_deserializing)]
    pub selected: bool,
}

impl Task {
    pub fn new(
        name: String,
        help: Option<String>,
        after: Vec<String>,
        before: Vec<String>,
        params: Params,
        action: Option<String>,
        selected: bool,
    ) -> Self {
        Self {
            name,
            help,
            after,
            before,
            params,
            action,
            selected,
        }
    }
}

fn deserialize_task_map<'de, D>(deserializer: D) -> Result<Tasks, D::Error>
where
    D: Deserializer<'de>,
{
    struct TaskMap;

    impl<'de> Visitor<'de> for TaskMap {
        type Value = Tasks;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a map of name to Task")
        }

        fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
        where
            M: MapAccess<'de>,
        {
            let mut tasks = Tasks::new();
            while let Some((name, mut task)) = map.next_entry::<String, Task>()? {
                task.name = name.to_owned();
                tasks.insert(name.to_owned(), task);
            }
            Ok(tasks)
        }
    }
    deserializer.deserialize_map(TaskMap)
}
<commit_msg>suggested pub typedefs<commit_after>#![allow(unused_imports, unused_variables, dead_code)]
use super::error::ConfigError;
use anyhow::{anyhow, Result};

use serde::de::{Deserializer, Error, MapAccess, SeqAccess, Visitor};
use serde::Deserialize;
use std::collections::HashMap;
use std::fmt;
use std::num::ParseIntError;
use std::path::PathBuf;
use std::vec::Vec;

pub(crate) type Tasks = HashMap<String, Task>;
pub type Params = HashMap<String, Param>;

#[derive(Debug, Clone, PartialEq)]
pub enum Nargs {
    One,
    Zero,
    OneOrZero,
    OneOrMore,
    ZeroOrMore,
    Range(usize, usize),
}

impl fmt::Display for Nargs {
    fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Nargs::One => write!(fmtr, "Nargs::One[1]"),
            Nargs::Zero => write!(fmtr, "Nargs::Zero[0]"),
            Nargs::OneOrZero => write!(fmtr, "Nargs::OneOrZero[?]"),
            Nargs::OneOrMore => write!(fmtr, "Nargs::OneOrMore[+]"),
            Nargs::ZeroOrMore => write!(fmtr, "Nargs::ZeroOrMore[*]"),
            Nargs::Range(min, max) => write!(fmtr, "Nargs::Range[{}, {}]", min + 1, max),
        }
    }
}

impl Default for Nargs {
    fn default() -> Self {
        Nargs::One
    }
}

impl<'de> Deserialize<'de> for Nargs {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        let result = match &s[..] {
            "1" => Nargs::One,
            "0" => Nargs::Zero,
            "?" => Nargs::OneOrZero,
            "+" => Nargs::OneOrMore,
            "*" => Nargs::ZeroOrMore,
            _ => {
                println!("s={}", s);
                if s.contains(':') {
                    let parts: Vec<&str> = s.split(':').collect();
                    let min = parts[0].parse::<usize>().map_err(Error::custom)?;
                    let max = parts[1].parse::<usize>().map_err(Error::custom)?;
                    Nargs::Range(min - 1, max)
                } else {
                    let num = s.parse::<usize>().map_err(Error::custom)?;
                    Nargs::Range(0, num)
                }
            }
        };
        Ok(result)
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Action {
    Script(String),
    File(PathBuf),
    //URL(Url),
}

#[derive(Debug, Clone, PartialEq)]
pub enum Value {
    Item(String),
    List(Vec<String>),
    Dict(HashMap<String, String>),
    Empty,
}

impl fmt::Display for Value {
    fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Value::Item(s) => write!(fmtr, "Values::Item({})", s),
            Value::List(vs) => write!(fmtr, "Values::List([{}])", vs.join(", ")),
            Value::Dict(ds) => write!(fmtr, "Values::Dict[NOT IMPLEMENTED]"),
            Value::Empty => write!(fmtr, "Value::Empty(\"\")"),
        }
    }
}

impl Default for Value {
    fn default() -> Self {
        Value::Empty
    }
}

fn deserialize_value<'de, D>(deserializer: D) -> Result<Value, D::Error>
where
    D: Deserializer<'de>,
{
    struct ValueEnum;
    impl<'de> Visitor<'de> for ValueEnum {
        type Value = Value;

        fn expecting(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
            fmtr.write_str("string or list of strings")
        }
        fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
        where
            E: Error,
        {
            Ok(Value::Item(value.to_owned()))
        }
        fn visit_seq<S>(self, mut visitor: S) -> Result<Self::Value, S::Error>
        where
            S: SeqAccess<'de>,
        {
            let mut vec: Vec<String> = vec![];
            while let Some(item) = visitor.next_element()? {
                vec.push(item);
            }
            Ok(Value::List(vec))
        }
    }
    deserializer.deserialize_any(ValueEnum)
}

fn default_otto() -> String {
    "otto".to_string()
}

fn default_verbosity() -> i32 {
    1
}

fn default_api() -> i32 {
    1
}

fn default_jobs() -> i32 {
    12
}
fn default_defaults() -> Defaults {
    Defaults {
        api: default_api(),
        verbosity: default_verbosity(),
        jobs: default_jobs(),
        tasks: vec![],
    }
}

#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Spec {
    #[serde(default = "default_defaults")]
    pub defaults: Defaults,

    pub otto: Otto,
}

#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Defaults {
    #[serde(default = "default_api")]
    pub api: i32,

    #[serde(default = "default_verbosity")]
    pub verbosity: i32,

    #[serde(default = "default_jobs")]
    pub jobs: i32,

    #[serde(default)]
    pub tasks: Vec<String>,
}

#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Otto {
    #[serde(skip_deserializing, default = "default_otto")]
    pub name: String,

    #[serde(default)]
    pub author: Option<String>,

    #[serde(default)]
    pub about: Option<String>,

    #[serde(default)]
    pub version: Option<String>,

    #[serde(default, deserialize_with = "deserialize_param_map")]
    pub params: Params,

    #[serde(default, deserialize_with = "deserialize_task_map")]
    pub tasks: Tasks,

    pub action: Option<String>,
}

impl Otto {
    pub fn task_names(&self) -> Vec<&str> {
        self.tasks.keys().map(AsRef::as_ref).collect()
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum ParamType {
    FLG,
    OPT,
    POS,
}

impl Default for ParamType {
    fn default() -> Self {
        ParamType::OPT
    }
}

// FIXME: Flag, Named and Positional Args
#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Param {
    #[serde(skip_deserializing)]
    pub name: String,

    #[serde(skip_deserializing)]
    pub short: Option<char>,

    #[serde(skip_deserializing)]
    pub long: Option<String>,

    #[serde(skip_deserializing, default)]
    pub param_type: ParamType,

    #[serde(default)]
    pub dest: Option<String>,

    #[serde(default)]
    pub metavar: Option<String>,

    #[serde(default)]
    pub default: Option<String>,

    #[serde(default, deserialize_with = "deserialize_value")]
    pub constant: Value,

    #[serde(default)]
    pub choices: Vec<String>,

    #[serde(default)]
    pub nargs: Nargs,

    #[serde(default)]
    pub help: Option<String>,
}

fn divine(title: &str) -> (String, Option<char>, Option<String>) {
    let flags: Vec<String> = title.split('|').map(|f| f.to_string()).collect();
    let short = flags
        .iter()
        .cloned()
        .filter(|i| i.starts_with('-') && i.len() == 2)
        .collect::<String>()
        .trim_matches('-')
        .chars()
        .next();

    let long = Some(String::from(
        flags
            .iter()
            .cloned()
            .filter(|i| i.starts_with("--") && i.len() > 2)
            .collect::<String>()
            .trim_matches('-'),
    ))
    .filter(|s| !s.is_empty());

    let name = if let Some(ref long) = long {
        long.to_owned()
    } else {
        match short {
                Some(ref short) => short.to_string(),
                None => title.to_string(),
            }
    };
    (name, short, long)
}

fn deserialize_param_map<'de, D>(deserializer: D) -> Result<Params, D::Error>
where
    D: Deserializer<'de>,
{
    struct ParamMap;

    impl<'de> Visitor<'de> for ParamMap {
        type Value = Params;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a map of name to Param")
        }

        fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
        where
            M: MapAccess<'de>,
        {
            let mut params = Params::new();
            while let Some((title, mut param)) = map.next_entry::<String, Param>()? {
                (param.name, param.short, param.long) = divine(&title);
                if param.long.is_some() || param.short.is_some() {
                    if let Some(ref value) = param.default {
                        if value == "true" || value == "false" {
                            param.param_type = ParamType::FLG;
                        }
                    }
                } else {
                    param.param_type = ParamType::POS;
                }
                params.insert(title.to_owned(), param);
            }
            Ok(params)
        }
    }
    deserializer.deserialize_map(ParamMap)
}

#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Task {
    #[serde(skip_deserializing)]
    pub name: String,

    #[serde(default)]
    pub help: Option<String>,

    #[serde(default)]
    pub after: Vec<String>,

    #[serde(default)]
    pub before: Vec<String>,

    #[serde(default, deserialize_with = "deserialize_param_map")]
    pub params: Params,

    pub action: Option<String>,

    #[serde(skip_deserializing)]
    pub selected: bool,
}

impl Task {
    pub fn new(
        name: String,
        help: Option<String>,
        after: Vec<String>,
        before: Vec<String>,
        params: Params,
        action: Option<String>,
        selected: bool,
    ) -> Self {
        Self {
            name,
            help,
            after,
            before,
            params,
            action,
            selected,
        }
    }
}

fn deserialize_task_map<'de, D>(deserializer: D) -> Result<Tasks, D::Error>
where
    D: Deserializer<'de>,
{
    struct TaskMap;

    impl<'de> Visitor<'de> for TaskMap {
        type Value = Tasks;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a map of name to Task")
        }

        fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
        where
            M: MapAccess<'de>,
        {
            let mut tasks = Tasks::new();
            while let Some((name, mut task)) = map.next_entry::<String, Task>()? {
                task.name = name.to_owned();
                tasks.insert(name.to_owned(), task);
            }
            Ok(tasks)
        }
    }
    deserializer.deserialize_map(TaskMap)
}
<|endoftext|>


<commit_before>//! Types and functions dealing with positions within the source code
//!

use std::ops::{Add, Sub};
use std::cmp::{min, max};

// Helps implementing basic operators, like `Add` and `Sub`
macro_rules! impl_math {
    ($ty_name:ident, $trait_name:ident, $fun_name:ident) => {
        impl $trait_name for $ty_name {
            type Output = $ty_name;

            fn $fun_name(self, rhs: $ty_name) -> $ty_name {
                $ty_name($trait_name::$fun_name(self.0, rhs.0))
            }
        }
    }
}

// ----------------------------------------------------------------------------
/// Type do index one byte in a source code. It should be rather small, since
/// it's used a lot.
pub type SrcOffset = u32;

/// Position within source specified by byte offset. This is not equal to
/// `CharPos` thanks to UTF-8 and multibyte chars. This type always represents
/// positions relative to the whole codemap.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
pub struct BytePos(pub SrcOffset);

impl_math!(BytePos, Add, add);
impl_math!(BytePos, Sub, sub);

// ----------------------------------------------------------------------------
/// A region within the source specified by first and last byte offset. `lo`
/// byte is included in the span, `hi` byte is excluded.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Span {
    /// Low byte, inclusive
    pub lo: BytePos,
    /// High byte, exclusive
    pub hi: BytePos,
}

impl Span {
    /// Creates a span that points to a single char
    pub fn single(pos: BytePos) -> Span {
        Span { lo: pos, hi: pos + BytePos(1) }
    }

    /// Creates a span from a lo and hi (shorter than struct constructor
    /// syntax)
    pub fn new(lo: BytePos, hi: BytePos) -> Span {
        Span { lo: lo, hi: hi }
    }

    /// Creates a span from a tuple
    pub fn from_pair((lo, hi): (BytePos, BytePos)) -> Span {
        Span { lo: lo, hi: hi }
    }

    /// Creates a dummy span. Should be used with caution.
    pub fn dummy() -> Span {
        Span { lo: BytePos(1), hi: BytePos(0) }
    }

    /// Checks if the this span is a dummy span
    pub fn is_dummy(&self) -> bool {
        self.lo.0 == 1 && self.hi.0 == 0
    }

    /// Returns the length (number of bytes) of the span or 0 if it's a dummy
    /// span
    pub fn len(&self) -> SrcOffset {
        if self.is_dummy() {
            0
        } else {
            (self.hi - self.lo).0
        }
    }

    /// Returns the smallest span which encloses both given spans
    ///
    /// If one of given spans is a dummy span, it is ignored and the other span
    /// is returned. If both spans are dummy spans, a dummy span is returned.
    pub fn hull(&self, other: &Self) -> Span {
        if self.is_dummy() {
            *other
        } else if other.is_dummy() {
            *self
        } else {
            Span {
                lo: min(self.lo, other.lo),
                hi: max(self.hi, other.hi),
            }
        }
    }

    /// Checks if this span contains another span. A dummy span never contains
    /// any other span and is never contained in another span.
    pub fn contains(&self, other: Self) -> bool {
        !self.is_dummy()
            && !other.is_dummy()
            && self.lo <= other.lo
            && self.hi >= other.hi
    }
}

// ----------------------------------------------------------------------------
/// Represents a line index.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
pub struct LineIdx(pub SrcOffset);

impl ::std::fmt::Display for LineIdx {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        (self.0 + 1).fmt(f)
    }
}

/// Represents a column index.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
pub struct ColIdx(pub SrcOffset);

impl_math!(LineIdx, Add, add);
impl_math!(LineIdx, Sub, sub);
impl_math!(ColIdx, Add, add);
impl_math!(ColIdx, Sub, sub);

/// Location within one file specified by line and column.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Loc {
    pub line: LineIdx,
    pub col: ColIdx,
}

// --- tests ---
#[test]
fn basic_spans() {
    use super::Span;

    let s = Span::new(BytePos(3), BytePos(10));
    assert_eq!(s, Span { lo: BytePos(3), hi: BytePos(10) });
    assert_eq!(s, Span::from_pair((BytePos(3), BytePos(10))));
    assert_eq!(s.len(), 7);
    assert!(!s.is_dummy());

    assert!(s.contains(Span::new(BytePos(4), BytePos(9))));
    assert!(s.contains(Span::new(BytePos(3), BytePos(10))));
    assert!(s.contains(Span::new(BytePos(5), BytePos(10))));
    assert!(s.contains(Span::new(BytePos(3), BytePos(8))));
    assert!(!s.contains(Span::new(BytePos(2), BytePos(8))));
    assert!(!s.contains(Span::new(BytePos(3), BytePos(11))));
    assert!(!s.contains(Span::new(BytePos(1), BytePos(12))));
    assert!(!s.contains(Span::dummy()));

    assert_eq!(Span::single(BytePos(15)), Span::new(BytePos(15), BytePos(16)));
}

#[test]
fn dummy_spans() {
    use super::Span;

    let d = Span::dummy();
    assert_eq!(d, Span::dummy());
    assert_eq!(d.len(), 0);
    assert!(d.is_dummy());

    assert!(!d.contains(Span::new(BytePos(4), BytePos(9))));
    assert!(!d.contains(Span::new(BytePos(3), BytePos(0))));
    assert!(!d.contains(Span::dummy()));
}

#[test]
fn span_hulls() {
    use super::Span;

    let d = Span::dummy();
    let a = Span::new(BytePos(1), BytePos(5));
    let b = Span::new(BytePos(3), BytePos(7));
    let c = Span::new(BytePos(7), BytePos(9));

    assert_eq!(a.hull(&d), a);
    assert_eq!(d.hull(&a), a);
    assert_eq!(d.hull(&d), d);

    assert_eq!(a.hull(&b), Span::new(BytePos(1), BytePos(7)));
    assert_eq!(a.hull(&c), Span::new(BytePos(1), BytePos(9)));
    assert_eq!(b.hull(&c), Span::new(BytePos(3), BytePos(9)));
}
<commit_msg>Add custom `Debug` impl to `Span` to increase readability<commit_after>//! Types and functions dealing with positions within the source code
//!

use std::ops::{Add, Sub};
use std::cmp::{min, max};
use std::fmt;

// Helps implementing basic operators, like `Add` and `Sub`
macro_rules! impl_math {
    ($ty_name:ident, $trait_name:ident, $fun_name:ident) => {
        impl $trait_name for $ty_name {
            type Output = $ty_name;

            fn $fun_name(self, rhs: $ty_name) -> $ty_name {
                $ty_name($trait_name::$fun_name(self.0, rhs.0))
            }
        }
    }
}

// ----------------------------------------------------------------------------
/// Type do index one byte in a source code. It should be rather small, since
/// it's used a lot.
pub type SrcOffset = u32;

/// Position within source specified by byte offset. This is not equal to
/// `CharPos` thanks to UTF-8 and multibyte chars. This type always represents
/// positions relative to the whole codemap.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
pub struct BytePos(pub SrcOffset);

impl_math!(BytePos, Add, add);
impl_math!(BytePos, Sub, sub);

// ----------------------------------------------------------------------------
/// A region within the source specified by first and last byte offset. `lo`
/// byte is included in the span, `hi` byte is excluded.
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct Span {
    /// Low byte, inclusive
    pub lo: BytePos,
    /// High byte, exclusive
    pub hi: BytePos,
}

impl Span {
    /// Creates a span that points to a single char
    pub fn single(pos: BytePos) -> Span {
        Span { lo: pos, hi: pos + BytePos(1) }
    }

    /// Creates a span from a lo and hi (shorter than struct constructor
    /// syntax)
    pub fn new(lo: BytePos, hi: BytePos) -> Span {
        Span { lo: lo, hi: hi }
    }

    /// Creates a span from a tuple
    pub fn from_pair((lo, hi): (BytePos, BytePos)) -> Span {
        Span { lo: lo, hi: hi }
    }

    /// Creates a dummy span. Should be used with caution.
    pub fn dummy() -> Span {
        Span { lo: BytePos(1), hi: BytePos(0) }
    }

    /// Checks if the this span is a dummy span
    pub fn is_dummy(&self) -> bool {
        self.lo.0 == 1 && self.hi.0 == 0
    }

    /// Returns the length (number of bytes) of the span or 0 if it's a dummy
    /// span
    pub fn len(&self) -> SrcOffset {
        if self.is_dummy() {
            0
        } else {
            (self.hi - self.lo).0
        }
    }

    /// Returns the smallest span which encloses both given spans
    ///
    /// If one of given spans is a dummy span, it is ignored and the other span
    /// is returned. If both spans are dummy spans, a dummy span is returned.
    pub fn hull(&self, other: &Self) -> Span {
        if self.is_dummy() {
            *other
        } else if other.is_dummy() {
            *self
        } else {
            Span {
                lo: min(self.lo, other.lo),
                hi: max(self.hi, other.hi),
            }
        }
    }

    /// Checks if this span contains another span. A dummy span never contains
    /// any other span and is never contained in another span.
    pub fn contains(&self, other: Self) -> bool {
        !self.is_dummy()
            && !other.is_dummy()
            && self.lo <= other.lo
            && self.hi >= other.hi
    }
}

// custom `Debug` impl to shorten debug output and improve readability
impl fmt::Debug for Span {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "@({}, {})", self.lo.0, self.hi.0)
    }
}

// ----------------------------------------------------------------------------
/// Represents a line index.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
pub struct LineIdx(pub SrcOffset);

impl ::std::fmt::Display for LineIdx {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        (self.0 + 1).fmt(f)
    }
}

/// Represents a column index.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
pub struct ColIdx(pub SrcOffset);

impl_math!(LineIdx, Add, add);
impl_math!(LineIdx, Sub, sub);
impl_math!(ColIdx, Add, add);
impl_math!(ColIdx, Sub, sub);

/// Location within one file specified by line and column.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Loc {
    pub line: LineIdx,
    pub col: ColIdx,
}

// --- tests ---
#[test]
fn basic_spans() {
    use super::Span;

    let s = Span::new(BytePos(3), BytePos(10));
    assert_eq!(s, Span { lo: BytePos(3), hi: BytePos(10) });
    assert_eq!(s, Span::from_pair((BytePos(3), BytePos(10))));
    assert_eq!(s.len(), 7);
    assert!(!s.is_dummy());

    assert!(s.contains(Span::new(BytePos(4), BytePos(9))));
    assert!(s.contains(Span::new(BytePos(3), BytePos(10))));
    assert!(s.contains(Span::new(BytePos(5), BytePos(10))));
    assert!(s.contains(Span::new(BytePos(3), BytePos(8))));
    assert!(!s.contains(Span::new(BytePos(2), BytePos(8))));
    assert!(!s.contains(Span::new(BytePos(3), BytePos(11))));
    assert!(!s.contains(Span::new(BytePos(1), BytePos(12))));
    assert!(!s.contains(Span::dummy()));

    assert_eq!(Span::single(BytePos(15)), Span::new(BytePos(15), BytePos(16)));
}

#[test]
fn dummy_spans() {
    use super::Span;

    let d = Span::dummy();
    assert_eq!(d, Span::dummy());
    assert_eq!(d.len(), 0);
    assert!(d.is_dummy());

    assert!(!d.contains(Span::new(BytePos(4), BytePos(9))));
    assert!(!d.contains(Span::new(BytePos(3), BytePos(0))));
    assert!(!d.contains(Span::dummy()));
}

#[test]
fn span_hulls() {
    use super::Span;

    let d = Span::dummy();
    let a = Span::new(BytePos(1), BytePos(5));
    let b = Span::new(BytePos(3), BytePos(7));
    let c = Span::new(BytePos(7), BytePos(9));

    assert_eq!(a.hull(&d), a);
    assert_eq!(d.hull(&a), a);
    assert_eq!(d.hull(&d), d);

    assert_eq!(a.hull(&b), Span::new(BytePos(1), BytePos(7)));
    assert_eq!(a.hull(&c), Span::new(BytePos(1), BytePos(9)));
    assert_eq!(b.hull(&c), Span::new(BytePos(3), BytePos(9)));
}
<|endoftext|>


<commit_before>
use std::num::Float;
use sdl::video::{Surface};
use sdl::event::{Key};

use map::{Map};
use math::{LineSeg, Vec2, Mat3};
use input::{InputState};
use math;

pub struct Game<'a> {
    pub pos: Vec2,
    pub face_angle: f32,
    pub map: &'a Map,
    pub show_map: bool,
}

const SPEED: f32 = 0.4;
const TURN: f32 = 0.03;
const FOV_DIV: f32 = 500.0;
const WALL: f32 = 3000.0;

impl<'a> Game<'a> {

    pub fn step(&mut self, input: &InputState) {
        if input.has_key(Key::Left) {
            self.face_angle -= TURN;
        }
        if input.has_key(Key::Right) {
            self.face_angle += TURN;
        }
        if input.has_key(Key::W) {
            self.pos.x += SPEED*Float::sin(self.face_angle);
            self.pos.y -= SPEED*Float::cos(self.face_angle);
        }
        if input.has_key(Key::S) {
            self.pos.x -= SPEED*Float::sin(self.face_angle);
            self.pos.y += SPEED*Float::cos(self.face_angle);
        }
        if input.has_key(Key::A) {
            self.pos.x -= SPEED*Float::cos(self.face_angle);
            self.pos.y -= SPEED*Float::sin(self.face_angle);
        }
        if input.has_key(Key::D) {
            self.pos.x += SPEED*Float::cos(self.face_angle);
            self.pos.y += SPEED*Float::sin(self.face_angle);
        }
        self.show_map = input.has_key(Key::Tab);
    }

    pub fn render(&self, surf: &Surface) {
        if self.show_map {
            self.render_lines(&surf);
        } else {
            self.render_cast(&surf);
        }
    }

    fn render_lines(&self, surf: &Surface) {
        let trans = Mat3::rotation(-self.face_angle)
                  * Mat3::translation(-self.pos);

        surf.clear();
        for wall in self.map.walls.iter() {
            draw_seg(&surf, wall.transform(trans), 0xFF, 0x00, 0x00);
        }

        let w = surf.get_width() as usize;
        for x in 0..w {
            let offset = ((x as f32) - (w as f32) / 2.0) / FOV_DIV;
            let (q1,q2) = self.cast_ray(offset);
            match q1 {
                Some(_) => {
                    let draw_sg = LineSeg::new(self.pos.x, self.pos.y, q2.x, q2.y);
                    draw_seg(&surf, draw_sg.transform(trans), 0x00, 0xFF, 0x00);
                }
                None => {}
            }
        }
    }

    fn render_cast(&self, surf: &Surface) {
        let w = surf.get_width() as usize;
        let h = surf.get_height() as usize;

        surf.clear();
        surf.with_lock(|pixels| {
            for x in 0..w {
                let offset = ((x as f32) - (w as f32) / 2.0) / FOV_DIV;
                let (q1,_) = self.cast_ray(offset);
                match q1 {
                    Some(dist) => {
                        let ray_height = (WALL / dist) as usize;
                        let top = if h > ray_height { (h - ray_height) / 2 } else { 0 };
                        let bottom = h - top;
                        let proto_color = 0xFF-(h/2) + ray_height/2;
                        let color = if proto_color > 0xFF { 0xFF } else { proto_color as u8 };
                        for y in 0..top {
                            put_px(pixels, w, x, y, 0, 0x66, 0xFF);
                        }
                        for y in top..bottom {
                            put_px(pixels, w, x, y, color, 0, 0);
                        }
                        for y in bottom..h {
                            put_px(pixels, w, x, y, 0, 0xBB, 0);
                        }
                    }
                    None => {
                        for y in 0..(h/2) {
                            put_px(pixels, w, x, y, 0, 0x66, 0xFF);
                        }
                        for y in (h/2)..h {
                            put_px(pixels, w, x, y, 0, 0xBB, 0);
                        }
                    }
                }
            }
            true
        });
    }

    fn cast_ray(&self, offset: f32) -> (Option<f32>, Vec2) {
        let ray = LineSeg::new(
            self.pos.x,
            self.pos.y,
            self.pos.x + 1000.0*Float::sin(self.face_angle + offset),
            self.pos.y - 1000.0*Float::cos(self.face_angle + offset)
        );

        let mut shortest: Option<f32> = None;
        let mut vv: Vec2 = math::V2_ORIGIN;

        for wall in self.map.walls.iter() {
            match ray.intersects_at(*wall) {
                Some(t) => {
                    let dist = (wall.at(t) - self.pos).get_length() * Float::cos(offset);
                    shortest = match shortest {
                        Some(d) => { if dist < d { vv = wall.at(t); Some(dist) } else { shortest } }
                        None    => { vv = wall.at(t); Some(dist) }
                    }
                }
                None => {}
            };
        }

        (shortest, vv)
    }
}

fn put_px(pixels: &mut [u8], w: usize, x: usize, y: usize, r: u8, g: u8, b: u8) {
    pixels[3*(w*y+x) + 0] = b;
    pixels[3*(w*y+x) + 1] = g;
    pixels[3*(w*y+x) + 2] = r;
}

fn draw_seg(surf: &Surface, seg: LineSeg, r: u8, g: u8, b: u8) {
    let w = surf.get_width() as usize;
    let h = surf.get_height() as usize;
    let len = seg.get_length();

    surf.with_lock(|pixels| {
        for t in 0..(len as usize) {
            let pt = seg.at(t as f32 / len);
            let ux = (pt.x + (w/2) as f32) as usize;
            let uy = (pt.y + (h/2) as f32) as usize;

            if ux < w && uy < h {
                put_px(pixels, w, ux, uy, r, g, b);
            }
        };
        true
    });
}
<commit_msg>cast_ray functional style<commit_after>
use std::num::Float;
use sdl::video::{Surface};
use sdl::event::{Key};

use map::{Map};
use math::{LineSeg, Vec2, Mat3};
use input::{InputState};
use math;

pub struct Game<'a> {
    pub pos: Vec2,
    pub face_angle: f32,
    pub map: &'a Map,
    pub show_map: bool,
}

const SPEED: f32 = 0.4;
const TURN: f32 = 0.03;
const FOV_DIV: f32 = 500.0;
const WALL: f32 = 3000.0;

impl<'a> Game<'a> {

    pub fn step(&mut self, input: &InputState) {
        if input.has_key(Key::Left) {
            self.face_angle -= TURN;
        }
        if input.has_key(Key::Right) {
            self.face_angle += TURN;
        }
        if input.has_key(Key::W) {
            self.pos.x += SPEED*Float::sin(self.face_angle);
            self.pos.y -= SPEED*Float::cos(self.face_angle);
        }
        if input.has_key(Key::S) {
            self.pos.x -= SPEED*Float::sin(self.face_angle);
            self.pos.y += SPEED*Float::cos(self.face_angle);
        }
        if input.has_key(Key::A) {
            self.pos.x -= SPEED*Float::cos(self.face_angle);
            self.pos.y -= SPEED*Float::sin(self.face_angle);
        }
        if input.has_key(Key::D) {
            self.pos.x += SPEED*Float::cos(self.face_angle);
            self.pos.y += SPEED*Float::sin(self.face_angle);
        }
        self.show_map = input.has_key(Key::Tab);
    }

    pub fn render(&self, surf: &Surface) {
        if self.show_map {
            self.render_lines(&surf);
        } else {
            self.render_cast(&surf);
        }
    }

    fn render_lines(&self, surf: &Surface) {
        let trans = Mat3::rotation(-self.face_angle)
                  * Mat3::translation(-self.pos);

        surf.clear();
        for wall in self.map.walls.iter() {
            draw_seg(&surf, wall.transform(trans), 0xFF, 0x00, 0x00);
        }

        let w = surf.get_width() as usize;
        for x in 0..w {
            let offset = ((x as f32) - (w as f32) / 2.0) / FOV_DIV;
            let (q1,q2) = self.cast_ray(offset);
            match q1 {
                Some(_) => {
                    let draw_sg = LineSeg::new(self.pos.x, self.pos.y, q2.x, q2.y);
                    draw_seg(&surf, draw_sg.transform(trans), 0x00, 0xFF, 0x00);
                }
                None => {}
            }
        }
    }

    fn render_cast(&self, surf: &Surface) {
        let w = surf.get_width() as usize;
        let h = surf.get_height() as usize;

        surf.clear();
        surf.with_lock(|pixels| {
            for x in 0..w {
                let offset = ((x as f32) - (w as f32) / 2.0) / FOV_DIV;
                let (q1,_) = self.cast_ray(offset);
                match q1 {
                    Some(dist) => {
                        let ray_height = (WALL / dist) as usize;
                        let top = if h > ray_height { (h - ray_height) / 2 } else { 0 };
                        let bottom = h - top;
                        let proto_color = 0xFF-(h/2) + ray_height/2;
                        let color = if proto_color > 0xFF { 0xFF } else { proto_color as u8 };
                        for y in 0..top {
                            put_px(pixels, w, x, y, 0, 0x66, 0xFF);
                        }
                        for y in top..bottom {
                            put_px(pixels, w, x, y, color, 0, 0);
                        }
                        for y in bottom..h {
                            put_px(pixels, w, x, y, 0, 0xBB, 0);
                        }
                    }
                    None => {
                        for y in 0..(h/2) {
                            put_px(pixels, w, x, y, 0, 0x66, 0xFF);
                        }
                        for y in (h/2)..h {
                            put_px(pixels, w, x, y, 0, 0xBB, 0);
                        }
                    }
                }
            }
            true
        });
    }

    fn cast_ray(&self, offset: f32) -> (Option<f32>, Vec2) {
        let ray = LineSeg::new(
            self.pos.x,
            self.pos.y,
            self.pos.x + 1000.0*Float::sin(self.face_angle + offset),
            self.pos.y - 1000.0*Float::cos(self.face_angle + offset)
        );

        let cos_offset = Float::cos(offset);

        let (dist,pos) = self.map.walls.iter()
            .filter_map(|&wall| ray.intersects_at(wall).map(|t| wall.at(t)))
            .map(|int| ((int - self.pos).get_length() * cos_offset, int))
            .fold((Float::max_value(), math::V2_ORIGIN), |(shortest, _), (dist, pos)| {
                (if dist < shortest { dist } else { shortest }, pos)
            });

        if dist < 1.0e5 {
            (Some(dist), pos)
        } else {
            (None, math::V2_ORIGIN)
        }
    }
}

fn put_px(pixels: &mut [u8], w: usize, x: usize, y: usize, r: u8, g: u8, b: u8) {
    pixels[3*(w*y+x) + 0] = b;
    pixels[3*(w*y+x) + 1] = g;
    pixels[3*(w*y+x) + 2] = r;
}

fn draw_seg(surf: &Surface, seg: LineSeg, r: u8, g: u8, b: u8) {
    let w = surf.get_width() as usize;
    let h = surf.get_height() as usize;
    let len = seg.get_length();

    surf.with_lock(|pixels| {
        for t in 0..(len as usize) {
            let pt = seg.at(t as f32 / len);
            let ux = (pt.x + (w/2) as f32) as usize;
            let uy = (pt.y + (h/2) as f32) as usize;

            if ux < w && uy < h {
                put_px(pixels, w, ux, uy, r, g, b);
            }
        };
        true
    });
}
<|endoftext|>


<commit_before>use cranelift_module::*;
use crate::prelude::*;
use rustc::mir::interpret::{
    read_target_uint, AllocId, AllocType, Allocation, ConstValue, EvalResult, GlobalId,
};
use rustc::ty::Const;
use rustc_mir::interpret::{CompileTimeEvaluator, EvalContext, Memory, MemoryKind};
use syntax::ast::Mutability as AstMutability;

#[derive(Default)]
pub struct ConstantCx {
    todo: HashSet<TodoItem>,
    done: HashSet<DataId>,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
enum TodoItem {
    Alloc(AllocId),
    Static(DefId),
}

impl ConstantCx {
    pub fn finalize<'a, 'tcx: 'a, B: Backend>(
        mut self,
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        module: &mut Module<B>,
    ) {
        //println!("todo {:?}", self.todo);
        define_all_allocs(tcx, module, &mut self);
        //println!("done {:?}", self.done);
        for data_id in self.done.drain() {
            module.finalize_data(data_id);
        }
    }
}

pub fn codegen_static<'a, 'tcx: 'a>(ccx: &mut ConstantCx, def_id: DefId) {
    ccx.todo.insert(TodoItem::Static(def_id));
}

pub fn codegen_static_ref<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    static_: &Static<'tcx>,
) -> CPlace<'tcx> {
    let data_id = data_id_for_static(fx.tcx, fx.module, static_.def_id);
    cplace_for_dataid(fx, static_.ty, data_id)
}

pub fn trans_promoted<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    promoted: Promoted,
) -> CPlace<'tcx> {
    let const_ = fx
        .tcx
        .const_eval(ParamEnv::reveal_all().and(GlobalId {
            instance: fx.instance,
            promoted: Some(promoted),
        })).unwrap();

    let const_ = force_eval_const(fx, const_);
    trans_const_place(fx, const_)
}

pub fn trans_constant<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    constant: &Constant<'tcx>,
) -> CValue<'tcx> {
    let const_ = fx.monomorphize(&constant.literal);
    let const_ = force_eval_const(fx, const_);
    trans_const_value(fx, const_)
}

fn force_eval_const<'a, 'tcx: 'a>(
    fx: &FunctionCx<'a, 'tcx, impl Backend>,
    const_: &'tcx Const<'tcx>,
) -> &'tcx Const<'tcx> {
    match const_.val {
        ConstValue::Unevaluated(def_id, ref substs) => {
            let param_env = ParamEnv::reveal_all();
            let instance = Instance::resolve(fx.tcx, param_env, def_id, substs).unwrap();
            let cid = GlobalId {
                instance,
                promoted: None,
            };
            fx.tcx.const_eval(param_env.and(cid)).unwrap()
        }
        _ => const_,
    }
}

fn trans_const_value<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    const_: &'tcx Const<'tcx>,
) -> CValue<'tcx> {
    let ty = fx.monomorphize(&const_.ty);
    let layout = fx.layout_of(ty);
    match ty.sty {
        ty::Bool => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as u64 as i64)
        }
        ty::Uint(_) => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as u64 as i64)
        }
        ty::Int(_) => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as i128 as i64)
        }
        ty::FnDef(def_id, substs) => {
            let func_ref = fx.get_function_ref(
                Instance::resolve(fx.tcx, ParamEnv::reveal_all(), def_id, substs).unwrap(),
            );
            let func_addr = fx.bcx.ins().func_addr(fx.module.pointer_type(), func_ref);
            CValue::ByVal(func_addr, layout)
        }
        _ => trans_const_place(fx, const_).to_cvalue(fx),
    }
}

fn trans_const_place<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    const_: &'tcx Const<'tcx>,
) -> CPlace<'tcx> {
    // Adapted from https://github.com/rust-lang/rust/pull/53671/files#diff-e0b58bb6712edaa8595ad7237542c958L551
    let result = || -> EvalResult<'tcx, &'tcx Allocation> {
        let mut ecx = EvalContext::new(
            fx.tcx.at(DUMMY_SP),
            ty::ParamEnv::reveal_all(),
            CompileTimeEvaluator,
            (),
        );
        let op = ecx.const_to_op(const_)?;
        let ptr = ecx.allocate(op.layout, MemoryKind::Stack)?;
        ecx.copy_op(op, ptr.into())?;
        let alloc = ecx.memory.get(ptr.to_ptr()?.alloc_id)?;
        Ok(fx.tcx.intern_const_alloc(alloc.clone()))
    };
    let alloc = result().expect("unable to convert ConstValue to Allocation");

    //println!("const value: {:?} allocation: {:?}", value, alloc);
    let alloc_id = fx.tcx.alloc_map.lock().allocate(alloc);
    fx.constants.todo.insert(TodoItem::Alloc(alloc_id));
    let data_id = data_id_for_alloc_id(fx.module, alloc_id);
    cplace_for_dataid(fx, const_.ty, data_id)
}

fn data_id_for_alloc_id<B: Backend>(module: &mut Module<B>, alloc_id: AllocId) -> DataId {
    module
        .declare_data(&alloc_id.0.to_string(), Linkage::Local, false)
        .unwrap()
}

fn data_id_for_static<'a, 'tcx: 'a, B: Backend>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<B>,
    def_id: DefId,
) -> DataId {
    let symbol_name = tcx.symbol_name(Instance::mono(tcx, def_id)).as_str();
    let is_mutable = if let ::rustc::hir::Mutability::MutMutable = tcx.is_static(def_id).unwrap() {
        true
    } else {
        !tcx.type_of(def_id)
            .is_freeze(tcx, ParamEnv::reveal_all(), DUMMY_SP)
    };
    module
        .declare_data(&*symbol_name, Linkage::Export, is_mutable)
        .unwrap()
}

fn cplace_for_dataid<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    ty: Ty<'tcx>,
    data_id: DataId,
) -> CPlace<'tcx> {
    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
    let global_ptr = fx
        .bcx
        .ins()
        .global_value(fx.module.pointer_type(), local_data_id);
    let layout = fx.layout_of(fx.monomorphize(&ty));
    assert!(!layout.is_unsized(), "unsized statics aren't supported");
    CPlace::Addr(global_ptr, None, layout)
}

fn define_all_allocs<'a, 'tcx: 'a, B: Backend + 'a>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<B>,
    cx: &mut ConstantCx,
) {
    let memory = Memory::<CompileTimeEvaluator>::new(tcx.at(DUMMY_SP), ());

    while let Some(todo_item) = pop_set(&mut cx.todo) {
        let (data_id, alloc) = match todo_item {
            TodoItem::Alloc(alloc_id) => {
                //println!("alloc_id {}", alloc_id);
                let data_id = data_id_for_alloc_id(module, alloc_id);
                let alloc = memory.get(alloc_id).unwrap();
                (data_id, alloc)
            }
            TodoItem::Static(def_id) => {
                //println!("static {:?}", def_id);
                let instance = ty::Instance::mono(tcx, def_id);
                let cid = GlobalId {
                    instance,
                    promoted: None,
                };
                let const_ = tcx.const_eval(ParamEnv::reveal_all().and(cid)).unwrap();

                let alloc = match const_.val {
                    ConstValue::ByRef(_alloc_id, alloc, n) if n.bytes() == 0 => alloc,
                    _ => bug!("static const eval returned {:#?}", const_),
                };

                let data_id = data_id_for_static(tcx, module, def_id);
                (data_id, alloc)
            }
        };

        //("data_id {}", data_id);
        if cx.done.contains(&data_id) {
            continue;
        }

        let mut data_ctx = DataContext::new();

        data_ctx.define(
            alloc.bytes.to_vec().into_boxed_slice(),
            match alloc.mutability {
                AstMutability::Mutable => Writability::Writable,
                AstMutability::Immutable => Writability::Readonly,
            },
        );

        for &(offset, reloc) in alloc.relocations.iter() {
            let data_id = match tcx.alloc_map.lock().get(reloc).unwrap() {
                AllocType::Memory(_) => {
                    cx.todo.insert(TodoItem::Alloc(reloc));
                    data_id_for_alloc_id(module, reloc)
                }
                AllocType::Function(_) => unimplemented!("function static reference"),
                AllocType::Static(def_id) => {
                    cx.todo.insert(TodoItem::Static(def_id));
                    data_id_for_static(tcx, module, def_id)
                }
            };

            let reloc_offset = {
                let endianness = memory.endianness();
                let offset = offset.bytes() as usize;
                let ptr_size = tcx.data_layout.pointer_size;
                let bytes = &alloc.bytes[offset..offset + ptr_size.bytes() as usize];
                read_target_uint(endianness, bytes).unwrap()
            };

            let global_value = module.declare_data_in_data(data_id, &mut data_ctx);
            data_ctx.write_data_addr(reloc_offset as u32, global_value, 0);
        }

        module.define_data(data_id, &data_ctx).unwrap();
        cx.done.insert(data_id);
    }

    assert!(cx.todo.is_empty(), "{:?}", cx.todo);
}

fn pop_set<T: Copy + Eq + ::std::hash::Hash>(set: &mut HashSet<T>) -> Option<T> {
    if let Some(elem) = set.iter().next().map(|elem| *elem) {
        set.remove(&elem);
        Some(elem)
    } else {
        None
    }
}
<commit_msg>Rustup to rustc 1.30.0-nightly (28bcffead 2018-09-01)<commit_after>use cranelift_module::*;
use crate::prelude::*;
use rustc::mir::interpret::{
    read_target_uint, AllocId, AllocType, Allocation, ConstValue, EvalResult, GlobalId,
};
use rustc::ty::Const;
use rustc_mir::interpret::{CompileTimeEvaluator, EvalContext, Memory, MemoryKind};
use syntax::ast::Mutability as AstMutability;

#[derive(Default)]
pub struct ConstantCx {
    todo: HashSet<TodoItem>,
    done: HashSet<DataId>,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
enum TodoItem {
    Alloc(AllocId),
    Static(DefId),
}

impl ConstantCx {
    pub fn finalize<'a, 'tcx: 'a, B: Backend>(
        mut self,
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        module: &mut Module<B>,
    ) {
        //println!("todo {:?}", self.todo);
        define_all_allocs(tcx, module, &mut self);
        //println!("done {:?}", self.done);
        for data_id in self.done.drain() {
            module.finalize_data(data_id);
        }
    }
}

pub fn codegen_static<'a, 'tcx: 'a>(ccx: &mut ConstantCx, def_id: DefId) {
    ccx.todo.insert(TodoItem::Static(def_id));
}

pub fn codegen_static_ref<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    static_: &Static<'tcx>,
) -> CPlace<'tcx> {
    let data_id = data_id_for_static(fx.tcx, fx.module, static_.def_id);
    cplace_for_dataid(fx, static_.ty, data_id)
}

pub fn trans_promoted<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    promoted: Promoted,
) -> CPlace<'tcx> {
    let const_ = fx
        .tcx
        .const_eval(ParamEnv::reveal_all().and(GlobalId {
            instance: fx.instance,
            promoted: Some(promoted),
        })).unwrap();

    let const_ = force_eval_const(fx, const_);
    trans_const_place(fx, const_)
}

pub fn trans_constant<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    constant: &Constant<'tcx>,
) -> CValue<'tcx> {
    let const_ = fx.monomorphize(&constant.literal);
    let const_ = force_eval_const(fx, const_);
    trans_const_value(fx, const_)
}

fn force_eval_const<'a, 'tcx: 'a>(
    fx: &FunctionCx<'a, 'tcx, impl Backend>,
    const_: &'tcx Const<'tcx>,
) -> &'tcx Const<'tcx> {
    match const_.val {
        ConstValue::Unevaluated(def_id, ref substs) => {
            let param_env = ParamEnv::reveal_all();
            let instance = Instance::resolve(fx.tcx, param_env, def_id, substs).unwrap();
            let cid = GlobalId {
                instance,
                promoted: None,
            };
            fx.tcx.const_eval(param_env.and(cid)).unwrap()
        }
        _ => const_,
    }
}

fn trans_const_value<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    const_: &'tcx Const<'tcx>,
) -> CValue<'tcx> {
    let ty = fx.monomorphize(&const_.ty);
    let layout = fx.layout_of(ty);
    match ty.sty {
        ty::Bool => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as u64 as i64)
        }
        ty::Uint(_) => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as u64 as i64)
        }
        ty::Int(_) => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as i128 as i64)
        }
        ty::FnDef(def_id, substs) => {
            let func_ref = fx.get_function_ref(
                Instance::resolve(fx.tcx, ParamEnv::reveal_all(), def_id, substs).unwrap(),
            );
            let func_addr = fx.bcx.ins().func_addr(fx.module.pointer_type(), func_ref);
            CValue::ByVal(func_addr, layout)
        }
        _ => trans_const_place(fx, const_).to_cvalue(fx),
    }
}

fn trans_const_place<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    const_: &'tcx Const<'tcx>,
) -> CPlace<'tcx> {
    // Adapted from https://github.com/rust-lang/rust/pull/53671/files#diff-e0b58bb6712edaa8595ad7237542c958L551
    let result = || -> EvalResult<'tcx, &'tcx Allocation> {
        let mut ecx = EvalContext::new(
            fx.tcx.at(DUMMY_SP),
            ty::ParamEnv::reveal_all(),
            CompileTimeEvaluator,
            (),
        );
        let op = ecx.const_to_op(const_)?;
        let ptr = ecx.allocate(op.layout, MemoryKind::Stack)?;
        ecx.copy_op(op, ptr.into())?;
        let alloc = ecx.memory.get(ptr.to_ptr()?.alloc_id)?;
        Ok(fx.tcx.intern_const_alloc(alloc.clone()))
    };
    let alloc = result().expect("unable to convert ConstValue to Allocation");

    //println!("const value: {:?} allocation: {:?}", value, alloc);
    let alloc_id = fx.tcx.alloc_map.lock().allocate(alloc);
    fx.constants.todo.insert(TodoItem::Alloc(alloc_id));
    let data_id = data_id_for_alloc_id(fx.module, alloc_id);
    cplace_for_dataid(fx, const_.ty, data_id)
}

fn data_id_for_alloc_id<B: Backend>(module: &mut Module<B>, alloc_id: AllocId) -> DataId {
    module
        .declare_data(&alloc_id.0.to_string(), Linkage::Local, false)
        .unwrap()
}

fn data_id_for_static<'a, 'tcx: 'a, B: Backend>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<B>,
    def_id: DefId,
) -> DataId {
    let symbol_name = tcx.symbol_name(Instance::mono(tcx, def_id)).as_str();
    let is_mutable = if let ::rustc::hir::Mutability::MutMutable = tcx.is_static(def_id).unwrap() {
        true
    } else {
        !tcx.type_of(def_id)
            .is_freeze(tcx, ParamEnv::reveal_all(), DUMMY_SP)
    };
    module
        .declare_data(&*symbol_name, Linkage::Export, is_mutable)
        .unwrap()
}

fn cplace_for_dataid<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    ty: Ty<'tcx>,
    data_id: DataId,
) -> CPlace<'tcx> {
    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
    let global_ptr = fx
        .bcx
        .ins()
        .global_value(fx.module.pointer_type(), local_data_id);
    let layout = fx.layout_of(fx.monomorphize(&ty));
    assert!(!layout.is_unsized(), "unsized statics aren't supported");
    CPlace::Addr(global_ptr, None, layout)
}

fn define_all_allocs<'a, 'tcx: 'a, B: Backend + 'a>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<B>,
    cx: &mut ConstantCx,
) {
    let memory = Memory::<CompileTimeEvaluator>::new(tcx.at(DUMMY_SP), ());

    while let Some(todo_item) = pop_set(&mut cx.todo) {
        let (data_id, alloc) = match todo_item {
            TodoItem::Alloc(alloc_id) => {
                //println!("alloc_id {}", alloc_id);
                let data_id = data_id_for_alloc_id(module, alloc_id);
                let alloc = memory.get(alloc_id).unwrap();
                (data_id, alloc)
            }
            TodoItem::Static(def_id) => {
                //println!("static {:?}", def_id);
                let instance = ty::Instance::mono(tcx, def_id);
                let cid = GlobalId {
                    instance,
                    promoted: None,
                };
                let const_ = tcx.const_eval(ParamEnv::reveal_all().and(cid)).unwrap();

                let alloc = match const_.val {
                    ConstValue::ByRef(_alloc_id, alloc, n) if n.bytes() == 0 => alloc,
                    _ => bug!("static const eval returned {:#?}", const_),
                };

                let data_id = data_id_for_static(tcx, module, def_id);
                (data_id, alloc)
            }
        };

        //("data_id {}", data_id);
        if cx.done.contains(&data_id) {
            continue;
        }

        let mut data_ctx = DataContext::new();

        data_ctx.define(
            alloc.bytes.to_vec().into_boxed_slice(),
            match alloc.mutability {
                AstMutability::Mutable => Writability::Writable,
                AstMutability::Immutable => Writability::Readonly,
            },
        );

        for &(offset, reloc) in alloc.relocations.iter() {
            let data_id = match tcx.alloc_map.lock().get(reloc).unwrap() {
                AllocType::Memory(_) => {
                    cx.todo.insert(TodoItem::Alloc(reloc));
                    data_id_for_alloc_id(module, reloc)
                }
                AllocType::Function(_) => unimplemented!("function static reference"),
                AllocType::Static(def_id) => {
                    cx.todo.insert(TodoItem::Static(def_id));
                    data_id_for_static(tcx, module, def_id)
                }
            };

            let reloc_offset = {
                let endianness = tcx.data_layout.endian;
                let offset = offset.bytes() as usize;
                let ptr_size = tcx.data_layout.pointer_size;
                let bytes = &alloc.bytes[offset..offset + ptr_size.bytes() as usize];
                read_target_uint(endianness, bytes).unwrap()
            };

            let global_value = module.declare_data_in_data(data_id, &mut data_ctx);
            data_ctx.write_data_addr(reloc_offset as u32, global_value, 0);
        }

        module.define_data(data_id, &data_ctx).unwrap();
        cx.done.insert(data_id);
    }

    assert!(cx.todo.is_empty(), "{:?}", cx.todo);
}

fn pop_set<T: Copy + Eq + ::std::hash::Hash>(set: &mut HashSet<T>) -> Option<T> {
    if let Some(elem) = set.iter().next().map(|elem| *elem) {
        set.remove(&elem);
        Some(elem)
    } else {
        None
    }
}
<|endoftext|>


<commit_before>use crate::{
    executor::Executor, message::Delivery, types::ShortString, wait::NotifyReady, BasicProperties,
    Error,
};
use crossbeam_channel::{Receiver, Sender};
use log::trace;
use parking_lot::{Mutex, MutexGuard};
use std::{fmt, sync::Arc};

pub trait ConsumerDelegate: Send + Sync {
    fn on_new_delivery(&self, delivery: Delivery);
    fn drop_prefetched_messages(&self) {}
    fn on_canceled(&self) {}
    fn on_error(&self, _error: Error) {}
}

#[derive(Clone)]
pub struct Consumer {
    inner: Arc<Mutex<ConsumerInner>>,
}

impl Consumer {
    pub(crate) fn new(consumer_tag: ShortString, executor: Arc<dyn Executor>) -> Consumer {
        Consumer {
            inner: Arc::new(Mutex::new(ConsumerInner::new(consumer_tag, executor))),
        }
    }

    pub fn inner(&self) -> MutexGuard<'_, ConsumerInner> {
        self.inner.lock()
    }

    pub fn set_delegate(&self, delegate: Box<dyn ConsumerDelegate>) {
        let mut inner = self.inner();
        while let Some(delivery) = inner.next_delivery() {
            delegate.on_new_delivery(delivery);
        }
        inner.delegate = Some(Arc::new(Mutex::new(delegate)));
    }

    pub(crate) fn start_new_delivery(&mut self, delivery: Delivery) {
        self.inner().current_message = Some(delivery)
    }

    pub(crate) fn set_delivery_properties(&mut self, properties: BasicProperties) {
        if let Some(delivery) = self.inner().current_message.as_mut() {
            delivery.properties = properties;
        }
    }

    pub(crate) fn receive_delivery_content(&mut self, payload: Vec<u8>) {
        if let Some(delivery) = self.inner().current_message.as_mut() {
            delivery.receive_content(payload);
        }
    }

    pub(crate) fn new_delivery_complete(&mut self) -> Result<(), Error> {
        let mut inner = self.inner();
        if let Some(delivery) = inner.current_message.take() {
            inner.new_delivery(delivery)?;
        }
        Ok(())
    }

    pub(crate) fn drop_prefetched_messages(&self) -> Result<(), Error> {
        self.inner().drop_prefetched_messages()
    }

    pub(crate) fn cancel(&self) -> Result<(), Error> {
        self.inner().cancel()
    }

    pub(crate) fn set_error(&self, error: Error) -> Result<(), Error> {
        self.inner().set_error(error)
    }
}

pub struct ConsumerInner {
    current_message: Option<Delivery>,
    deliveries_in: Sender<Delivery>,
    deliveries_out: Receiver<Delivery>,
    task: Option<Box<dyn NotifyReady + Send>>,
    canceled: bool,
    tag: ShortString,
    delegate: Option<Arc<Mutex<Box<dyn ConsumerDelegate>>>>,
    executor: Arc<dyn Executor>,
    error: Option<Error>,
}

impl fmt::Debug for ConsumerInner {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "ConsumerInnder({})", self.tag)
    }
}

impl ConsumerInner {
    fn new(consumer_tag: ShortString, executor: Arc<dyn Executor>) -> Self {
        let (sender, receiver) = crossbeam_channel::unbounded();
        Self {
            current_message: None,
            deliveries_in: sender,
            deliveries_out: receiver,
            task: None,
            canceled: false,
            tag: consumer_tag,
            delegate: None,
            executor,
            error: None,
        }
    }

    pub fn next_delivery(&mut self) -> Option<Delivery> {
        self.deliveries_out.try_recv().ok()
    }

    pub fn set_task(&mut self, task: Box<dyn NotifyReady + Send>) {
        self.task = Some(task);
    }

    pub fn has_task(&self) -> bool {
        self.task.is_some()
    }

    pub fn canceled(&self) -> bool {
        self.canceled
    }

    pub fn error(&mut self) -> Option<Error> {
        self.error.take()
    }

    pub fn tag(&self) -> &ShortString {
        &self.tag
    }

    fn new_delivery(&mut self, delivery: Delivery) -> Result<(), Error> {
        trace!("new_delivery; consumer_tag={}", self.tag);
        if let Some(delegate) = self.delegate.as_ref() {
            let delegate = delegate.clone();
            self.executor
                .execute(Box::new(move || delegate.lock().on_new_delivery(delivery)))?;
        } else {
            self.deliveries_in
                .send(delivery)
                .expect("failed to send delivery to consumer");
        }
        if let Some(task) = self.task.as_ref() {
            task.notify();
        }
        Ok(())
    }

    fn drop_prefetched_messages(&mut self) -> Result<(), Error> {
        trace!("drop_prefetched_messages; consumer_tag={}", self.tag);
        if let Some(delegate) = self.delegate.as_ref() {
            let delegate = delegate.clone();
            self.executor
                .execute(Box::new(move || delegate.lock().drop_prefetched_messages()))?;
        }
        while let Some(_) = self.next_delivery() {}
        Ok(())
    }

    fn cancel(&mut self) -> Result<(), Error> {
        trace!("cancel; consumer_tag={}", self.tag);
        if let Some(delegate) = self.delegate.as_ref() {
            let delegate = delegate.clone();
            self.executor
                .execute(Box::new(move || delegate.lock().on_canceled()))?;
        }
        while let Some(_) = self.next_delivery() {}
        self.canceled = true;
        self.task.take();
        Ok(())
    }

    pub fn set_error(&mut self, error: Error) -> Result<(), Error> {
        trace!("set_error; consumer_tag={}", self.tag);
        if let Some(delegate) = self.delegate.as_ref() {
            let delegate = delegate.clone();
            self.executor
                .execute(Box::new(move || delegate.lock().on_error(error)))?;
        } else {
            self.error = Some(error);
        }
        self.cancel()
    }
}

impl fmt::Debug for Consumer {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Consumer({})", self.inner().tag())
    }
}

#[cfg(feature = "futures")]
mod futures {
    use super::*;

    use ::futures::stream::Stream;

    use std::{
        pin::Pin,
        task::{Context, Poll},
    };

    use crate::confirmation::futures::Watcher;

    impl Stream for Consumer {
        type Item = Result<Delivery, Error>;

        fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
            trace!("consumer poll; polling transport");
            let mut inner = self.inner();
            trace!(
                "consumer poll; acquired inner lock, consumer_tag={}",
                inner.tag()
            );
            if !inner.has_task() {
                inner.set_task(Box::new(Watcher(cx.waker().clone())));
            }
            if let Some(delivery) = inner.next_delivery() {
                trace!(
                    "delivery; consumer_tag={}, delivery_tag={:?}",
                    inner.tag(),
                    delivery.delivery_tag
                );
                Poll::Ready(Some(Ok(delivery)))
            } else if inner.canceled() {
                trace!("consumer canceled; consumer_tag={}", inner.tag());
                if let Some(error) = inner.error() {
                    Poll::Ready(Some(Err(error)))
                } else {
                    Poll::Ready(None)
                }
            } else {
                trace!("delivery; status=NotReady, consumer_tag={}", inner.tag());
                Poll::Pending
            }
        }
    }
}
<commit_msg>consumer: add Iterator<commit_after>use crate::{
    executor::Executor, message::Delivery, types::ShortString, wait::NotifyReady, BasicProperties,
    Error,
};
use crossbeam_channel::{Receiver, Sender};
use log::trace;
use parking_lot::{Mutex, MutexGuard};
use std::{fmt, sync::Arc};

pub trait ConsumerDelegate: Send + Sync {
    fn on_new_delivery(&self, delivery: Delivery);
    fn drop_prefetched_messages(&self) {}
    fn on_canceled(&self) {}
    fn on_error(&self, _error: Error) {}
}

#[derive(Clone)]
pub struct Consumer {
    inner: Arc<Mutex<ConsumerInner>>,
}

impl Consumer {
    pub(crate) fn new(consumer_tag: ShortString, executor: Arc<dyn Executor>) -> Consumer {
        Consumer {
            inner: Arc::new(Mutex::new(ConsumerInner::new(consumer_tag, executor))),
        }
    }

    pub fn inner(&self) -> MutexGuard<'_, ConsumerInner> {
        self.inner.lock()
    }

    pub fn set_delegate(&self, delegate: Box<dyn ConsumerDelegate>) {
        let mut inner = self.inner();
        while let Some(delivery) = inner.next_delivery() {
            delegate.on_new_delivery(delivery);
        }
        inner.delegate = Some(Arc::new(Mutex::new(delegate)));
    }

    pub(crate) fn start_new_delivery(&mut self, delivery: Delivery) {
        self.inner().current_message = Some(delivery)
    }

    pub(crate) fn set_delivery_properties(&mut self, properties: BasicProperties) {
        if let Some(delivery) = self.inner().current_message.as_mut() {
            delivery.properties = properties;
        }
    }

    pub(crate) fn receive_delivery_content(&mut self, payload: Vec<u8>) {
        if let Some(delivery) = self.inner().current_message.as_mut() {
            delivery.receive_content(payload);
        }
    }

    pub(crate) fn new_delivery_complete(&mut self) -> Result<(), Error> {
        let mut inner = self.inner();
        if let Some(delivery) = inner.current_message.take() {
            inner.new_delivery(delivery)?;
        }
        Ok(())
    }

    pub(crate) fn drop_prefetched_messages(&self) -> Result<(), Error> {
        self.inner().drop_prefetched_messages()
    }

    pub(crate) fn cancel(&self) -> Result<(), Error> {
        self.inner().cancel()
    }

    pub(crate) fn set_error(&self, error: Error) -> Result<(), Error> {
        self.inner().set_error(error)
    }
}

pub struct ConsumerInner {
    current_message: Option<Delivery>,
    deliveries_in: Sender<Delivery>,
    deliveries_out: Receiver<Delivery>,
    task: Option<Box<dyn NotifyReady + Send>>,
    canceled: bool,
    tag: ShortString,
    delegate: Option<Arc<Mutex<Box<dyn ConsumerDelegate>>>>,
    executor: Arc<dyn Executor>,
    error: Option<Error>,
}

pub struct ConsumerIterator {
    receiver: Receiver<Delivery>,
}

impl Iterator for ConsumerIterator {
    type Item = Delivery;

    fn next(&mut self) -> Option<Self::Item> {
        self.receiver.recv().ok()
    }
}

impl IntoIterator for Consumer {
    type Item = Delivery;
    type IntoIter = ConsumerIterator;

    fn into_iter(self) -> Self::IntoIter {
        ConsumerIterator {
            receiver: self.inner().deliveries_out.clone(),
        }
    }
}

impl fmt::Debug for ConsumerInner {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "ConsumerInnder({})", self.tag)
    }
}

impl ConsumerInner {
    fn new(consumer_tag: ShortString, executor: Arc<dyn Executor>) -> Self {
        let (sender, receiver) = crossbeam_channel::unbounded();
        Self {
            current_message: None,
            deliveries_in: sender,
            deliveries_out: receiver,
            task: None,
            canceled: false,
            tag: consumer_tag,
            delegate: None,
            executor,
            error: None,
        }
    }

    pub fn next_delivery(&mut self) -> Option<Delivery> {
        self.deliveries_out.try_recv().ok()
    }

    pub fn set_task(&mut self, task: Box<dyn NotifyReady + Send>) {
        self.task = Some(task);
    }

    pub fn has_task(&self) -> bool {
        self.task.is_some()
    }

    pub fn canceled(&self) -> bool {
        self.canceled
    }

    pub fn error(&mut self) -> Option<Error> {
        self.error.take()
    }

    pub fn tag(&self) -> &ShortString {
        &self.tag
    }

    fn new_delivery(&mut self, delivery: Delivery) -> Result<(), Error> {
        trace!("new_delivery; consumer_tag={}", self.tag);
        if let Some(delegate) = self.delegate.as_ref() {
            let delegate = delegate.clone();
            self.executor
                .execute(Box::new(move || delegate.lock().on_new_delivery(delivery)))?;
        } else {
            self.deliveries_in
                .send(delivery)
                .expect("failed to send delivery to consumer");
        }
        if let Some(task) = self.task.as_ref() {
            task.notify();
        }
        Ok(())
    }

    fn drop_prefetched_messages(&mut self) -> Result<(), Error> {
        trace!("drop_prefetched_messages; consumer_tag={}", self.tag);
        if let Some(delegate) = self.delegate.as_ref() {
            let delegate = delegate.clone();
            self.executor
                .execute(Box::new(move || delegate.lock().drop_prefetched_messages()))?;
        }
        while let Some(_) = self.next_delivery() {}
        Ok(())
    }

    fn cancel(&mut self) -> Result<(), Error> {
        trace!("cancel; consumer_tag={}", self.tag);
        if let Some(delegate) = self.delegate.as_ref() {
            let delegate = delegate.clone();
            self.executor
                .execute(Box::new(move || delegate.lock().on_canceled()))?;
        }
        while let Some(_) = self.next_delivery() {}
        self.canceled = true;
        self.task.take();
        Ok(())
    }

    pub fn set_error(&mut self, error: Error) -> Result<(), Error> {
        trace!("set_error; consumer_tag={}", self.tag);
        if let Some(delegate) = self.delegate.as_ref() {
            let delegate = delegate.clone();
            self.executor
                .execute(Box::new(move || delegate.lock().on_error(error)))?;
        } else {
            self.error = Some(error);
        }
        self.cancel()
    }
}

impl fmt::Debug for Consumer {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Consumer({})", self.inner().tag())
    }
}

#[cfg(feature = "futures")]
mod futures {
    use super::*;

    use ::futures::stream::Stream;

    use std::{
        pin::Pin,
        task::{Context, Poll},
    };

    use crate::confirmation::futures::Watcher;

    impl Stream for Consumer {
        type Item = Result<Delivery, Error>;

        fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
            trace!("consumer poll; polling transport");
            let mut inner = self.inner();
            trace!(
                "consumer poll; acquired inner lock, consumer_tag={}",
                inner.tag()
            );
            if !inner.has_task() {
                inner.set_task(Box::new(Watcher(cx.waker().clone())));
            }
            if let Some(delivery) = inner.next_delivery() {
                trace!(
                    "delivery; consumer_tag={}, delivery_tag={:?}",
                    inner.tag(),
                    delivery.delivery_tag
                );
                Poll::Ready(Some(Ok(delivery)))
            } else if inner.canceled() {
                trace!("consumer canceled; consumer_tag={}", inner.tag());
                if let Some(error) = inner.error() {
                    Poll::Ready(Some(Err(error)))
                } else {
                    Poll::Ready(None)
                }
            } else {
                trace!("delivery; status=NotReady, consumer_tag={}", inner.tag());
                Poll::Pending
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::intrinsics::{size_of, offset};
use std::iter::{Iterator, range_step};

extern {
    static kernel_end_symbol_table_entry: ();
    //static kernel_start_symbol_table_entry: ();
}

struct PhysicalAddress(u64);

struct FrameStack {
    first: *const PhysicalAddress,
    length: u32, //up to 16TB memory possible
}

const PAGE_SIZE: u64 = 4096;
const FRAME_STACK : *const FrameStack = (10*1024*1024 as uint) as *const FrameStack; //10MB

pub unsafe fn frame_stack(multiboot: *const ::multiboot::Information) {

    let kernel_end = (&kernel_end_symbol_table_entry as *const ()) as *const FrameStack;
    assert!(kernel_end < FRAME_STACK);

    let mut areas = (*multiboot).memory_areas().unwrap();
    let maximal_phys_addr = areas.clone().fold(0, |max, area| {
                if area.base_addr + area.length > max {
                    area.base_addr + area.length
                } else {max}
            });
    let free_phys_addr_start = (FRAME_STACK as u64) + size_of::<FrameStack>() as u64
         + maximal_phys_addr / PAGE_SIZE * size_of::<PhysicalAddress>() as u64;

    let mut stack = FrameStack {
        first: offset(FRAME_STACK, 1) as *const PhysicalAddress,
        length: 0,
    };

    for area in areas {
        for frame_addr in range_step(area.base_addr, area.base_addr + area.length, PAGE_SIZE) {
            if frame_addr > free_phys_addr_start {
                stack.push(PhysicalAddress(frame_addr))
            }
        }
    }
    *(FRAME_STACK as *mut FrameStack) = stack;
}

impl FrameStack {
    unsafe fn push(&mut self, frame: PhysicalAddress) {
        let last = offset(self.first, self.length as int);
        *(last as *mut PhysicalAddress) = frame;
        self.length += 1;
    }

}<commit_msg>rewrite init to work with new frame_stack<commit_after>extern crate "os_x86_64_frame_stack" as frame_stack;

use std::prelude::*;
use self::frame_stack::Frame;

extern {
    static kernel_end_symbol_table_entry: ();
    //static kernel_start_symbol_table_entry: ();
}

const PAGE_SIZE: u64 = 4096;

pub unsafe fn init_frame_stack(multiboot: *const ::multiboot::Information) {

    let kernel_end = &kernel_end_symbol_table_entry as *const () as u32;

    let stack_start_frame = Frame{number: kernel_end >> 12};

    // map frame stack to 2mb behind kernel
    map_p1_entries(0, 0, stack_start_frame);
    // map p1 entries
    for i in range(0, 512) {
        map_p1_entries(0, i, Frame{
            number: stack_start_frame.number + i,
        });
    }

    frame_stack::init();

    let mut areas = (*multiboot).memory_areas().unwrap();
    let number_of_frames = areas.clone().fold(0, |n, area| {n + area.length / PAGE_SIZE}) as u32;

    // for memory > 1GB we need more p1 tables
    let p1_tables_required = (frame_stack::max_size(number_of_frames) / 4096 / 512) as u32;
    let mut last_mapped_p1_table = 0;

    // the first free physical frame (the 512 frames after kernel are used)
    let first_free_frame = Frame{
        number: stack_start_frame.number + 512,
    };

    for area in areas {
        for frame in range(area.base_addr >> 12, (area.base_addr+area.length) >> 12).map(
            |frame_number| Frame{number: frame_number as u32}) {
            if frame >= first_free_frame {
                if last_mapped_p1_table < p1_tables_required {
                    // add as p1 table
                    last_mapped_p1_table += 1;
                    map_to_p1_table(last_mapped_p1_table, frame);
                    // map p1 entries
                    for i in range(0, 512) {
                        map_p1_entries(last_mapped_p1_table, i, Frame{
                            number: stack_start_frame.number + last_mapped_p1_table*512 + i,
                        });
                    }
                } else {
                    // add as free
                    frame_stack::deallocate_frame(frame);
                }
            }
        }
    }
}

unsafe fn map_to_p1_table(p2_index: u32, to: Frame) {
    *((0o177777_777_777_000_001_0000 + (p2_index as u64)*8) as *mut u64) = (to.number as u64 << 12) | 1;
}
unsafe fn map_p1_entries(p2_index: u32, p1_index: u32, to: Frame) {
    let entry = (0o177777_777_000_001_000_0000 | (p2_index as u64 << 12) | (p1_index as u64 * 8)) as *mut u64;
    *entry = (to.number as u64 << 12) | 3;
}<|endoftext|>


<commit_before>// Copyright 2016-2017 Matthew D. Michelotti
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

mod grid;
mod collider;
mod events;
mod dur_hitbox;

pub use self::collider::*;

use std::f64;

use geom::*;
use geom::shape::PlacedBounds;
use self::dur_hitbox::{DurHitbox, DurHbVel};

const HIGH_TIME: f64 = 1e50;

/// Type used as a handle for referencing hitboxes in a `Collider` instance.
pub type HbId = u64;

/// Velocity information describing how a hitbox shape is changing over time.
#[derive(PartialEq, Clone, Debug)]
pub struct HbVel {
    /// The movement velocity of the hitbox.
    pub value: Vec2,

    /// A velocity describing how the hitbox dims are changing over time.
    ///
    /// Since the width and height of the shape is greater than `padding` at all times,
    /// if a resize velocity is set that decreases the dimensions of the shape over time,
    /// then the user is responsible for ensuring that the shape will not decrease below this threshold.
    /// Collider may panic if this is violated.
    pub resize: Vec2,

    /// An upper-bound on the time at which the hitbox will be updated by the user.
    ///
    /// This is an advanced feature for efficiency and does not impact the results.
    /// Infinity is used as the default, but using a lower value may improve performance
    ///
    /// Collider will panic if the end time is exceeded without update,
    /// at least in unoptimized builds.  It is ultimately the user's responsibility
    /// to ensure that end times are not exceeded.
    pub end_time: f64,
}

impl HbVel {
    /// Creates an `HbVel` with the given `value`.
    pub fn moving(value: Vec2) -> HbVel {
        HbVel { value, resize: Vec2::zero(), end_time: f64::INFINITY }
    }

    /// Creates an `HbVel` with the given `value` and `end_time`.
    pub fn moving_until(value: Vec2, end_time: f64) -> HbVel {
        HbVel { value, resize: Vec2::zero(), end_time }
    }

    /// Creates a stationary `HbVel`.
    pub fn still() -> HbVel {
        HbVel { value: Vec2::zero(), resize: Vec2::zero(), end_time: f64::INFINITY }
    }

    /// Creates a stationary `HbVel` with the given `end_time`.
    pub fn still_until(end_time: f64) -> HbVel {
        HbVel { value: Vec2::zero(), resize: Vec2::zero(), end_time }
    }
}

impl From<Vec2> for HbVel {
    fn from(value: Vec2) -> HbVel { HbVel::moving(value) }
}

impl PlacedBounds for HbVel {
    fn bounds_center(&self) -> &Vec2 { &self.value }
    fn bounds_dims(&self) -> &Vec2 { &self.resize }
}

/// Represents a moving shape for continuous collision testing.
#[derive(PartialEq, Clone, Debug)]
pub struct Hitbox {
    /// The placed shape at the given point in time.
    ///
    /// The width and height of the shape must be greater than `padding` at all times.
    pub value: PlacedShape,

    // Velocity information describing how the hitbox shape is changing over time.
    pub vel: HbVel,
}

//TODO invoke hitbox.validate() in more places so that inconsistencies are still found in optimized builds, just found later

impl Hitbox {
    /// Constructs a new hitbox with the given `value` and `vel`.
    pub fn new(value: PlacedShape, vel: HbVel) -> Hitbox {
        Hitbox { value, vel }
    }

    fn advanced_shape(&self, time: f64) -> PlacedShape {
        assert!(time < HIGH_TIME, "requires time < {}", HIGH_TIME);
        self.value.advance(self.vel.value, self.vel.resize, time)
    }

    fn validate(&self, min_size: f64, present_time: f64) {
        assert!(!self.vel.end_time.is_nan() && self.vel.end_time >= present_time, "end time must exceed present time");
        if self.value.kind() == ShapeKind::Circle {
            assert!(self.vel.resize.x == self.vel.resize.y, "circle resize velocity must maintain aspect ratio");
        }
        assert!(self.value.dims().x >= min_size && self.value.dims().y >= min_size, "shape width/height must be at least {}", min_size);
    }

    fn time_until_too_small(&self, min_size: f64) -> f64 {
        let min_size = min_size * 0.9;
        assert!(self.value.dims().x > min_size && self.value.dims().y > min_size);
        let mut time = f64::INFINITY;
        if self.vel.resize.x < 0.0 { time = time.min((min_size - self.value.dims().x) / self.vel.value.x); }
        if self.vel.resize.y < 0.0 { time = time.min((min_size - self.value.dims().y) / self.vel.value.y); }
        time
    }

    fn to_dur_hitbox(&self, time: f64) -> DurHitbox {
        assert!(time <= self.vel.end_time);
        DurHitbox {
            value: self.value,
            vel: DurHbVel {
                value: self.vel.value,
                resize: self.vel.resize,
                duration: self.vel.end_time - time,
            },
        }
    }
}

/// A group id that may be used as a first measure to efficiently filter out hitboxes that don't interact.
///
/// The total number of groups used should in general be very small.
/// Often 1 is enough, and 10 is excessive.
/// As an example, in a [danmaku](https://en.wikipedia.org/wiki/Shoot_%27em_up#Bullet_hell_and_niche_appeal) game
/// (which has many bullets on screen that do not interact with each other),
/// we may use one group for bullets and one group for everything else,
/// to avoid the quadratic cost of comparing all nearby bullets with each other.
pub type HbGroup = u32;

static DEFAULT_GROUPS: [HbGroup; 1] = [0];

/// A trait that holds metadata for describing a hitbox.
///
/// A user of `Collider` will need to implement an HbProfile that best suites their needs in a game.
/// The most basic HbProfile will just contain an integer ID for the hitbox,
/// but a user may define additional metadata for identfying the hitbox and describing interactivity.
/// An HbProfile must implement the `Copy` trait and should not take up much memory.
pub trait HbProfile: Copy {
    /// A unique identifier for the hitbox.
    ///
    /// Trying to have multiple hitboxes with the same `id` to a `Collider` instance simultaneously
    /// will result in a panic.
    fn id(&self) -> HbId;

    /// Returns the group id associated with the hitbox.
    /// Default is `Some(0)`.
    ///
    /// If `None` is returned, then no collisions will be reported
    /// for this hitbox at all.
    fn group(&self) -> Option<HbGroup> { Some(0) }

    /// Returns a list of groups that this hitbox can interact with.
    /// Using large lists of groups may be inefficient.
    /// Default is `[0]`.
    fn interact_groups(&self) -> &'static [HbGroup] { &DEFAULT_GROUPS }

    /// Returns true if the pair of hitboxes should be checked for collisions.
    /// This method should be commutative.
    /// This method should be consistent with `group` and `interact_groups`,
    /// although possibly more restrictive.
    fn can_interact(&self, other: &Self) -> bool;

    /// The width of the cells used in the Collider grid.
    ///
    /// To reduce the number of overlaps that are tested,
    /// hitboxes are placed in a sparse grid structure behind the scenes.
    /// `cell_width` is the width of the cells used in that grid.
    /// If your game has a similar grid concept, then it is usually a good choice
    /// to use the same cell width as that grid.
    /// Otherwise, a good choice is to use a width that is slightly larger
    /// than most of the hitboxes.
    fn cell_width() -> f64;

    /// The minimum distance before two hitboxes are considered separated.
    ///
    /// Collider generates both `Collide` and `Separate` events.
    /// However, due to numerical error, it is important that two hitboxes
    /// be a certain small distance apart from each other after a collision
    /// before they are considered separated.
    /// Otherwise, false separation events may occur if, for example,
    /// a sprite runs into a wall and stops, still touching the wall.
    /// `padding` is used to describe what this minimum separation distance is.
    /// This should typically be something that is not visible to the
    /// user, perhaps a fraction of a "pixel."
    ///
    /// Another restriction introduced by `padding` is that hitboxes are not
    /// allowed to have a width or height smaller than `padding`.
    fn padding() -> f64;
}
<commit_msg>doc comment updates<commit_after>// Copyright 2016-2017 Matthew D. Michelotti
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

mod grid;
mod collider;
mod events;
mod dur_hitbox;

pub use self::collider::*;

use std::f64;

use geom::*;
use geom::shape::PlacedBounds;
use self::dur_hitbox::{DurHitbox, DurHbVel};

const HIGH_TIME: f64 = 1e50;

/// Type used as a handle for referencing hitboxes in a `Collider` instance.
pub type HbId = u64;

/// Velocity information describing how a hitbox shape is changing over time.
#[derive(PartialEq, Clone, Debug)]
pub struct HbVel {
    /// The movement velocity of the hitbox.
    pub value: Vec2,

    /// A velocity describing how the hitbox dims are changing over time.
    ///
    /// Since the width and height of the shape is greater than `padding` at all times,
    /// if a resize velocity is set that decreases the dimensions of the shape over time,
    /// then the user is responsible for ensuring that the shape will not decrease below this threshold.
    /// Collider may panic if this is violated.
    pub resize: Vec2,

    /// An upper-bound on the time at which the hitbox will be updated by the user.
    ///
    /// This is an advanced feature for efficiency and does not impact the results.
    /// Infinity is used as the default, but using a lower value may improve performance
    ///
    /// Collider will panic if the end time is exceeded without update,
    /// at least in unoptimized builds.  It is ultimately the user's responsibility
    /// to ensure that end times are not exceeded.
    pub end_time: f64,
}

impl HbVel {
    /// Creates an `HbVel` with the given `value`.
    pub fn moving(value: Vec2) -> HbVel {
        HbVel { value, resize: Vec2::zero(), end_time: f64::INFINITY }
    }

    /// Creates an `HbVel` with the given `value` and `end_time`.
    pub fn moving_until(value: Vec2, end_time: f64) -> HbVel {
        HbVel { value, resize: Vec2::zero(), end_time }
    }

    /// Creates a stationary `HbVel`.
    pub fn still() -> HbVel {
        HbVel { value: Vec2::zero(), resize: Vec2::zero(), end_time: f64::INFINITY }
    }

    /// Creates a stationary `HbVel` with the given `end_time`.
    pub fn still_until(end_time: f64) -> HbVel {
        HbVel { value: Vec2::zero(), resize: Vec2::zero(), end_time }
    }
}

impl From<Vec2> for HbVel {
    fn from(value: Vec2) -> HbVel { HbVel::moving(value) }
}

impl PlacedBounds for HbVel {
    fn bounds_center(&self) -> &Vec2 { &self.value }
    fn bounds_dims(&self) -> &Vec2 { &self.resize }
}

/// Represents a moving shape for continuous collision testing.
#[derive(PartialEq, Clone, Debug)]
pub struct Hitbox {
    /// The placed shape at the given point in time.
    ///
    /// The width and height of the shape must be greater than `padding` at all times.
    pub value: PlacedShape,

    /// Velocity information describing how the hitbox shape is changing over time.
    pub vel: HbVel,
}

//TODO invoke hitbox.validate() in more places so that inconsistencies are still found in optimized builds, just found later

impl Hitbox {
    /// Constructs a new hitbox with the given `value` and `vel`.
    pub fn new(value: PlacedShape, vel: HbVel) -> Hitbox {
        Hitbox { value, vel }
    }

    fn advanced_shape(&self, time: f64) -> PlacedShape {
        assert!(time < HIGH_TIME, "requires time < {}", HIGH_TIME);
        self.value.advance(self.vel.value, self.vel.resize, time)
    }

    fn validate(&self, min_size: f64, present_time: f64) {
        assert!(!self.vel.end_time.is_nan() && self.vel.end_time >= present_time, "end time must exceed present time");
        if self.value.kind() == ShapeKind::Circle {
            assert!(self.vel.resize.x == self.vel.resize.y, "circle resize velocity must maintain aspect ratio");
        }
        assert!(self.value.dims().x >= min_size && self.value.dims().y >= min_size, "shape width/height must be at least {}", min_size);
    }

    fn time_until_too_small(&self, min_size: f64) -> f64 {
        let min_size = min_size * 0.9;
        assert!(self.value.dims().x > min_size && self.value.dims().y > min_size);
        let mut time = f64::INFINITY;
        if self.vel.resize.x < 0.0 { time = time.min((min_size - self.value.dims().x) / self.vel.value.x); }
        if self.vel.resize.y < 0.0 { time = time.min((min_size - self.value.dims().y) / self.vel.value.y); }
        time
    }

    fn to_dur_hitbox(&self, time: f64) -> DurHitbox {
        assert!(time <= self.vel.end_time);
        DurHitbox {
            value: self.value,
            vel: DurHbVel {
                value: self.vel.value,
                resize: self.vel.resize,
                duration: self.vel.end_time - time,
            },
        }
    }
}

/// A group id that may be used as a first measure to efficiently filter out hitboxes that don't interact.
///
/// The total number of groups used should in general be very small.
/// Often 1 is enough, and 10 is excessive.
/// As an example, in a [danmaku](https://en.wikipedia.org/wiki/Shoot_%27em_up#Bullet_hell_and_niche_appeal) game
/// (which has many bullets on screen that do not interact with each other),
/// we may use one group for bullets and one group for everything else,
/// to avoid the quadratic cost of comparing all nearby bullets with each other.
pub type HbGroup = u32;

static DEFAULT_GROUPS: [HbGroup; 1] = [0];

/// A trait that holds metadata for describing a hitbox.
///
/// A user of `Collider` will need to implement an HbProfile that best suites their needs in a game.
/// The most basic HbProfile will just contain an integer ID for the hitbox,
/// but a user may define additional metadata for identfying the hitbox and describing interactivity.
/// An HbProfile must implement the `Copy` trait and should not take up much memory.
pub trait HbProfile: Copy {
    /// A unique identifier for the hitbox.
    ///
    /// Trying to have multiple hitboxes with the same `id` to a `Collider` instance simultaneously
    /// will result in a panic.
    fn id(&self) -> HbId;

    /// Returns the group id associated with the hitbox.
    /// Default is `Some(0)`.
    ///
    /// If `None` is returned, then no collisions will be reported
    /// for this hitbox at all.
    fn group(&self) -> Option<HbGroup> { Some(0) }

    /// Returns a list of groups that this hitbox can interact with.
    /// Default is `[0]`.
    ///
    /// Using large lists of groups may be inefficient.
    fn interact_groups(&self) -> &'static [HbGroup] { &DEFAULT_GROUPS }

    /// Returns true if the pair of hitboxes should be checked for collisions.
    ///
    /// This method should be commutative.
    /// This method should be consistent with `group` and `interact_groups`,
    /// although possibly more restrictive.
    fn can_interact(&self, other: &Self) -> bool;

    /// The width of the cells used in the Collider grid.
    ///
    /// To reduce the number of overlaps that are tested,
    /// hitboxes are placed in a sparse grid structure behind the scenes.
    /// `cell_width` is the width of the cells used in that grid.
    /// If your game has a similar grid concept, then it is usually a good choice
    /// to use the same cell width as that grid.
    /// Otherwise, a good choice is to use a width that is slightly larger
    /// than most of the hitboxes.
    fn cell_width() -> f64;

    /// The minimum distance before two hitboxes are considered separated.
    ///
    /// Collider generates both `Collide` and `Separate` events.
    /// However, due to numerical error, it is important that two hitboxes
    /// be a certain small distance apart from each other after a collision
    /// before they are considered separated.
    /// Otherwise, false separation events may occur if, for example,
    /// a sprite runs into a wall and stops, still touching the wall.
    /// `padding` is used to describe what this minimum separation distance is.
    /// This should typically be something that is not visible to the
    /// user, perhaps a fraction of a "pixel."
    ///
    /// Another restriction introduced by `padding` is that hitboxes are not
    /// allowed to have a width or height smaller than `padding`.
    fn padding() -> f64;
}
<|endoftext|>