<commit_before>use std::fmt;

use chrono::{DateTime, Local};
use itertools::Itertools;
use json::JsonValue;

// #[derive(Debug, Default)]
// pub struct Error {
//     pub detail: String,
// }
//
// #[derive(Debug)]
// pub struct CrateLinks {
//     pub owners: Option<String>,
//     pub reverse_dependencies: String,
//     pub version_downloads: String,
//     pub versions: Option<String>,
// }
//
// pub struct Crate {
//     pub created_at: String,
//     pub description: Option<String>,
//     pub documentation: Option<String>,
//     pub downloads: i32,
//     pub homepage: Option<String>,
//     pub id: String,
//     pub keywords: Option<Vec<String>>,
//     pub license: Option<String>,
//     pub links: CrateLinks,
//     pub max_version: String,
//     pub name: String,
//     pub repository: Option<String>,
//     pub updated_at: String,
//     pub versions: Option<Vec<u64>>,
// }
//
// #[derive(Debug)]
// pub struct Keyword {
//     pub crates_cnt: u64,
//     pub created_at: String,
//     pub id: String,
//     pub keyword: String,
// }
//
// #[derive(Debug)]
// pub struct VersionLinks {
//     pub authors: String,
//     pub dependencies: String,
//     pub version_downloads: String,
// }
//
// #[derive(Debug)]
// pub struct Version {
//     pub krate: String,
//     pub created_at: String,
//     pub dl_path: String,
//     pub downloads: i32,
//     pub features: HashMap<String, Vec<String>>,
//     pub id: i32,
//     pub links: VersionLinks,
//     pub num: String,
//     pub updated_at: String,
//     pub yanked: bool,
// }
//
// pub struct Reply {
//     pub errors: Error,
//     pub krate: Crate,
//     pub keywords: Vec<Keyword>,
//     pub versions: Vec<Version>,
// }

struct TimeStamp(Option<DateTime<Local>>);

impl<'a> From<&'a JsonValue> for TimeStamp {
    fn from(jv: &JsonValue) -> Self {
        let parse = |s: &str| s.parse::<DateTime<Local>>().ok();
        TimeStamp(jv.as_str().and_then(parse))
    }
}

impl fmt::Display for TimeStamp {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(ts) = self.0 {
            write!(f, "{}", ts)
        } else {
            write!(f, "")
        }
    }
}

pub struct Crate {
    krate: JsonValue,
    versions: JsonValue,
    keywords: JsonValue,
}

impl Crate {
    pub fn new(json: &JsonValue) -> Self {
        Crate {
            krate: json["crate"].clone(),
            versions: json["versions"].clone(),
            keywords: json["keywords"].clone(),
        }
    }

    pub fn print_repository(&self, verbose: bool) {
        if let JsonValue::String(ref repository) = self.krate["repository"] {
            let fmt = if verbose {
                format!("{:<16}{}", "Repository:", repository)
            } else {
                repository.clone()
            };
            println!("{}", fmt);
        }
    }

    pub fn print_documentation(&self, verbose: bool) {
        if let JsonValue::String(ref documentation) = self.krate["documentation"] {
            let fmt = if verbose {
                format!("{:<16}{}", "Documentation:", documentation)
            } else {
                documentation.clone()
            };
            println!("{}", fmt);
        }
    }

    pub fn print_downloads(&self, verbose: bool) {
        if let JsonValue::Number(downloads) = self.krate["downloads"] {
            let fmt = if verbose {
                format!("{:<16}{}", "Downloads:", downloads)
            } else {
                format!("{}", downloads)
            };
            println!("{}", fmt);
        }
    }

    pub fn print_homepage(&self, verbose: bool) {
        if let JsonValue::String(ref homepage) = self.krate["homepage"] {
            let fmt = if verbose {
                format!("{:<16}{}", "Homepage:", homepage)
            } else {
                homepage.clone()
            };
            println!("{}", fmt);
        }
    }

    fn print_version(v: &JsonValue, verbose: bool) {

        let fmt = if verbose {
            let created_at = TimeStamp::from(&v["created_at"]);
            format!("{} {} {}", v["num"], created_at, v["downloads"])
        } else {
            format!("{}", v["num"])
        };
        println!("{}", fmt);
    }

    pub fn print_last_versions(&self, verbose: bool) {
        // self.versions.members().take(5).rev().foreach(|v| Crate::print_version(v, verbose));
        self.versions.members().take(5).foreach(|v| Crate::print_version(v, verbose));
    }

    pub fn print_keywords(&self, verbose: bool) {
        let fmt = if verbose {
            format!("{:#}", self.keywords)
        } else {
            format!("{}", self.keywords)
        };
        println!("{}", fmt);
    }
}

impl fmt::Display for Crate {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let empty = "";

        let name = self.krate["name"].as_str().unwrap_or(empty);
        let max_version = self.krate["max_version"].as_str().unwrap_or(empty);
        let downloads = self.krate["downloads"].as_i32().unwrap_or(0);

        let created_at = TimeStamp::from(&self.krate["created_at"]);
        let updated_at = TimeStamp::from(&self.krate["updated_at"]);

        let description = self.krate["description"].as_str().unwrap_or(empty);
        let documentation = self.krate["documentation"].as_str().unwrap_or(empty);
        let homepage = self.krate["homepage"].as_str().unwrap_or(empty);
        let repository = self.krate["repository"].as_str().unwrap_or(empty);
        let license = self.krate["license"].as_str().unwrap_or(empty);

        let keywords = self.krate["keywords"]
            .members()
            .filter_map(|jv| jv.as_str())
            .collect::<Vec<_>>();

        if f.alternate() {
            write!(f,
                   "{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}",
                   format_args!("{:<16}{}", "Crate:", name),
                   format_args!("{:<16}{}", "Version:", max_version),
                   format_args!("{:<16}{}", "Description:", description),
                   format_args!("{:<16}{}", "Downloads:", downloads),
                   format_args!("{:<16}{}", "Homepage:", homepage),
                   format_args!("{:<16}{}", "Documentation:", documentation),
                   format_args!("{:<16}{}", "Repository:", repository),
                   format_args!("{:<16}{}", "License:", license),
                   format_args!("{:<16}{:?}", "Keywords:", keywords),
                   format_args!("{:<16}{}", "Created at:", created_at),
                   format_args!("{:<16}{}", "Updated at:", updated_at))
        } else {
            write!(f,
                   "{}\n{}\n{}\n{}\n{}\n{}\n{}",
                   format_args!("{:<16}{}", "Crate:", name),
                   format_args!("{:<16}{}", "Version:", max_version),
                   format_args!("{:<16}{}", "Description:", description),
                   format_args!("{:<16}{}", "Downloads:", downloads),
                   format_args!("{:<16}{}", "Homepage:", homepage),
                   format_args!("{:<16}{}", "Documentation:", documentation),
                   format_args!("{:<16}{}", "Repository:", repository))
        }
    }
}
<commit_msg>Show last 5 versions<commit_after>use std::fmt;

use chrono::{DateTime, Local};
use itertools::Itertools;
use json::JsonValue;

// #[derive(Debug, Default)]
// pub struct Error {
//     pub detail: String,
// }
//
// #[derive(Debug)]
// pub struct CrateLinks {
//     pub owners: Option<String>,
//     pub reverse_dependencies: String,
//     pub version_downloads: String,
//     pub versions: Option<String>,
// }
//
// pub struct Crate {
//     pub created_at: String,
//     pub description: Option<String>,
//     pub documentation: Option<String>,
//     pub downloads: i32,
//     pub homepage: Option<String>,
//     pub id: String,
//     pub keywords: Option<Vec<String>>,
//     pub license: Option<String>,
//     pub links: CrateLinks,
//     pub max_version: String,
//     pub name: String,
//     pub repository: Option<String>,
//     pub updated_at: String,
//     pub versions: Option<Vec<u64>>,
// }
//
// #[derive(Debug)]
// pub struct Keyword {
//     pub crates_cnt: u64,
//     pub created_at: String,
//     pub id: String,
//     pub keyword: String,
// }
//
// #[derive(Debug)]
// pub struct VersionLinks {
//     pub authors: String,
//     pub dependencies: String,
//     pub version_downloads: String,
// }
//
// #[derive(Debug)]
// pub struct Version {
//     pub krate: String,
//     pub created_at: String,
//     pub dl_path: String,
//     pub downloads: i32,
//     pub features: HashMap<String, Vec<String>>,
//     pub id: i32,
//     pub links: VersionLinks,
//     pub num: String,
//     pub updated_at: String,
//     pub yanked: bool,
// }
//
// pub struct Reply {
//     pub errors: Error,
//     pub krate: Crate,
//     pub keywords: Vec<Keyword>,
//     pub versions: Vec<Version>,
// }

struct TimeStamp(Option<DateTime<Local>>);

impl<'a> From<&'a JsonValue> for TimeStamp {
    fn from(jv: &JsonValue) -> Self {
        let parse = |s: &str| s.parse::<DateTime<Local>>().ok();
        TimeStamp(jv.as_str().and_then(parse))
    }
}

impl fmt::Display for TimeStamp {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(ts) = self.0 {
            write!(f, "{}", ts)
        } else {
            write!(f, "")
        }
    }
}

pub struct Crate {
    krate: JsonValue,
    versions: JsonValue,
    keywords: JsonValue,
}

impl Crate {
    pub fn new(json: &JsonValue) -> Self {
        Crate {
            krate: json["crate"].clone(),
            versions: json["versions"].clone(),
            keywords: json["keywords"].clone(),
        }
    }

    pub fn print_repository(&self, verbose: bool) {
        if let JsonValue::String(ref repository) = self.krate["repository"] {
            let fmt = if verbose {
                format!("{:<16}{}", "Repository:", repository)
            } else {
                repository.clone()
            };
            println!("{}", fmt);
        }
    }

    pub fn print_documentation(&self, verbose: bool) {
        if let JsonValue::String(ref documentation) = self.krate["documentation"] {
            let fmt = if verbose {
                format!("{:<16}{}", "Documentation:", documentation)
            } else {
                documentation.clone()
            };
            println!("{}", fmt);
        }
    }

    pub fn print_downloads(&self, verbose: bool) {
        if let JsonValue::Number(downloads) = self.krate["downloads"] {
            let fmt = if verbose {
                format!("{:<16}{}", "Downloads:", downloads)
            } else {
                format!("{}", downloads)
            };
            println!("{}", fmt);
        }
    }

    pub fn print_homepage(&self, verbose: bool) {
        if let JsonValue::String(ref homepage) = self.krate["homepage"] {
            let fmt = if verbose {
                format!("{:<16}{}", "Homepage:", homepage)
            } else {
                homepage.clone()
            };
            println!("{}", fmt);
        }
    }

    fn print_version(v: &JsonValue, verbose: bool) {

        let fmt = if verbose {
            let created_at = TimeStamp::from(&v["created_at"]);
            format!("{} {} {}", v["num"], created_at, v["downloads"])
        } else {
            format!("{}", v["num"])
        };
        println!("{}", fmt);
    }

    pub fn print_last_versions(&self, verbose: bool) {
        self.versions
            .members()
            .take(5)
            // This collect()::<Vec<_>>.iter() is here only because take()
            // does not support DoubleEndedIterator for rev(), bummer
            .collect::<Vec<_>>()
            .iter()
            .rev()
            .foreach(|v| Crate::print_version(v, verbose));
    }

    pub fn print_keywords(&self, verbose: bool) {
        let fmt = if verbose {
            format!("{:#}", self.keywords)
        } else {
            format!("{}", self.keywords)
        };
        println!("{}", fmt);
    }
}

impl fmt::Display for Crate {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let empty = "";

        let name = self.krate["name"].as_str().unwrap_or(empty);
        let max_version = self.krate["max_version"].as_str().unwrap_or(empty);
        let downloads = self.krate["downloads"].as_i32().unwrap_or(0);

        let created_at = TimeStamp::from(&self.krate["created_at"]);
        let updated_at = TimeStamp::from(&self.krate["updated_at"]);

        let description = self.krate["description"].as_str().unwrap_or(empty);
        let documentation = self.krate["documentation"].as_str().unwrap_or(empty);
        let homepage = self.krate["homepage"].as_str().unwrap_or(empty);
        let repository = self.krate["repository"].as_str().unwrap_or(empty);
        let license = self.krate["license"].as_str().unwrap_or(empty);

        let keywords = self.krate["keywords"]
            .members()
            .filter_map(|jv| jv.as_str())
            .collect::<Vec<_>>();

        if f.alternate() {
            write!(f,
                   "{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}",
                   format_args!("{:<16}{}", "Crate:", name),
                   format_args!("{:<16}{}", "Version:", max_version),
                   format_args!("{:<16}{}", "Description:", description),
                   format_args!("{:<16}{}", "Downloads:", downloads),
                   format_args!("{:<16}{}", "Homepage:", homepage),
                   format_args!("{:<16}{}", "Documentation:", documentation),
                   format_args!("{:<16}{}", "Repository:", repository),
                   format_args!("{:<16}{}", "License:", license),
                   format_args!("{:<16}{:?}", "Keywords:", keywords),
                   format_args!("{:<16}{}", "Created at:", created_at),
                   format_args!("{:<16}{}", "Updated at:", updated_at))
        } else {
            write!(f,
                   "{}\n{}\n{}\n{}\n{}\n{}\n{}",
                   format_args!("{:<16}{}", "Crate:", name),
                   format_args!("{:<16}{}", "Version:", max_version),
                   format_args!("{:<16}{}", "Description:", description),
                   format_args!("{:<16}{}", "Downloads:", downloads),
                   format_args!("{:<16}{}", "Homepage:", homepage),
                   format_args!("{:<16}{}", "Documentation:", documentation),
                   format_args!("{:<16}{}", "Repository:", repository))
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Update: add feature kv_unstable to code block.<commit_after><|endoftext|>


<commit_before>use ast::with_error_checking_parse;
use core::{Match, MatchType, Session};
use typeinf::get_function_declaration;

use syntax::ast::ImplItemKind;

/// Returns completion snippets usable by some editors
///
/// Generates a snippet string given a `Match`. The provided snippet contains
/// substrings like "${1:name}" which some editors can use to quickly fill in
/// arguments.
///
/// # Examples
///
/// ```no_run
/// extern crate racer;
///
/// use std::path::Path;
///
/// let path = Path::new(".");
/// let cache = racer::FileCache::default();
/// let session = racer::Session::new(&cache);
///
/// let m = racer::complete_fully_qualified_name(
///     "std::fs::canonicalize",
///     &path,
///     &session
/// ).next().unwrap();
///
/// let snip = racer::snippet_for_match(&m, &session);
/// assert_eq!(snip, "canonicalize(${1:path})");
/// ```
pub fn snippet_for_match(m: &Match, session: &Session) -> String {
    if m.mtype == MatchType::Function {
        let method = get_function_declaration(m, session);
        if let Some(m) = MethodInfo::from_source_str(&method) {
            m.snippet()
        } else {
            "".into()
        }
    } else {
        m.matchstr.clone()
    }
}

struct MethodInfo {
    name: String,
    args: Vec<String>
}

impl MethodInfo {
    ///Parses method declaration as string and returns relevant data
    fn from_source_str(source: &str) -> Option<MethodInfo> {
        let trim: &[_] = &['\n', '\r', '{', ' '];
        let decorated = format!("{} {{}}()", source.trim_right_matches(trim));

        trace!("MethodInfo::from_source_str: {:?}", decorated);
        with_error_checking_parse(decorated, |p| {
            let mut at_end = false;
            if let Ok(method) = p.parse_impl_item(&mut at_end) {
                if let ImplItemKind::Method(ref msig, _) = method.node {
                        let decl = &msig.decl;
                        return Some(MethodInfo {
                            // ident.as_str calls Ident.name.as_str
                            name: method.ident.name.to_string(),
                            args: decl.inputs
                                      .iter()
                                      .map(|arg| {
                                          let codemap = &p.sess.codemap();
                                          let var_name = match codemap.span_to_snippet(arg.pat.span) {
                                              Ok(name) => name,
                                              _ => "".into()
                                          };
                                          match codemap.span_to_snippet(arg.ty.span) {
                                              Ok(ref type_name) if !type_name.is_empty() => format!("{}: {}", var_name, type_name),
                                              _ => var_name
                                          }
                                      })
                                      .collect()
                        })
                }
            }
            debug!("Unable to parse method declaration. |{}|", source);
            None
        })
    }

    ///Returns completion snippets usable by some editors
    fn snippet(&self) -> String {
        format!("{}({})",
                self.name,
                &self.args
                     .iter()
                     .filter(|&s| !s.ends_with("self"))
                     .enumerate()
                     .fold(String::new(), |cur, (i, ref s)| {
                         let arg = format!("${{{}:{}}}", i + 1, s);
                         let delim = if i > 0 { ", " } else { "" };
                         cur + delim + &arg
                     }))
    }
}

#[test]
fn method_info_test() {
    let info = MethodInfo::from_source_str("pub fn new() -> Vec<T>").unwrap();
    assert_eq!(info.name, "new");
    assert_eq!(info.args.len(), 0);
    assert_eq!(info.snippet(), "new()");

    let info = MethodInfo::from_source_str("pub fn reserve(&mut self, additional: uint)").unwrap();
    assert_eq!(info.name, "reserve");
    assert_eq!(info.args.len(), 2);
    assert_eq!(info.args[0], "&mut self");
    assert_eq!(info.snippet(), "reserve(${1:additional: uint})");
}
<commit_msg>Fix broken test of snippet<commit_after>use ast::with_error_checking_parse;
use core::{Match, MatchType, Session};
use typeinf::get_function_declaration;

use syntax::ast::ImplItemKind;

/// Returns completion snippets usable by some editors
///
/// Generates a snippet string given a `Match`. The provided snippet contains
/// substrings like "${1:name}" which some editors can use to quickly fill in
/// arguments.
///
/// # Examples
///
/// ```no_run
/// extern crate racer;
///
/// use std::path::Path;
///
/// let path = Path::new(".");
/// let cache = racer::FileCache::default();
/// let session = racer::Session::new(&cache);
///
/// let m = racer::complete_fully_qualified_name(
///     "std::fs::canonicalize",
///     &path,
///     &session
/// ).next().unwrap();
///
/// let snip = racer::snippet_for_match(&m, &session);
/// assert_eq!(snip, "canonicalize(${1:path})");
/// ```
pub fn snippet_for_match(m: &Match, session: &Session) -> String {
    if m.mtype == MatchType::Function {
        let method = get_function_declaration(m, session);
        if let Some(m) = MethodInfo::from_source_str(&method) {
            m.snippet()
        } else {
            "".into()
        }
    } else {
        m.matchstr.clone()
    }
}

struct MethodInfo {
    name: String,
    args: Vec<String>
}

impl MethodInfo {
    ///Parses method declaration as string and returns relevant data
    fn from_source_str(source: &str) -> Option<MethodInfo> {
        let trim: &[_] = &['\n', '\r', '{', ' '];
        let decorated = format!("{} {{}}()", source.trim_right_matches(trim));

        trace!("MethodInfo::from_source_str: {:?}", decorated);
        with_error_checking_parse(decorated, |p| {
            let mut at_end = false;
            if let Ok(method) = p.parse_impl_item(&mut at_end) {
                if let ImplItemKind::Method(ref msig, _) = method.node {
                        let decl = &msig.decl;
                        return Some(MethodInfo {
                            // ident.as_str calls Ident.name.as_str
                            name: method.ident.name.to_string(),
                            args: decl.inputs
                                      .iter()
                                      .map(|arg| {
                                          let codemap = &p.sess.codemap();
                                          let var_name = match codemap.span_to_snippet(arg.pat.span) {
                                              Ok(name) => name,
                                              _ => "".into()
                                          };
                                          match codemap.span_to_snippet(arg.ty.span) {
                                              Ok(ref type_name) if !type_name.is_empty() => format!("{}: {}", var_name, type_name),
                                              _ => var_name
                                          }
                                      })
                                      .collect()
                        })
                }
            }
            debug!("Unable to parse method declaration. |{}|", source);
            None
        })
    }

    ///Returns completion snippets usable by some editors
    fn snippet(&self) -> String {
        format!("{}({})",
                self.name,
                &self.args
                     .iter()
                     .filter(|&s| !s.ends_with("self"))
                     .enumerate()
                     .fold(String::new(), |cur, (i, ref s)| {
                         let arg = format!("${{{}:{}}}", i + 1, s);
                         let delim = if i > 0 { ", " } else { "" };
                         cur + delim + &arg
                     }))
    }
}

#[test]
fn method_info_test() {
    let info = MethodInfo::from_source_str("pub fn new() -> Vec<T>").unwrap();
    assert_eq!(info.name, "new");
    assert_eq!(info.args.len(), 0);
    assert_eq!(info.snippet(), "new()");

    let info = MethodInfo::from_source_str("pub fn reserve(&mut self, additional: usize)").unwrap();
    assert_eq!(info.name, "reserve");
    assert_eq!(info.args.len(), 2);
    // it looks odd, but no problme because what our clients see is only snippet
    assert_eq!(info.args[0], "&mut self: &mut self");
    assert_eq!(info.snippet(), "reserve(${1:additional: usize})");
}
<|endoftext|>


<commit_before>use std::convert::TryFrom;
use std::marker::PhantomData;
use num::Float;
use operate::Operate;
use stack::Stack;
use ::pop_two_operands;

// Add  (+)      pop 2, push 1
// Sub  (-)      pop 2, push 1
// Mul  (*)      pop 2, push 1
// Div  (/)      pop 2, push 1
// Rem  (%)      pop 2, push 1
// Neg  (neg)    pop 1, push 1
// Sqrt (sqrt)   pop 1, push 1
// Pow  (pow)    pop 1, push 1
// Log2 (log2)   pop 1, push 1
// Exp  (exp)    pop 1, push 1
// Swap (swap)   pop 2, push 2
// Zero (zero)   pop 0, push 1
// One  (zero)   pop 0, push 1
// Round (round) pop 1, push 1

#[derive(Debug, Copy, Clone)]
pub enum FloatOperator<T: Float> {
    Add(PhantomData<T>),
    Sub(PhantomData<T>),
    Mul(PhantomData<T>),
    Div(PhantomData<T>),
    Rem(PhantomData<T>),
    Neg(PhantomData<T>),
    Sqrt(PhantomData<T>),
    Pow(PhantomData<T>),
    Log2(PhantomData<T>),
    Exp(PhantomData<T>),
    Swap(PhantomData<T>),
    Zero(PhantomData<T>),
    One(PhantomData<T>),
    Round(PhantomData<T>),
}

impl<T: Float> Operate<T> for FloatOperator<T> {
    type Err = ();

    fn operands_needed(&self) -> usize {
        use self::FloatOperator::*;
        match *self {
              Add(_)
            | Sub(_)
            | Mul(_)
            | Div(_)
            | Pow(_)
            | Rem(_)
            | Swap(_) => 2,
              Neg(_)
            | Sqrt(_)
            | Log2(_)
            | Round(_)
            | Exp(_) => 1,
              Zero(_)
            | One(_) => 0,
        }
    }

    fn operands_generated(&self) -> usize {
        use self::FloatOperator::*;
        match *self {
              Add(_)
            | Sub(_)
            | Mul(_)
            | Div(_)
            | Rem(_)
            | Neg(_)
            | Sqrt(_)
            | Pow(_)
            | Log2(_)
            | Exp(_)
            | Zero(_)
            | One(_)
            | Round(_) => 1,
              Swap(_) => 2,
        }
    }

    fn operate(self, stack: &mut Stack<T>) -> Result<(), Self::Err> {
        use self::FloatOperator::*;
        match self {
            Add(_) => {
                let (a, b) = pop_two_operands(stack).unwrap();
                Ok(stack.push(a + b))
            },
            Sub(_) => {
                let (a, b) = pop_two_operands(stack).unwrap();
                Ok(stack.push(b - a))
            },
            Mul(_) => {
                let (a, b) = pop_two_operands(stack).unwrap();
                Ok(stack.push(a * b))
            },
            Div(_) => {
                let (a, b) = pop_two_operands(stack).unwrap();
                Ok(stack.push(b / a))
            },
            Rem(_) => {
                let (a, b) = pop_two_operands(stack).unwrap();
                Ok(stack.push(b % a))
            },
            Neg(_) => {
                let a = stack.pop().unwrap();
                Ok(stack.push(-a))
            },
            Sqrt(_) => {
                let a = stack.pop().unwrap();
                Ok(stack.push(a.sqrt()))
            },
            Pow(_) => {
                let (a, b) = pop_two_operands(stack).unwrap();
                Ok(stack.push(b.powf(a)))
            },
            Log2(_) => {
                let a = stack.pop().unwrap();
                Ok(stack.push(a.log2()))
            },
            Exp(_) => {
                let a = stack.pop().unwrap();
                Ok(stack.push(a.exp()))
            },
            Swap(_) => {
                let (a, b) = pop_two_operands(stack).unwrap();
                stack.push(a);
                stack.push(b);
                Ok(())
            },
            Zero(_) => Ok(stack.push(T::zero())),
            One(_) => Ok(stack.push(T::one())),
            Round(_) => {
                let a = stack.pop().unwrap();
                Ok(stack.push(a.round()))
            },
        }
    }
}

impl<'a, T: Float> TryFrom<&'a str> for FloatOperator<T> {
    type Err = (); // TODO change this
    fn try_from(expr: &'a str) -> Result<Self, Self::Err> {
        use self::FloatOperator::*;
        match expr {
            "+" => Ok(Add(PhantomData::default())),
            "-" => Ok(Sub(PhantomData::default())),
            "*" => Ok(Mul(PhantomData::default())),
            "/" => Ok(Div(PhantomData::default())),
            "%" => Ok(Rem(PhantomData::default())),
            "neg" => Ok(Neg(PhantomData::default())),
            "sqrt" => Ok(Sqrt(PhantomData::default())),
            "pow" => Ok(Pow(PhantomData::default())),
            "log2" => Ok(Log2(PhantomData::default())),
            "exp" => Ok(Exp(PhantomData::default())),
            "swap" => Ok(Swap(PhantomData::default())),
            "zero" => Ok(Zero(PhantomData::default())),
            "one" => Ok(One(PhantomData::default())),
            "round" => Ok(Round(PhantomData::default())),
            _ => Err(())
        }
    }
}

#[cfg(test)]
mod tests {
    use std::convert::TryInto;
    use expression::Expression;
    use operate::FloatOperator;

    #[test]
    fn simple_addition() {
        let expr: Expression<f32, FloatOperator<_>> = "3 4 +".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(7.0));
    }

    #[test]
    fn simple_substraction() {
        let expr: Expression<f32, FloatOperator<_>> = "4 3 -".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(1.0));
    }

    #[test]
    fn simple_multiplication() {
        let expr: Expression<f32, FloatOperator<_>> = "3 4 *".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(12.0));
    }

    #[test]
    fn simple_division() {
        let expr: Expression<f32, FloatOperator<_>> = "9 3 /".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(3.0));
    }

    #[test]
    fn simple_remaining() {
        let expr: Expression<f32, FloatOperator<_>> = "9 3 %".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(0.0));
    }

    #[test]
    fn simple_negation() {
        let expr: Expression<f32, FloatOperator<_>> = "9 neg".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(-9.0));
    }

    #[test]
    fn simple_square_root() {
        let expr: Expression<f32, FloatOperator<_>> = "9 sqrt".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(3.0));
    }

    #[test]
    fn simple_power() {
        let expr: Expression<f32, FloatOperator<_>> = "3 4 pow".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(81.0));
    }

    #[test]
    fn simple_logarithm_2() {
        let expr: Expression<f32, FloatOperator<_>> = "4 log2".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(2.0));
    }

    #[test]
    fn simple_exponential() {
        let expr: Expression<f32, FloatOperator<_>> = "0 exp".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(1.0));
    }

    #[test]
    fn simple_swap() {
        let expr: Expression<f32, FloatOperator<_>> = "2 4 swap /".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(2.0));
    }

    #[test]
    fn simple_zero() {
        let expr: Expression<f32, FloatOperator<_>> = "zero".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(0.0));
    }

    #[test]
    fn simple_one() {
        let expr: Expression<f32, FloatOperator<_>> = "one".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(1.0));
    }

    #[test]
    fn simple_round() {
        let expr: Expression<f32, FloatOperator<_>> = "3.3 round".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(3.0));
    }

    #[test]
    #[should_panic]
    fn simple_wrong_expression() {
        let _: Expression<f32, FloatOperator<_>> = "3 4 + &".try_into().unwrap();
    }
}
<commit_msg>operate: Add test for invalidity<commit_after>use std::convert::TryFrom;
use std::marker::PhantomData;
use num::Float;
use operate::Operate;
use stack::Stack;
use ::pop_two_operands;

// Add  (+)      pop 2, push 1
// Sub  (-)      pop 2, push 1
// Mul  (*)      pop 2, push 1
// Div  (/)      pop 2, push 1
// Rem  (%)      pop 2, push 1
// Neg  (neg)    pop 1, push 1
// Sqrt (sqrt)   pop 1, push 1
// Pow  (pow)    pop 1, push 1
// Log2 (log2)   pop 1, push 1
// Exp  (exp)    pop 1, push 1
// Swap (swap)   pop 2, push 2
// Zero (zero)   pop 0, push 1
// One  (zero)   pop 0, push 1
// Round (round) pop 1, push 1

#[derive(Debug, Copy, Clone)]
pub enum FloatOperator<T: Float> {
    Add(PhantomData<T>),
    Sub(PhantomData<T>),
    Mul(PhantomData<T>),
    Div(PhantomData<T>),
    Rem(PhantomData<T>),
    Neg(PhantomData<T>),
    Sqrt(PhantomData<T>),
    Pow(PhantomData<T>),
    Log2(PhantomData<T>),
    Exp(PhantomData<T>),
    Swap(PhantomData<T>),
    Zero(PhantomData<T>),
    One(PhantomData<T>),
    Round(PhantomData<T>),
}

impl<T: Float> Operate<T> for FloatOperator<T> {
    type Err = ();

    fn operands_needed(&self) -> usize {
        use self::FloatOperator::*;
        match *self {
              Add(_)
            | Sub(_)
            | Mul(_)
            | Div(_)
            | Pow(_)
            | Rem(_)
            | Swap(_) => 2,
              Neg(_)
            | Sqrt(_)
            | Log2(_)
            | Round(_)
            | Exp(_) => 1,
              Zero(_)
            | One(_) => 0,
        }
    }

    fn operands_generated(&self) -> usize {
        use self::FloatOperator::*;
        match *self {
              Add(_)
            | Sub(_)
            | Mul(_)
            | Div(_)
            | Rem(_)
            | Neg(_)
            | Sqrt(_)
            | Pow(_)
            | Log2(_)
            | Exp(_)
            | Zero(_)
            | One(_)
            | Round(_) => 1,
              Swap(_) => 2,
        }
    }

    fn operate(self, stack: &mut Stack<T>) -> Result<(), Self::Err> {
        use self::FloatOperator::*;
        match self {
            Add(_) => {
                let (a, b) = pop_two_operands(stack).unwrap();
                Ok(stack.push(a + b))
            },
            Sub(_) => {
                let (a, b) = pop_two_operands(stack).unwrap();
                Ok(stack.push(b - a))
            },
            Mul(_) => {
                let (a, b) = pop_two_operands(stack).unwrap();
                Ok(stack.push(a * b))
            },
            Div(_) => {
                let (a, b) = pop_two_operands(stack).unwrap();
                Ok(stack.push(b / a))
            },
            Rem(_) => {
                let (a, b) = pop_two_operands(stack).unwrap();
                Ok(stack.push(b % a))
            },
            Neg(_) => {
                let a = stack.pop().unwrap();
                Ok(stack.push(-a))
            },
            Sqrt(_) => {
                let a = stack.pop().unwrap();
                Ok(stack.push(a.sqrt()))
            },
            Pow(_) => {
                let (a, b) = pop_two_operands(stack).unwrap();
                Ok(stack.push(b.powf(a)))
            },
            Log2(_) => {
                let a = stack.pop().unwrap();
                Ok(stack.push(a.log2()))
            },
            Exp(_) => {
                let a = stack.pop().unwrap();
                Ok(stack.push(a.exp()))
            },
            Swap(_) => {
                let (a, b) = pop_two_operands(stack).unwrap();
                stack.push(a);
                stack.push(b);
                Ok(())
            },
            Zero(_) => Ok(stack.push(T::zero())),
            One(_) => Ok(stack.push(T::one())),
            Round(_) => {
                let a = stack.pop().unwrap();
                Ok(stack.push(a.round()))
            },
        }
    }
}

impl<'a, T: Float> TryFrom<&'a str> for FloatOperator<T> {
    type Err = (); // TODO change this
    fn try_from(expr: &'a str) -> Result<Self, Self::Err> {
        use self::FloatOperator::*;
        match expr {
            "+" => Ok(Add(PhantomData::default())),
            "-" => Ok(Sub(PhantomData::default())),
            "*" => Ok(Mul(PhantomData::default())),
            "/" => Ok(Div(PhantomData::default())),
            "%" => Ok(Rem(PhantomData::default())),
            "neg" => Ok(Neg(PhantomData::default())),
            "sqrt" => Ok(Sqrt(PhantomData::default())),
            "pow" => Ok(Pow(PhantomData::default())),
            "log2" => Ok(Log2(PhantomData::default())),
            "exp" => Ok(Exp(PhantomData::default())),
            "swap" => Ok(Swap(PhantomData::default())),
            "zero" => Ok(Zero(PhantomData::default())),
            "one" => Ok(One(PhantomData::default())),
            "round" => Ok(Round(PhantomData::default())),
            _ => Err(())
        }
    }
}

#[cfg(test)]
mod tests {
    use std::convert::TryInto;
    use expression::Expression;
    use operate::FloatOperator;

    #[test]
    #[should_panic]
    fn bad_operator() {
        let _: Expression<f32, FloatOperator<_>> = "3 4 + &".try_into().unwrap();
    }

    #[test]
    #[should_panic]
    fn too_many_operands() {
        let _: Expression<f32, FloatOperator<_>> = "3 3 4 +".try_into().unwrap();
    }

    #[test]
    #[should_panic]
    fn not_enough_operand() {
        let _: Expression<f32, FloatOperator<_>> = "4 +".try_into().unwrap();
    }

    #[test]
    fn simple_addition() {
        let expr: Expression<f32, FloatOperator<_>> = "3 4 +".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(7.0));
    }

    #[test]
    fn simple_substraction() {
        let expr: Expression<f32, FloatOperator<_>> = "4 3 -".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(1.0));
    }

    #[test]
    fn simple_multiplication() {
        let expr: Expression<f32, FloatOperator<_>> = "3 4 *".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(12.0));
    }

    #[test]
    fn simple_division() {
        let expr: Expression<f32, FloatOperator<_>> = "9 3 /".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(3.0));
    }

    #[test]
    fn simple_remaining() {
        let expr: Expression<f32, FloatOperator<_>> = "9 3 %".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(0.0));
    }

    #[test]
    fn simple_negation() {
        let expr: Expression<f32, FloatOperator<_>> = "9 neg".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(-9.0));
    }

    #[test]
    fn simple_square_root() {
        let expr: Expression<f32, FloatOperator<_>> = "9 sqrt".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(3.0));
    }

    #[test]
    fn simple_power() {
        let expr: Expression<f32, FloatOperator<_>> = "3 4 pow".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(81.0));
    }

    #[test]
    fn simple_logarithm_2() {
        let expr: Expression<f32, FloatOperator<_>> = "4 log2".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(2.0));
    }

    #[test]
    fn simple_exponential() {
        let expr: Expression<f32, FloatOperator<_>> = "0 exp".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(1.0));
    }

    #[test]
    fn simple_swap() {
        let expr: Expression<f32, FloatOperator<_>> = "2 4 swap /".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(2.0));
    }

    #[test]
    fn simple_zero() {
        let expr: Expression<f32, FloatOperator<_>> = "zero".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(0.0));
    }

    #[test]
    fn simple_one() {
        let expr: Expression<f32, FloatOperator<_>> = "one".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(1.0));
    }

    #[test]
    fn simple_round() {
        let expr: Expression<f32, FloatOperator<_>> = "3.3 round".try_into().unwrap();
        assert_eq!(expr.operate(), Ok(3.0));
    }
}
<|endoftext|>


<commit_before>//! This module contains the `InterpCx` methods for executing a single step of the interpreter.
//!
//! The main entry point is the `step` method.

use rustc_middle::mir;
use rustc_middle::mir::interpret::{InterpResult, Scalar};
use rustc_middle::ty::layout::LayoutOf;

use super::{InterpCx, Machine};

/// Classify whether an operator is "left-homogeneous", i.e., the LHS has the
/// same type as the result.
#[inline]
fn binop_left_homogeneous(op: mir::BinOp) -> bool {
    use rustc_middle::mir::BinOp::*;
    match op {
        Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Offset | Shl | Shr => true,
        Eq | Ne | Lt | Le | Gt | Ge => false,
    }
}
/// Classify whether an operator is "right-homogeneous", i.e., the RHS has the
/// same type as the LHS.
#[inline]
fn binop_right_homogeneous(op: mir::BinOp) -> bool {
    use rustc_middle::mir::BinOp::*;
    match op {
        Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Eq | Ne | Lt | Le | Gt | Ge => true,
        Offset | Shl | Shr => false,
    }
}

impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
    pub fn run(&mut self) -> InterpResult<'tcx> {
        while self.step()? {}
        Ok(())
    }

    /// Returns `true` as long as there are more things to do.
    ///
    /// This is used by [priroda](https://github.com/oli-obk/priroda)
    ///
    /// This is marked `#inline(always)` to work around adverserial codegen when `opt-level = 3`
    #[inline(always)]
    pub fn step(&mut self) -> InterpResult<'tcx, bool> {
        if self.stack().is_empty() {
            return Ok(false);
        }

        let loc = match self.frame().loc {
            Ok(loc) => loc,
            Err(_) => {
                // We are unwinding and this fn has no cleanup code.
                // Just go on unwinding.
                trace!("unwinding: skipping frame");
                self.pop_stack_frame(/* unwinding */ true)?;
                return Ok(true);
            }
        };
        let basic_block = &self.body().basic_blocks()[loc.block];

        let old_frames = self.frame_idx();

        if let Some(stmt) = basic_block.statements.get(loc.statement_index) {
            assert_eq!(old_frames, self.frame_idx());
            self.statement(stmt)?;
            return Ok(true);
        }

        M::before_terminator(self)?;

        let terminator = basic_block.terminator();
        assert_eq!(old_frames, self.frame_idx());
        self.terminator(terminator)?;
        Ok(true)
    }

    /// Runs the interpretation logic for the given `mir::Statement` at the current frame and
    /// statement counter. This also moves the statement counter forward.
    pub fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
        info!("{:?}", stmt);

        use rustc_middle::mir::StatementKind::*;

        // Some statements (e.g., box) push new stack frames.
        // We have to record the stack frame number *before* executing the statement.
        let frame_idx = self.frame_idx();

        match &stmt.kind {
            Assign(box (place, rvalue)) => self.eval_rvalue_into_place(rvalue, *place)?,

            SetDiscriminant { place, variant_index } => {
                let dest = self.eval_place(**place)?;
                self.write_discriminant(*variant_index, &dest)?;
            }

            // Mark locals as alive
            StorageLive(local) => {
                self.storage_live(*local)?;
            }

            // Mark locals as dead
            StorageDead(local) => {
                self.storage_dead(*local)?;
            }

            // No dynamic semantics attached to `FakeRead`; MIR
            // interpreter is solely intended for borrowck'ed code.
            FakeRead(..) => {}

            // Stacked Borrows.
            Retag(kind, place) => {
                let dest = self.eval_place(**place)?;
                M::retag(self, *kind, &dest)?;
            }

            // Call CopyNonOverlapping
            CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { src, dst, count }) => {
                let src = self.eval_operand(src, None)?;
                let dst = self.eval_operand(dst, None)?;
                let count = self.eval_operand(count, None)?;
                self.copy_intrinsic(&src, &dst, &count, /* nonoverlapping */ true)?;
            }

            // Statements we do not track.
            AscribeUserType(..) => {}

            // Currently, Miri discards Coverage statements. Coverage statements are only injected
            // via an optional compile time MIR pass and have no side effects. Since Coverage
            // statements don't exist at the source level, it is safe for Miri to ignore them, even
            // for undefined behavior (UB) checks.
            //
            // A coverage counter inside a const expression (for example, a counter injected in a
            // const function) is discarded when the const is evaluated at compile time. Whether
            // this should change, and/or how to implement a const eval counter, is a subject of the
            // following issue:
            //
            // FIXME(#73156): Handle source code coverage in const eval
            Coverage(..) => {}

            // Defined to do nothing. These are added by optimization passes, to avoid changing the
            // size of MIR constantly.
            Nop => {}

            LlvmInlineAsm { .. } => throw_unsup_format!("inline assembly is not supported"),
        }

        self.stack_mut()[frame_idx].loc.as_mut().unwrap().statement_index += 1;
        Ok(())
    }

    /// Evaluate an assignment statement.
    ///
    /// There is no separate `eval_rvalue` function. Instead, the code for handling each rvalue
    /// type writes its results directly into the memory specified by the place.
    pub fn eval_rvalue_into_place(
        &mut self,
        rvalue: &mir::Rvalue<'tcx>,
        place: mir::Place<'tcx>,
    ) -> InterpResult<'tcx> {
        let dest = self.eval_place(place)?;

        use rustc_middle::mir::Rvalue::*;
        match *rvalue {
            ThreadLocalRef(did) => {
                let ptr = M::thread_local_static_base_pointer(self, did)?;
                self.write_pointer(ptr, &dest)?;
            }

            Use(ref operand) => {
                // Avoid recomputing the layout
                let op = self.eval_operand(operand, Some(dest.layout))?;
                self.copy_op(&op, &dest)?;
            }

            BinaryOp(bin_op, box (ref left, ref right)) => {
                let layout = binop_left_homogeneous(bin_op).then_some(dest.layout);
                let left = self.read_immediate(&self.eval_operand(left, layout)?)?;
                let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
                let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
                self.binop_ignore_overflow(bin_op, &left, &right, &dest)?;
            }

            CheckedBinaryOp(bin_op, box (ref left, ref right)) => {
                // Due to the extra boolean in the result, we can never reuse the `dest.layout`.
                let left = self.read_immediate(&self.eval_operand(left, None)?)?;
                let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
                let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
                self.binop_with_overflow(bin_op, &left, &right, &dest)?;
            }

            UnaryOp(un_op, ref operand) => {
                // The operand always has the same type as the result.
                let val = self.read_immediate(&self.eval_operand(operand, Some(dest.layout))?)?;
                let val = self.unary_op(un_op, &val)?;
                assert_eq!(val.layout, dest.layout, "layout mismatch for result of {:?}", un_op);
                self.write_immediate(*val, &dest)?;
            }

            Aggregate(ref kind, ref operands) => {
                let (dest, active_field_index) = match **kind {
                    mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
                        self.write_discriminant(variant_index, &dest)?;
                        if adt_def.is_enum() {
                            (self.place_downcast(&dest, variant_index)?, active_field_index)
                        } else {
                            (dest, active_field_index)
                        }
                    }
                    _ => (dest, None),
                };

                for (i, operand) in operands.iter().enumerate() {
                    let op = self.eval_operand(operand, None)?;
                    // Ignore zero-sized fields.
                    if !op.layout.is_zst() {
                        let field_index = active_field_index.unwrap_or(i);
                        let field_dest = self.place_field(&dest, field_index)?;
                        self.copy_op(&op, &field_dest)?;
                    }
                }
            }

            Repeat(ref operand, _) => {
                let src = self.eval_operand(operand, None)?;
                assert!(!src.layout.is_unsized());
                let dest = self.force_allocation(&dest)?;
                let length = dest.len(self)?;

                if length == 0 {
                    // Nothing to copy... but let's still make sure that `dest` as a place is valid.
                    self.get_alloc_mut(&dest)?;
                } else {
                    // Write the src to the first element.
                    let first = self.mplace_field(&dest, 0)?;
                    self.copy_op(&src, &first.into())?;

                    // This is performance-sensitive code for big static/const arrays! So we
                    // avoid writing each operand individually and instead just make many copies
                    // of the first element.
                    let elem_size = first.layout.size;
                    let first_ptr = first.ptr;
                    let rest_ptr = first_ptr.offset(elem_size, self)?;
                    self.memory.copy_repeatedly(
                        first_ptr,
                        first.align,
                        rest_ptr,
                        first.align,
                        elem_size,
                        length - 1,
                        /*nonoverlapping:*/ true,
                    )?;
                }
            }

            Len(place) => {
                let src = self.eval_place(place)?;
                let mplace = self.force_allocation(&src)?;
                let len = mplace.len(self)?;
                self.write_scalar(Scalar::from_machine_usize(len, self), &dest)?;
            }

            AddressOf(_, place) | Ref(_, _, place) => {
                let src = self.eval_place(place)?;
                let place = self.force_allocation(&src)?;
                self.write_immediate(place.to_ref(self), &dest)?;
            }

            NullaryOp(mir::NullOp::Box, _) => {
                M::box_alloc(self, &dest)?;
            }

            NullaryOp(null_op, ty) => {
                let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty);
                let layout = self.layout_of(ty)?;
                if layout.is_unsized() {
                    // FIXME: This should be a span_bug (#80742)
                    self.tcx.sess.delay_span_bug(
                        self.frame().current_span(),
                        &format!("Nullary MIR operator called for unsized type {}", ty),
                    );
                    throw_inval!(SizeOfUnsizedType(ty));
                }
                let val = match null_op {
                    mir::NullOp::SizeOf => layout.size.bytes(),
                    mir::NullOp::AlignOf => layout.align.abi.bytes(),
                    mir::NullOp::Box => unreachable!(),
                };
                self.write_scalar(Scalar::from_machine_usize(val, self), &dest)?;
            }

            ShallowInitBox(ref operand, _) => {
                let src = self.eval_operand(operand, None)?;
                let v = self.read_immediate(&src)?;
                self.write_immediate(*v, &dest)?;
            }

            Cast(cast_kind, ref operand, cast_ty) => {
                let src = self.eval_operand(operand, None)?;
                let cast_ty = self.subst_from_current_frame_and_normalize_erasing_regions(cast_ty);
                self.cast(&src, cast_kind, cast_ty, &dest)?;
            }

            Discriminant(place) => {
                let op = self.eval_place_to_op(place, None)?;
                let discr_val = self.read_discriminant(&op)?.0;
                self.write_scalar(discr_val, &dest)?;
            }
        }

        trace!("{:?}", self.dump_place(*dest));

        Ok(())
    }

    fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> {
        info!("{:?}", terminator.kind);

        self.eval_terminator(terminator)?;
        if !self.stack().is_empty() {
            if let Ok(loc) = self.frame().loc {
                info!("// executing {:?}", loc.block);
            }
        }
        Ok(())
    }
}
<commit_msg>CTFE: extra assertions for Aggregate rvalues; remove unnecessarily eager special case<commit_after>//! This module contains the `InterpCx` methods for executing a single step of the interpreter.
//!
//! The main entry point is the `step` method.

use rustc_middle::mir;
use rustc_middle::mir::interpret::{InterpResult, Scalar};
use rustc_middle::ty::layout::LayoutOf;

use super::{InterpCx, Machine};

/// Classify whether an operator is "left-homogeneous", i.e., the LHS has the
/// same type as the result.
#[inline]
fn binop_left_homogeneous(op: mir::BinOp) -> bool {
    use rustc_middle::mir::BinOp::*;
    match op {
        Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Offset | Shl | Shr => true,
        Eq | Ne | Lt | Le | Gt | Ge => false,
    }
}
/// Classify whether an operator is "right-homogeneous", i.e., the RHS has the
/// same type as the LHS.
#[inline]
fn binop_right_homogeneous(op: mir::BinOp) -> bool {
    use rustc_middle::mir::BinOp::*;
    match op {
        Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Eq | Ne | Lt | Le | Gt | Ge => true,
        Offset | Shl | Shr => false,
    }
}

impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
    pub fn run(&mut self) -> InterpResult<'tcx> {
        while self.step()? {}
        Ok(())
    }

    /// Returns `true` as long as there are more things to do.
    ///
    /// This is used by [priroda](https://github.com/oli-obk/priroda)
    ///
    /// This is marked `#inline(always)` to work around adverserial codegen when `opt-level = 3`
    #[inline(always)]
    pub fn step(&mut self) -> InterpResult<'tcx, bool> {
        if self.stack().is_empty() {
            return Ok(false);
        }

        let loc = match self.frame().loc {
            Ok(loc) => loc,
            Err(_) => {
                // We are unwinding and this fn has no cleanup code.
                // Just go on unwinding.
                trace!("unwinding: skipping frame");
                self.pop_stack_frame(/* unwinding */ true)?;
                return Ok(true);
            }
        };
        let basic_block = &self.body().basic_blocks()[loc.block];

        let old_frames = self.frame_idx();

        if let Some(stmt) = basic_block.statements.get(loc.statement_index) {
            assert_eq!(old_frames, self.frame_idx());
            self.statement(stmt)?;
            return Ok(true);
        }

        M::before_terminator(self)?;

        let terminator = basic_block.terminator();
        assert_eq!(old_frames, self.frame_idx());
        self.terminator(terminator)?;
        Ok(true)
    }

    /// Runs the interpretation logic for the given `mir::Statement` at the current frame and
    /// statement counter. This also moves the statement counter forward.
    pub fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
        info!("{:?}", stmt);

        use rustc_middle::mir::StatementKind::*;

        // Some statements (e.g., box) push new stack frames.
        // We have to record the stack frame number *before* executing the statement.
        let frame_idx = self.frame_idx();

        match &stmt.kind {
            Assign(box (place, rvalue)) => self.eval_rvalue_into_place(rvalue, *place)?,

            SetDiscriminant { place, variant_index } => {
                let dest = self.eval_place(**place)?;
                self.write_discriminant(*variant_index, &dest)?;
            }

            // Mark locals as alive
            StorageLive(local) => {
                self.storage_live(*local)?;
            }

            // Mark locals as dead
            StorageDead(local) => {
                self.storage_dead(*local)?;
            }

            // No dynamic semantics attached to `FakeRead`; MIR
            // interpreter is solely intended for borrowck'ed code.
            FakeRead(..) => {}

            // Stacked Borrows.
            Retag(kind, place) => {
                let dest = self.eval_place(**place)?;
                M::retag(self, *kind, &dest)?;
            }

            // Call CopyNonOverlapping
            CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { src, dst, count }) => {
                let src = self.eval_operand(src, None)?;
                let dst = self.eval_operand(dst, None)?;
                let count = self.eval_operand(count, None)?;
                self.copy_intrinsic(&src, &dst, &count, /* nonoverlapping */ true)?;
            }

            // Statements we do not track.
            AscribeUserType(..) => {}

            // Currently, Miri discards Coverage statements. Coverage statements are only injected
            // via an optional compile time MIR pass and have no side effects. Since Coverage
            // statements don't exist at the source level, it is safe for Miri to ignore them, even
            // for undefined behavior (UB) checks.
            //
            // A coverage counter inside a const expression (for example, a counter injected in a
            // const function) is discarded when the const is evaluated at compile time. Whether
            // this should change, and/or how to implement a const eval counter, is a subject of the
            // following issue:
            //
            // FIXME(#73156): Handle source code coverage in const eval
            Coverage(..) => {}

            // Defined to do nothing. These are added by optimization passes, to avoid changing the
            // size of MIR constantly.
            Nop => {}

            LlvmInlineAsm { .. } => throw_unsup_format!("inline assembly is not supported"),
        }

        self.stack_mut()[frame_idx].loc.as_mut().unwrap().statement_index += 1;
        Ok(())
    }

    /// Evaluate an assignment statement.
    ///
    /// There is no separate `eval_rvalue` function. Instead, the code for handling each rvalue
    /// type writes its results directly into the memory specified by the place.
    pub fn eval_rvalue_into_place(
        &mut self,
        rvalue: &mir::Rvalue<'tcx>,
        place: mir::Place<'tcx>,
    ) -> InterpResult<'tcx> {
        let dest = self.eval_place(place)?;

        use rustc_middle::mir::Rvalue::*;
        match *rvalue {
            ThreadLocalRef(did) => {
                let ptr = M::thread_local_static_base_pointer(self, did)?;
                self.write_pointer(ptr, &dest)?;
            }

            Use(ref operand) => {
                // Avoid recomputing the layout
                let op = self.eval_operand(operand, Some(dest.layout))?;
                self.copy_op(&op, &dest)?;
            }

            BinaryOp(bin_op, box (ref left, ref right)) => {
                let layout = binop_left_homogeneous(bin_op).then_some(dest.layout);
                let left = self.read_immediate(&self.eval_operand(left, layout)?)?;
                let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
                let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
                self.binop_ignore_overflow(bin_op, &left, &right, &dest)?;
            }

            CheckedBinaryOp(bin_op, box (ref left, ref right)) => {
                // Due to the extra boolean in the result, we can never reuse the `dest.layout`.
                let left = self.read_immediate(&self.eval_operand(left, None)?)?;
                let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
                let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
                self.binop_with_overflow(bin_op, &left, &right, &dest)?;
            }

            UnaryOp(un_op, ref operand) => {
                // The operand always has the same type as the result.
                let val = self.read_immediate(&self.eval_operand(operand, Some(dest.layout))?)?;
                let val = self.unary_op(un_op, &val)?;
                assert_eq!(val.layout, dest.layout, "layout mismatch for result of {:?}", un_op);
                self.write_immediate(*val, &dest)?;
            }

            Aggregate(ref kind, ref operands) => {
                // active_field_index is for union initialization.
                let (dest, active_field_index) = match **kind {
                    mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
                        self.write_discriminant(variant_index, &dest)?;
                        if adt_def.is_enum() {
                            assert!(active_field_index.is_none());
                            (self.place_downcast(&dest, variant_index)?, None)
                        } else {
                            if active_field_index.is_some() {
                                assert_eq!(operands.len(), 1);
                            }
                            (dest, active_field_index)
                        }
                    }
                    _ => (dest, None),
                };

                for (i, operand) in operands.iter().enumerate() {
                    let op = self.eval_operand(operand, None)?;
                    let field_index = active_field_index.unwrap_or(i);
                    let field_dest = self.place_field(&dest, field_index)?;
                    self.copy_op(&op, &field_dest)?;
                }
            }

            Repeat(ref operand, _) => {
                let src = self.eval_operand(operand, None)?;
                assert!(!src.layout.is_unsized());
                let dest = self.force_allocation(&dest)?;
                let length = dest.len(self)?;

                if length == 0 {
                    // Nothing to copy... but let's still make sure that `dest` as a place is valid.
                    self.get_alloc_mut(&dest)?;
                } else {
                    // Write the src to the first element.
                    let first = self.mplace_field(&dest, 0)?;
                    self.copy_op(&src, &first.into())?;

                    // This is performance-sensitive code for big static/const arrays! So we
                    // avoid writing each operand individually and instead just make many copies
                    // of the first element.
                    let elem_size = first.layout.size;
                    let first_ptr = first.ptr;
                    let rest_ptr = first_ptr.offset(elem_size, self)?;
                    self.memory.copy_repeatedly(
                        first_ptr,
                        first.align,
                        rest_ptr,
                        first.align,
                        elem_size,
                        length - 1,
                        /*nonoverlapping:*/ true,
                    )?;
                }
            }

            Len(place) => {
                let src = self.eval_place(place)?;
                let mplace = self.force_allocation(&src)?;
                let len = mplace.len(self)?;
                self.write_scalar(Scalar::from_machine_usize(len, self), &dest)?;
            }

            AddressOf(_, place) | Ref(_, _, place) => {
                let src = self.eval_place(place)?;
                let place = self.force_allocation(&src)?;
                self.write_immediate(place.to_ref(self), &dest)?;
            }

            NullaryOp(mir::NullOp::Box, _) => {
                M::box_alloc(self, &dest)?;
            }

            NullaryOp(null_op, ty) => {
                let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty);
                let layout = self.layout_of(ty)?;
                if layout.is_unsized() {
                    // FIXME: This should be a span_bug (#80742)
                    self.tcx.sess.delay_span_bug(
                        self.frame().current_span(),
                        &format!("Nullary MIR operator called for unsized type {}", ty),
                    );
                    throw_inval!(SizeOfUnsizedType(ty));
                }
                let val = match null_op {
                    mir::NullOp::SizeOf => layout.size.bytes(),
                    mir::NullOp::AlignOf => layout.align.abi.bytes(),
                    mir::NullOp::Box => unreachable!(),
                };
                self.write_scalar(Scalar::from_machine_usize(val, self), &dest)?;
            }

            ShallowInitBox(ref operand, _) => {
                let src = self.eval_operand(operand, None)?;
                let v = self.read_immediate(&src)?;
                self.write_immediate(*v, &dest)?;
            }

            Cast(cast_kind, ref operand, cast_ty) => {
                let src = self.eval_operand(operand, None)?;
                let cast_ty = self.subst_from_current_frame_and_normalize_erasing_regions(cast_ty);
                self.cast(&src, cast_kind, cast_ty, &dest)?;
            }

            Discriminant(place) => {
                let op = self.eval_place_to_op(place, None)?;
                let discr_val = self.read_discriminant(&op)?.0;
                self.write_scalar(discr_val, &dest)?;
            }
        }

        trace!("{:?}", self.dump_place(*dest));

        Ok(())
    }

    fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> {
        info!("{:?}", terminator.kind);

        self.eval_terminator(terminator)?;
        if !self.stack().is_empty() {
            if let Ok(loc) = self.frame().loc {
                info!("// executing {:?}", loc.block);
            }
        }
        Ok(())
    }
}
<|endoftext|>


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

//! CSS handling for the [`basic-shape`](https://drafts.csswg.org/css-shapes/#typedef-basic-shape)
//! types that are generic over their `ToCss` implementations.

use std::fmt;
use style_traits::{HasViewportPercentage, ToCss};
use values::animated::{Animate, Procedure, ToAnimatedZero};
use values::computed::ComputedValueAsSpecified;
use values::distance::{ComputeSquaredDistance, SquaredDistance};
use values::generics::border::BorderRadius;
use values::generics::position::Position;
use values::generics::rect::Rect;

/// A clipping shape, for `clip-path`.
pub type ClippingShape<BasicShape, Url> = ShapeSource<BasicShape, GeometryBox, Url>;

/// https://drafts.fxtf.org/css-masking-1/#typedef-geometry-box
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Copy, Debug, PartialEq, ToCss)]
pub enum GeometryBox {
    FillBox,
    StrokeBox,
    ViewBox,
    ShapeBox(ShapeBox),
}
impl ComputedValueAsSpecified for GeometryBox {}

/// A float area shape, for `shape-outside`.
pub type FloatAreaShape<BasicShape, Url> = ShapeSource<BasicShape, ShapeBox, Url>;

// https://drafts.csswg.org/css-shapes-1/#typedef-shape-box
define_css_keyword_enum!(ShapeBox:
    "margin-box" => MarginBox,
    "border-box" => BorderBox,
    "padding-box" => PaddingBox,
    "content-box" => ContentBox
);
add_impls_for_keyword_enum!(ShapeBox);

/// A shape source, for some reference box.
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Debug, PartialEq, ToComputedValue, ToCss)]
pub enum ShapeSource<BasicShape, ReferenceBox, Url> {
    Url(Url),
    Shape(BasicShape, Option<ReferenceBox>),
    Box(ReferenceBox),
    None,
}

#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Animate, Clone, ComputeSquaredDistance, Debug, PartialEq)]
#[derive(ToComputedValue, ToCss)]
pub enum BasicShape<H, V, LengthOrPercentage> {
    Inset(InsetRect<LengthOrPercentage>),
    Circle(Circle<H, V, LengthOrPercentage>),
    Ellipse(Ellipse<H, V, LengthOrPercentage>),
    Polygon(Polygon<LengthOrPercentage>),
}

/// https://drafts.csswg.org/css-shapes/#funcdef-inset
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Animate, Clone, ComputeSquaredDistance, Debug, PartialEq, ToComputedValue)]
pub struct InsetRect<LengthOrPercentage> {
    pub rect: Rect<LengthOrPercentage>,
    pub round: Option<BorderRadius<LengthOrPercentage>>,
}

/// https://drafts.csswg.org/css-shapes/#funcdef-circle
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToComputedValue)]
pub struct Circle<H, V, LengthOrPercentage> {
    pub position: Position<H, V>,
    pub radius: ShapeRadius<LengthOrPercentage>,
}

/// https://drafts.csswg.org/css-shapes/#funcdef-ellipse
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToComputedValue)]
pub struct Ellipse<H, V, LengthOrPercentage> {
    pub position: Position<H, V>,
    pub semiaxis_x: ShapeRadius<LengthOrPercentage>,
    pub semiaxis_y: ShapeRadius<LengthOrPercentage>,
}

/// https://drafts.csswg.org/css-shapes/#typedef-shape-radius
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToComputedValue, ToCss)]
pub enum ShapeRadius<LengthOrPercentage> {
    Length(LengthOrPercentage),
    ClosestSide,
    FarthestSide,
}

#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Debug, PartialEq, ToComputedValue)]
/// A generic type for representing the `polygon()` function
///
/// https://drafts.csswg.org/css-shapes/#funcdef-polygon
pub struct Polygon<LengthOrPercentage> {
    /// The filling rule for a polygon.
    pub fill: FillRule,
    /// A collection of (x, y) coordinates to draw the polygon.
    pub coordinates: Vec<(LengthOrPercentage, LengthOrPercentage)>,
}

// https://drafts.csswg.org/css-shapes/#typedef-fill-rule
// NOTE: Basic shapes spec says that these are the only two values, however
// https://www.w3.org/TR/SVG/painting.html#FillRuleProperty
// says that it can also be `inherit`
define_css_keyword_enum!(FillRule:
    "nonzero" => NonZero,
    "evenodd" => EvenOdd
);
add_impls_for_keyword_enum!(FillRule);

// FIXME(nox): This should be derivable, but we need to implement Animate
// on the T types.
impl<B, T, U> Animate for ShapeSource<B, T, U>
where
    B: Animate,
    T: Clone + PartialEq,
{
    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
        match (self, other) {
            (
                &ShapeSource::Shape(ref this, ref this_box),
                &ShapeSource::Shape(ref other, ref other_box),
            ) if this_box == other_box => {
                Ok(ShapeSource::Shape(
                    this.animate(other, procedure)?,
                    this_box.clone(),
                ))
            },
            _ => Err(()),
        }
    }
}

// FIXME(nox): Implement ComputeSquaredDistance for T types and stop
// using PartialEq here, this will let us derive this impl.
impl<B, T, U> ComputeSquaredDistance for ShapeSource<B, T, U>
where
    B: ComputeSquaredDistance,
    T: PartialEq,
{
    fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
        match (self, other) {
            (
                &ShapeSource::Shape(ref this, ref this_box),
                &ShapeSource::Shape(ref other, ref other_box),
            ) if this_box == other_box => {
                this.compute_squared_distance(other)
            },
            _ => Err(()),
        }
    }
}

impl<B, T, U> ToAnimatedZero for ShapeSource<B, T, U> {
    fn to_animated_zero(&self) -> Result<Self, ()> {
        Err(())
    }
}

impl<B, T, U> HasViewportPercentage for ShapeSource<B, T, U> {
    #[inline]
    fn has_viewport_percentage(&self) -> bool { false }
}

impl<L> ToCss for InsetRect<L>
    where L: ToCss + PartialEq
{
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        dest.write_str("inset(")?;
        self.rect.to_css(dest)?;
        if let Some(ref radius) = self.round {
            dest.write_str(" round ")?;
            radius.to_css(dest)?;
        }
        dest.write_str(")")
    }
}

impl<L> Animate for ShapeRadius<L>
where
    L: Animate,
{
    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
        match (self, other) {
            (&ShapeRadius::Length(ref this), &ShapeRadius::Length(ref other)) => {
                Ok(ShapeRadius::Length(this.animate(other, procedure)?))
            },
            _ => Err(()),
        }
    }
}

impl<L> Default for ShapeRadius<L> {
    #[inline]
    fn default() -> Self { ShapeRadius::ClosestSide }
}

impl<L> Animate for Polygon<L>
where
    L: Animate,
{
    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
        if self.fill != other.fill {
            return Err(());
        }
        if self.coordinates.len() != other.coordinates.len() {
            return Err(());
        }
        let coordinates = self.coordinates.iter().zip(other.coordinates.iter()).map(|(this, other)| {
            Ok((
                this.0.animate(&other.0, procedure)?,
                this.1.animate(&other.1, procedure)?,
            ))
        }).collect::<Result<Vec<_>, _>>()?;
        Ok(Polygon { fill: self.fill, coordinates })
    }
}

impl<L> ComputeSquaredDistance for Polygon<L>
where
    L: ComputeSquaredDistance,
{
    fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
        if self.fill != other.fill {
            return Err(());
        }
        if self.coordinates.len() != other.coordinates.len() {
            return Err(());
        }
        self.coordinates.iter().zip(other.coordinates.iter()).map(|(this, other)| {
            Ok(
                this.0.compute_squared_distance(&other.0)? +
                this.1.compute_squared_distance(&other.1)?,
            )
        }).sum()
    }
}

impl<L: ToCss> ToCss for Polygon<L> {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        dest.write_str("polygon(")?;
        if self.fill != FillRule::default() {
            self.fill.to_css(dest)?;
            dest.write_str(", ")?;
        }

        for (i, coord) in self.coordinates.iter().enumerate() {
            if i > 0 {
                dest.write_str(", ")?;
            }

            coord.0.to_css(dest)?;
            dest.write_str(" ")?;
            coord.1.to_css(dest)?;
        }

        dest.write_str(")")
    }
}

impl Default for FillRule {
    #[inline]
    fn default() -> Self { FillRule::NonZero }
}
<commit_msg>Derive Animate for ShapeRadius<L><commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! CSS handling for the [`basic-shape`](https://drafts.csswg.org/css-shapes/#typedef-basic-shape)
//! types that are generic over their `ToCss` implementations.

use std::fmt;
use style_traits::{HasViewportPercentage, ToCss};
use values::animated::{Animate, Procedure, ToAnimatedZero};
use values::computed::ComputedValueAsSpecified;
use values::distance::{ComputeSquaredDistance, SquaredDistance};
use values::generics::border::BorderRadius;
use values::generics::position::Position;
use values::generics::rect::Rect;

/// A clipping shape, for `clip-path`.
pub type ClippingShape<BasicShape, Url> = ShapeSource<BasicShape, GeometryBox, Url>;

/// https://drafts.fxtf.org/css-masking-1/#typedef-geometry-box
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Copy, Debug, PartialEq, ToCss)]
pub enum GeometryBox {
    FillBox,
    StrokeBox,
    ViewBox,
    ShapeBox(ShapeBox),
}
impl ComputedValueAsSpecified for GeometryBox {}

/// A float area shape, for `shape-outside`.
pub type FloatAreaShape<BasicShape, Url> = ShapeSource<BasicShape, ShapeBox, Url>;

// https://drafts.csswg.org/css-shapes-1/#typedef-shape-box
define_css_keyword_enum!(ShapeBox:
    "margin-box" => MarginBox,
    "border-box" => BorderBox,
    "padding-box" => PaddingBox,
    "content-box" => ContentBox
);
add_impls_for_keyword_enum!(ShapeBox);

/// A shape source, for some reference box.
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Debug, PartialEq, ToComputedValue, ToCss)]
pub enum ShapeSource<BasicShape, ReferenceBox, Url> {
    Url(Url),
    Shape(BasicShape, Option<ReferenceBox>),
    Box(ReferenceBox),
    None,
}

#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Animate, Clone, ComputeSquaredDistance, Debug, PartialEq)]
#[derive(ToComputedValue, ToCss)]
pub enum BasicShape<H, V, LengthOrPercentage> {
    Inset(InsetRect<LengthOrPercentage>),
    Circle(Circle<H, V, LengthOrPercentage>),
    Ellipse(Ellipse<H, V, LengthOrPercentage>),
    Polygon(Polygon<LengthOrPercentage>),
}

/// https://drafts.csswg.org/css-shapes/#funcdef-inset
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Animate, Clone, ComputeSquaredDistance, Debug, PartialEq, ToComputedValue)]
pub struct InsetRect<LengthOrPercentage> {
    pub rect: Rect<LengthOrPercentage>,
    pub round: Option<BorderRadius<LengthOrPercentage>>,
}

/// https://drafts.csswg.org/css-shapes/#funcdef-circle
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToComputedValue)]
pub struct Circle<H, V, LengthOrPercentage> {
    pub position: Position<H, V>,
    pub radius: ShapeRadius<LengthOrPercentage>,
}

/// https://drafts.csswg.org/css-shapes/#funcdef-ellipse
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToComputedValue)]
pub struct Ellipse<H, V, LengthOrPercentage> {
    pub position: Position<H, V>,
    pub semiaxis_x: ShapeRadius<LengthOrPercentage>,
    pub semiaxis_y: ShapeRadius<LengthOrPercentage>,
}

/// https://drafts.csswg.org/css-shapes/#typedef-shape-radius
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq)]
#[derive(ToComputedValue, ToCss)]
pub enum ShapeRadius<LengthOrPercentage> {
    Length(LengthOrPercentage),
    #[animation(error)]
    ClosestSide,
    #[animation(error)]
    FarthestSide,
}

#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Debug, PartialEq, ToComputedValue)]
/// A generic type for representing the `polygon()` function
///
/// https://drafts.csswg.org/css-shapes/#funcdef-polygon
pub struct Polygon<LengthOrPercentage> {
    /// The filling rule for a polygon.
    pub fill: FillRule,
    /// A collection of (x, y) coordinates to draw the polygon.
    pub coordinates: Vec<(LengthOrPercentage, LengthOrPercentage)>,
}

// https://drafts.csswg.org/css-shapes/#typedef-fill-rule
// NOTE: Basic shapes spec says that these are the only two values, however
// https://www.w3.org/TR/SVG/painting.html#FillRuleProperty
// says that it can also be `inherit`
define_css_keyword_enum!(FillRule:
    "nonzero" => NonZero,
    "evenodd" => EvenOdd
);
add_impls_for_keyword_enum!(FillRule);

// FIXME(nox): This should be derivable, but we need to implement Animate
// on the T types.
impl<B, T, U> Animate for ShapeSource<B, T, U>
where
    B: Animate,
    T: Clone + PartialEq,
{
    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
        match (self, other) {
            (
                &ShapeSource::Shape(ref this, ref this_box),
                &ShapeSource::Shape(ref other, ref other_box),
            ) if this_box == other_box => {
                Ok(ShapeSource::Shape(
                    this.animate(other, procedure)?,
                    this_box.clone(),
                ))
            },
            _ => Err(()),
        }
    }
}

// FIXME(nox): Implement ComputeSquaredDistance for T types and stop
// using PartialEq here, this will let us derive this impl.
impl<B, T, U> ComputeSquaredDistance for ShapeSource<B, T, U>
where
    B: ComputeSquaredDistance,
    T: PartialEq,
{
    fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
        match (self, other) {
            (
                &ShapeSource::Shape(ref this, ref this_box),
                &ShapeSource::Shape(ref other, ref other_box),
            ) if this_box == other_box => {
                this.compute_squared_distance(other)
            },
            _ => Err(()),
        }
    }
}

impl<B, T, U> ToAnimatedZero for ShapeSource<B, T, U> {
    fn to_animated_zero(&self) -> Result<Self, ()> {
        Err(())
    }
}

impl<B, T, U> HasViewportPercentage for ShapeSource<B, T, U> {
    #[inline]
    fn has_viewport_percentage(&self) -> bool { false }
}

impl<L> ToCss for InsetRect<L>
    where L: ToCss + PartialEq
{
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        dest.write_str("inset(")?;
        self.rect.to_css(dest)?;
        if let Some(ref radius) = self.round {
            dest.write_str(" round ")?;
            radius.to_css(dest)?;
        }
        dest.write_str(")")
    }
}

impl<L> Default for ShapeRadius<L> {
    #[inline]
    fn default() -> Self { ShapeRadius::ClosestSide }
}

impl<L> Animate for Polygon<L>
where
    L: Animate,
{
    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
        if self.fill != other.fill {
            return Err(());
        }
        if self.coordinates.len() != other.coordinates.len() {
            return Err(());
        }
        let coordinates = self.coordinates.iter().zip(other.coordinates.iter()).map(|(this, other)| {
            Ok((
                this.0.animate(&other.0, procedure)?,
                this.1.animate(&other.1, procedure)?,
            ))
        }).collect::<Result<Vec<_>, _>>()?;
        Ok(Polygon { fill: self.fill, coordinates })
    }
}

impl<L> ComputeSquaredDistance for Polygon<L>
where
    L: ComputeSquaredDistance,
{
    fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
        if self.fill != other.fill {
            return Err(());
        }
        if self.coordinates.len() != other.coordinates.len() {
            return Err(());
        }
        self.coordinates.iter().zip(other.coordinates.iter()).map(|(this, other)| {
            Ok(
                this.0.compute_squared_distance(&other.0)? +
                this.1.compute_squared_distance(&other.1)?,
            )
        }).sum()
    }
}

impl<L: ToCss> ToCss for Polygon<L> {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        dest.write_str("polygon(")?;
        if self.fill != FillRule::default() {
            self.fill.to_css(dest)?;
            dest.write_str(", ")?;
        }

        for (i, coord) in self.coordinates.iter().enumerate() {
            if i > 0 {
                dest.write_str(", ")?;
            }

            coord.0.to_css(dest)?;
            dest.write_str(" ")?;
            coord.1.to_css(dest)?;
        }

        dest.write_str(")")
    }
}

impl Default for FillRule {
    #[inline]
    fn default() -> Self { FillRule::NonZero }
}
<|endoftext|>


<commit_before>//! Functions and data-structures to load descriptor tables.

use core::mem::size_of;

use current::irq::IdtEntry;
use shared::segmentation::SegmentDescriptor;

/// A struct describing a pointer to a descriptor table (GDT / IDT).
/// This is in a format suitable for giving to 'lgdt' or 'lidt'.
#[derive(Debug)]
#[repr(C, packed)]
pub struct DescriptorTablePointer<Entry> {
    /// Size of the DT.
    pub limit: u16,
    /// Pointer to the memory region containing the DT.
    pub base: *const Entry,
}

impl<T> DescriptorTablePointer<T> {
    fn new(slice: &[T]) -> Self {
        let len = slice.len() * size_of::<T>();
        assert!(len < 0x10000);
        DescriptorTablePointer {
            base: slice.as_ptr(),
            limit: len as u16,
        }
    }
}

impl DescriptorTablePointer<SegmentDescriptor> {
    pub fn new_gdtp(gdt: &[SegmentDescriptor]) -> Self {
        let mut p = Self::new(gdt);
        p.limit -= 1;
        p
    }
    pub fn new_ldtp(ldt: &[SegmentDescriptor]) -> Self {
        Self::new(ldt)
    }
}

impl DescriptorTablePointer<IdtEntry> {
    pub fn new_idtp(idt: &[IdtEntry]) -> Self {
        Self::new(idt)
    }
}

/// Load GDT table.
pub unsafe fn lgdt(gdt: &DescriptorTablePointer<SegmentDescriptor>) {
    asm!("lgdt ($0)" :: "r" (gdt) : "memory");
}

/// Load LDT table.
pub unsafe fn lldt(ldt: &DescriptorTablePointer<SegmentDescriptor>) {
    asm!("lldt ($0)" :: "r" (ldt) : "memory");
}

/// Load IDT table.
pub unsafe fn lidt(idt: &DescriptorTablePointer<IdtEntry>) {
    asm!("lidt ($0)" :: "r" (idt) : "memory");
}
<commit_msg>GDT, LDT, and IDT all expect the limit to be set to "one less". So do this in the "new" function and make it public instead of having three different functions that do the same.<commit_after>//! Functions and data-structures to load descriptor tables.

use core::mem::size_of;

use current::irq::IdtEntry;
use shared::segmentation::SegmentDescriptor;

/// A struct describing a pointer to a descriptor table (GDT / IDT).
/// This is in a format suitable for giving to 'lgdt' or 'lidt'.
#[derive(Debug)]
#[repr(C, packed)]
pub struct DescriptorTablePointer<Entry> {
    /// Size of the DT.
    pub limit: u16,
    /// Pointer to the memory region containing the DT.
    pub base: *const Entry,
}

impl<T> DescriptorTablePointer<T> {
    pub fn new(slice: &[T]) -> Self {
        // GDT, LDT, and IDT all expect the limit to be set to "one less".
        // See Intel 3a, Section 3.5.1 "Segment Descriptor Tables" and
        // Section 6.10 "Interrupt Descriptor Table (IDT)".
        let len = slice.len() * size_of::<T>() - 1;
        assert!(len < 0x10000);
        DescriptorTablePointer {
            base: slice.as_ptr(),
            limit: len as u16,
        }
    }
}

/// Load GDT table.
pub unsafe fn lgdt(gdt: &DescriptorTablePointer<SegmentDescriptor>) {
    asm!("lgdt ($0)" :: "r" (gdt) : "memory");
}

/// Load LDT table.
pub unsafe fn lldt(ldt: &DescriptorTablePointer<SegmentDescriptor>) {
    asm!("lldt ($0)" :: "r" (ldt) : "memory");
}

/// Load IDT table.
pub unsafe fn lidt(idt: &DescriptorTablePointer<IdtEntry>) {
    asm!("lidt ($0)" :: "r" (idt) : "memory");
}
<|endoftext|>