<commit_before>use std::path::Path;

use regex::Regex;

use crate::rustc_stderr::Level;

use color_eyre::eyre::{bail, ensure, eyre, Result};

#[cfg(test)]
mod tests;

/// This crate supports various magic comments that get parsed as file-specific
/// configuration values. This struct parses them all in one go and then they
/// get processed by their respective use sites.
#[derive(Default, Debug)]
pub(crate) struct Comments {
    /// List of revision names to execute. Can only be speicified once
    pub revisions: Option<Vec<String>>,
    /// Don't run this test if any of these filters apply
    pub ignore: Vec<Condition>,
    /// Only run this test if all of these filters apply
    pub only: Vec<Condition>,
    /// Generate one .stderr file per bit width, by prepending with `.64bit` and similar
    pub stderr_per_bitwidth: bool,
    /// Additional flags to pass to the executable
    pub compile_flags: Vec<String>,
    /// Additional env vars to set for the executable
    pub env_vars: Vec<(String, String)>,
    /// Normalizations to apply to the stderr output before emitting it to disk
    pub normalize_stderr: Vec<(Regex, String)>,
    /// An arbitrary pattern to look for in the stderr.
    pub error_pattern: Option<(String, usize)>,
    pub error_matches: Vec<ErrorMatch>,
}

/// The conditions used for "ignore" and "only" filters.
#[derive(Debug)]
pub(crate) enum Condition {
    /// The given string must appear in the target.
    Target(String),
    /// Tests that the bitwidth is the given one.
    Bitwidth(u8),
}

#[derive(Debug)]
pub(crate) struct ErrorMatch {
    pub matched: String,
    pub revision: Option<String>,
    pub level: Option<Level>,
    /// The line where the message was defined, for reporting issues with it (e.g. in case it wasn't found).
    pub definition_line: usize,
    /// The line this pattern is expecting to find a message in.
    pub line: usize,
}

impl Condition {
    fn parse(c: &str) -> Self {
        if let Some(bits) = c.strip_suffix("bit") {
            let bits: u8 = bits.parse().expect(
                "ignore/only filter ending in 'bit' must be of the form 'Nbit' for some integer N",
            );
            Condition::Bitwidth(bits)
        } else {
            Condition::Target(c.to_owned())
        }
    }
}

impl Comments {
    pub(crate) fn parse_file(path: &Path) -> Result<Self> {
        let content = std::fs::read_to_string(path)?;
        Self::parse(path, &content)
    }

    /// Parse comments in `content`.
    /// `path` is only used to emit diagnostics if parsing fails.
    ///
    /// This function will only parse `//@` and `//~` style comments (and the `//[xxx]~` variant)
    /// and ignore all others
    fn parse_checked(path: &Path, content: &str) -> Result<Self> {
        let mut this = Self::default();

        // The line that a `|` will refer to
        let mut fallthrough_to = None;
        for (l, line) in content.lines().enumerate() {
            let l = l + 1; // enumerate starts at 0, but line numbers start at 1
            this.parse_checked_line(l, &mut fallthrough_to, line).map_err(|err| {
                err.wrap_err(format!("{}:{l}: failed to parse annotation", path.display()))
            })?;
        }
        Ok(this)
    }

    fn parse_checked_line(
        &mut self,
        l: usize,
        fallthrough_to: &mut Option<usize>,
        line: &str,
    ) -> Result<()> {
        if let Some((_, command)) = line.split_once("//@") {
            self.parse_command(command.trim(), l)
        } else if let Some((_, pattern)) = line.split_once("//~") {
            self.parse_pattern(pattern, fallthrough_to, l)
        } else if let Some((_, pattern)) = line.split_once("//[") {
            self.parse_revisioned_pattern(pattern, fallthrough_to, l)
        } else {
            *fallthrough_to = None;
            Ok(())
        }
    }

    /// Parse comments in `content`.
    /// `path` is only used to emit diagnostics if parsing fails.
    pub(crate) fn parse(path: &Path, content: &str) -> Result<Self> {
        let mut this = Self::parse_checked(path, content)?;
        if content.contains("//@") {
            // Migration mode: if new syntax is used, ignore all old syntax
            return Ok(this);
        }

        for (l, line) in content.lines().enumerate() {
            let l = l + 1; // enumerate starts at 0, but line numbers start at 1
            if let Some(revisions) = line.strip_prefix("// revisions:") {
                assert_eq!(
                    this.revisions,
                    None,
                    "{}:{l}, cannot specifiy revisions twice",
                    path.display()
                );
                this.revisions =
                    Some(revisions.split_whitespace().map(|s| s.to_string()).collect());
            }
            if let Some(s) = line.strip_prefix("// ignore-") {
                let s = s
                    .split_once(|c: char| c == ':' || c.is_whitespace())
                    .map(|(s, _)| s)
                    .unwrap_or(s);
                this.ignore.push(Condition::parse(s));
            }
            if let Some(s) = line.strip_prefix("// only-") {
                let s = s
                    .split_once(|c: char| c == ':' || c.is_whitespace())
                    .map(|(s, _)| s)
                    .unwrap_or(s);
                this.only.push(Condition::parse(s));
            }
            if line.starts_with("// stderr-per-bitwidth") {
                assert!(
                    !this.stderr_per_bitwidth,
                    "{}:{l}, cannot specifiy stderr-per-bitwidth twice",
                    path.display()
                );
                this.stderr_per_bitwidth = true;
            }
            if let Some(s) = line.strip_prefix("// compile-flags:") {
                this.compile_flags.extend(s.split_whitespace().map(|s| s.to_string()));
            }
            if let Some(s) = line.strip_prefix("// rustc-env:") {
                for env in s.split_whitespace() {
                    if let Some((k, v)) = env.split_once('=') {
                        this.env_vars.push((k.to_string(), v.to_string()));
                    }
                }
            }
            if let Some(s) = line.strip_prefix("// normalize-stderr-test:") {
                let (from, to) = s.split_once("->").expect("normalize-stderr-test needs a `->`");
                let from = from.trim().trim_matches('"');
                let to = to.trim().trim_matches('"');
                let from = Regex::new(from).unwrap();
                this.normalize_stderr.push((from, to.to_string()));
            }
            if let Some(s) = line.strip_prefix("// error-pattern:") {
                assert_eq!(
                    this.error_pattern,
                    None,
                    "{}:{l}, cannot specifiy error_pattern twice",
                    path.display()
                );
                this.error_pattern = Some((s.trim().to_string(), l));
            }
        }
        Ok(this)
    }

    fn parse_command(&mut self, command: &str, l: usize) -> Result<()> {
        // Commands are letters or dashes, grab everything until the first character that is neither of those.
        let (command, args) =
            match command.chars().position(|c: char| !c.is_alphabetic() && c != '-') {
                None => (command, ""),
                Some(i) => {
                    let (command, args) = command.split_at(i);
                    let mut args = args.chars();
                    let next = args
                        .next()
                        .expect("the `position` above guarantees that there is at least one char");
                    let args = match next {
                        ':' | ' ' => args.as_str(),
                        _ => bail!("expected space or `:`, got `{next}`"),
                    };
                    (command, args)
                }
            };

        match command {
            "revisions" => {
                ensure!(self.revisions.is_none(), "cannot specifiy revisions twice");
                self.revisions = Some(args.split_whitespace().map(|s| s.to_string()).collect());
            }
            "compile-flags" => {
                self.compile_flags.extend(args.split_whitespace().map(|s| s.to_string()));
            }
            "rustc-env" =>
                for env in args.split_whitespace() {
                    let (k, v) = env.split_once('=').ok_or_else(|| {
                        eyre!("environment variables must be key/value pairs separated by a `=`")
                    })?;
                    self.env_vars.push((k.to_string(), v.to_string()));
                },
            "normalize-stderr-test" => {
                let (from, to) = args
                    .split_once("->")
                    .ok_or_else(|| eyre!("normalize-stderr-test needs a `->`"))?;
                let from = from.trim().trim_matches('"');
                let to = to.trim().trim_matches('"');
                let from = Regex::new(from).ok().ok_or_else(|| eyre!("invalid regex"))?;
                self.normalize_stderr.push((from, to.to_string()));
            }
            "error-pattern" => {
                ensure!(
                    self.error_pattern.is_none(),
                    "cannot specifiy error_pattern twice, previous: {:?}",
                    self.error_pattern
                );
                self.error_pattern = Some((args.trim().to_string(), l));
            }
            "stderr-per-bitwidth" => {
                ensure!(!self.stderr_per_bitwidth, "cannot specifiy stderr-per-bitwidth twice");
                self.stderr_per_bitwidth = true;
            }
            command => {
                if let Some(s) = command.strip_prefix("ignore-") {
                    self.ignore.push(Condition::parse(s));
                    return Ok(());
                }

                if let Some(s) = command.strip_prefix("only-") {
                    self.only.push(Condition::parse(s));
                    return Ok(());
                }
                bail!("unknown command {command}");
            }
        }

        Ok(())
    }

    fn parse_pattern(
        &mut self,
        pattern: &str,
        fallthrough_to: &mut Option<usize>,
        l: usize,
    ) -> Result<()> {
        self.parse_pattern_inner(pattern, fallthrough_to, None, l)
    }

    fn parse_revisioned_pattern(
        &mut self,
        pattern: &str,
        fallthrough_to: &mut Option<usize>,
        l: usize,
    ) -> Result<()> {
        let (revision, pattern) =
            pattern.split_once(']').ok_or_else(|| eyre!("`//[` without corresponding `]`"))?;
        if let Some(pattern) = pattern.strip_prefix('~') {
            self.parse_pattern_inner(pattern, fallthrough_to, Some(revision.to_owned()), l)
        } else {
            bail!("revisioned pattern must have `~` following the `]`");
        }
    }

    // parse something like (?P<offset>\||[\^]+)? *(?P<level>ERROR|HELP|WARN|NOTE)?:?(?P<text>.*)
    fn parse_pattern_inner(
        &mut self,
        pattern: &str,
        fallthrough_to: &mut Option<usize>,
        revision: Option<String>,
        l: usize,
    ) -> Result<()> {
        let (match_line, pattern) =
            match pattern.chars().next().ok_or_else(|| eyre!("no pattern specified"))? {
                '|' =>
                    (
                        *fallthrough_to
                            .as_mut()
                            .ok_or_else(|| eyre!("`//~|` pattern without preceding line"))?,
                        &pattern[1..],
                    ),
                '^' => {
                    let offset = pattern.chars().take_while(|&c| c == '^').count();
                    (l - offset, &pattern[offset..])
                }
                _ => (l, pattern),
            };

        let (level, pattern) = match pattern.trim_start().split_once(|c| matches!(c, ':' | ' ')) {
            None => (None, pattern),
            Some((level, pattern_without_level)) =>
                match level.parse().ok() {
                    Some(level) => (Some(level), pattern_without_level),
                    None => (None, pattern),
                },
        };

        let matched = pattern.trim().to_string();

        ensure!(!matched.is_empty(), "no pattern specified");

        *fallthrough_to = Some(match_line);

        self.error_matches.push(ErrorMatch {
            matched,
            revision,
            level,
            definition_line: l,
            line: match_line,
        });

        Ok(())
    }
}
<commit_msg>Add some comments<commit_after>use std::path::Path;

use regex::Regex;

use crate::rustc_stderr::Level;

use color_eyre::eyre::{bail, ensure, eyre, Result};

#[cfg(test)]
mod tests;

/// This crate supports various magic comments that get parsed as file-specific
/// configuration values. This struct parses them all in one go and then they
/// get processed by their respective use sites.
#[derive(Default, Debug)]
pub(crate) struct Comments {
    /// List of revision names to execute. Can only be speicified once
    pub revisions: Option<Vec<String>>,
    /// Don't run this test if any of these filters apply
    pub ignore: Vec<Condition>,
    /// Only run this test if all of these filters apply
    pub only: Vec<Condition>,
    /// Generate one .stderr file per bit width, by prepending with `.64bit` and similar
    pub stderr_per_bitwidth: bool,
    /// Additional flags to pass to the executable
    pub compile_flags: Vec<String>,
    /// Additional env vars to set for the executable
    pub env_vars: Vec<(String, String)>,
    /// Normalizations to apply to the stderr output before emitting it to disk
    pub normalize_stderr: Vec<(Regex, String)>,
    /// An arbitrary pattern to look for in the stderr.
    pub error_pattern: Option<(String, usize)>,
    pub error_matches: Vec<ErrorMatch>,
}

/// The conditions used for "ignore" and "only" filters.
#[derive(Debug)]
pub(crate) enum Condition {
    /// The given string must appear in the target.
    Target(String),
    /// Tests that the bitwidth is the given one.
    Bitwidth(u8),
}

#[derive(Debug)]
pub(crate) struct ErrorMatch {
    pub matched: String,
    pub revision: Option<String>,
    pub level: Option<Level>,
    /// The line where the message was defined, for reporting issues with it (e.g. in case it wasn't found).
    pub definition_line: usize,
    /// The line this pattern is expecting to find a message in.
    pub line: usize,
}

impl Condition {
    fn parse(c: &str) -> Self {
        if let Some(bits) = c.strip_suffix("bit") {
            let bits: u8 = bits.parse().expect(
                "ignore/only filter ending in 'bit' must be of the form 'Nbit' for some integer N",
            );
            Condition::Bitwidth(bits)
        } else {
            Condition::Target(c.to_owned())
        }
    }
}

impl Comments {
    pub(crate) fn parse_file(path: &Path) -> Result<Self> {
        let content = std::fs::read_to_string(path)?;
        Self::parse(path, &content)
    }

    /// Parse comments in `content`.
    /// `path` is only used to emit diagnostics if parsing fails.
    ///
    /// This function will only parse `//@` and `//~` style comments (and the `//[xxx]~` variant)
    /// and ignore all others
    fn parse_checked(path: &Path, content: &str) -> Result<Self> {
        let mut this = Self::default();

        let mut fallthrough_to = None; // The line that a `|` will refer to.
        for (l, line) in content.lines().enumerate() {
            let l = l + 1; // enumerate starts at 0, but line numbers start at 1
            this.parse_checked_line(l, &mut fallthrough_to, line).map_err(|err| {
                err.wrap_err(format!("{}:{l}: failed to parse annotation", path.display()))
            })?;
        }
        Ok(this)
    }

    fn parse_checked_line(
        &mut self,
        l: usize,
        fallthrough_to: &mut Option<usize>,
        line: &str,
    ) -> Result<()> {
        if let Some((_, command)) = line.split_once("//@") {
            self.parse_command(command.trim(), l)
        } else if let Some((_, pattern)) = line.split_once("//~") {
            self.parse_pattern(pattern, fallthrough_to, l)
        } else if let Some((_, pattern)) = line.split_once("//[") {
            self.parse_revisioned_pattern(pattern, fallthrough_to, l)
        } else {
            *fallthrough_to = None;
            Ok(())
        }
    }

    /// Parse comments in `content`.
    /// `path` is only used to emit diagnostics if parsing fails.
    pub(crate) fn parse(path: &Path, content: &str) -> Result<Self> {
        let mut this = Self::parse_checked(path, content)?;
        if content.contains("//@") {
            // Migration mode: if new syntax is used, ignore all old syntax
            return Ok(this);
        }

        for (l, line) in content.lines().enumerate() {
            let l = l + 1; // enumerate starts at 0, but line numbers start at 1
            if let Some(revisions) = line.strip_prefix("// revisions:") {
                assert_eq!(
                    this.revisions,
                    None,
                    "{}:{l}, cannot specifiy revisions twice",
                    path.display()
                );
                this.revisions =
                    Some(revisions.split_whitespace().map(|s| s.to_string()).collect());
            }
            if let Some(s) = line.strip_prefix("// ignore-") {
                let s = s
                    .split_once(|c: char| c == ':' || c.is_whitespace())
                    .map(|(s, _)| s)
                    .unwrap_or(s);
                this.ignore.push(Condition::parse(s));
            }
            if let Some(s) = line.strip_prefix("// only-") {
                let s = s
                    .split_once(|c: char| c == ':' || c.is_whitespace())
                    .map(|(s, _)| s)
                    .unwrap_or(s);
                this.only.push(Condition::parse(s));
            }
            if line.starts_with("// stderr-per-bitwidth") {
                assert!(
                    !this.stderr_per_bitwidth,
                    "{}:{l}, cannot specifiy stderr-per-bitwidth twice",
                    path.display()
                );
                this.stderr_per_bitwidth = true;
            }
            if let Some(s) = line.strip_prefix("// compile-flags:") {
                this.compile_flags.extend(s.split_whitespace().map(|s| s.to_string()));
            }
            if let Some(s) = line.strip_prefix("// rustc-env:") {
                for env in s.split_whitespace() {
                    if let Some((k, v)) = env.split_once('=') {
                        this.env_vars.push((k.to_string(), v.to_string()));
                    }
                }
            }
            if let Some(s) = line.strip_prefix("// normalize-stderr-test:") {
                let (from, to) = s.split_once("->").expect("normalize-stderr-test needs a `->`");
                let from = from.trim().trim_matches('"');
                let to = to.trim().trim_matches('"');
                let from = Regex::new(from).unwrap();
                this.normalize_stderr.push((from, to.to_string()));
            }
            if let Some(s) = line.strip_prefix("// error-pattern:") {
                assert_eq!(
                    this.error_pattern,
                    None,
                    "{}:{l}, cannot specifiy error_pattern twice",
                    path.display()
                );
                this.error_pattern = Some((s.trim().to_string(), l));
            }
        }
        Ok(this)
    }

    fn parse_command(&mut self, command: &str, l: usize) -> Result<()> {
        // Commands are letters or dashes, grab everything until the first character that is neither of those.
        let (command, args) =
            match command.chars().position(|c: char| !c.is_alphabetic() && c != '-') {
                None => (command, ""),
                Some(i) => {
                    let (command, args) = command.split_at(i);
                    let mut args = args.chars();
                    // Commands are separated from their arguments by ':' or ' '
                    let next = args
                        .next()
                        .expect("the `position` above guarantees that there is at least one char");
                    let args = match next {
                        ':' | ' ' => args.as_str(),
                        _ => bail!("expected space or `:`, got `{next}`"),
                    };
                    (command, args)
                }
            };

        match command {
            "revisions" => {
                ensure!(self.revisions.is_none(), "cannot specifiy revisions twice");
                self.revisions = Some(args.split_whitespace().map(|s| s.to_string()).collect());
            }
            "compile-flags" => {
                self.compile_flags.extend(args.split_whitespace().map(|s| s.to_string()));
            }
            "rustc-env" =>
                for env in args.split_whitespace() {
                    let (k, v) = env.split_once('=').ok_or_else(|| {
                        eyre!("environment variables must be key/value pairs separated by a `=`")
                    })?;
                    self.env_vars.push((k.to_string(), v.to_string()));
                },
            "normalize-stderr-test" => {
                let (from, to) = args
                    .split_once("->")
                    .ok_or_else(|| eyre!("normalize-stderr-test needs a `->`"))?;
                let from = from.trim().trim_matches('"');
                let to = to.trim().trim_matches('"');
                let from = Regex::new(from).ok().ok_or_else(|| eyre!("invalid regex"))?;
                self.normalize_stderr.push((from, to.to_string()));
            }
            "error-pattern" => {
                ensure!(
                    self.error_pattern.is_none(),
                    "cannot specifiy error_pattern twice, previous: {:?}",
                    self.error_pattern
                );
                self.error_pattern = Some((args.trim().to_string(), l));
            }
            "stderr-per-bitwidth" => {
                ensure!(!self.stderr_per_bitwidth, "cannot specifiy stderr-per-bitwidth twice");
                self.stderr_per_bitwidth = true;
            }
            command => {
                if let Some(s) = command.strip_prefix("ignore-") {
                    self.ignore.push(Condition::parse(s));
                    return Ok(());
                }

                if let Some(s) = command.strip_prefix("only-") {
                    self.only.push(Condition::parse(s));
                    return Ok(());
                }
                bail!("unknown command {command}");
            }
        }

        Ok(())
    }

    fn parse_pattern(
        &mut self,
        pattern: &str,
        fallthrough_to: &mut Option<usize>,
        l: usize,
    ) -> Result<()> {
        self.parse_pattern_inner(pattern, fallthrough_to, None, l)
    }

    fn parse_revisioned_pattern(
        &mut self,
        pattern: &str,
        fallthrough_to: &mut Option<usize>,
        l: usize,
    ) -> Result<()> {
        let (revision, pattern) =
            pattern.split_once(']').ok_or_else(|| eyre!("`//[` without corresponding `]`"))?;
        if let Some(pattern) = pattern.strip_prefix('~') {
            self.parse_pattern_inner(pattern, fallthrough_to, Some(revision.to_owned()), l)
        } else {
            bail!("revisioned pattern must have `~` following the `]`");
        }
    }

    // parse something like (?P<offset>\||[\^]+)? *(?P<level>ERROR|HELP|WARN|NOTE)?:?(?P<text>.*)
    fn parse_pattern_inner(
        &mut self,
        pattern: &str,
        fallthrough_to: &mut Option<usize>,
        revision: Option<String>,
        l: usize,
    ) -> Result<()> {
        let (match_line, pattern) =
            match pattern.chars().next().ok_or_else(|| eyre!("no pattern specified"))? {
                '|' =>
                    (
                        *fallthrough_to
                            .as_mut()
                            .ok_or_else(|| eyre!("`//~|` pattern without preceding line"))?,
                        &pattern[1..],
                    ),
                '^' => {
                    let offset = pattern.chars().take_while(|&c| c == '^').count();
                    (l - offset, &pattern[offset..])
                }
                _ => (l, pattern),
            };

        let (level, pattern) = match pattern.trim_start().split_once(|c| matches!(c, ':' | ' ')) {
            None => (None, pattern),
            Some((level, pattern_without_level)) =>
                match level.parse().ok() {
                    Some(level) => (Some(level), pattern_without_level),
                    None => (None, pattern),
                },
        };

        let matched = pattern.trim().to_string();

        ensure!(!matched.is_empty(), "no pattern specified");

        *fallthrough_to = Some(match_line);

        self.error_matches.push(ErrorMatch {
            matched,
            revision,
            level,
            definition_line: l,
            line: match_line,
        });

        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::sync::atomic::AtomicBool;

use parking_lot::{RwLockReadGuard, RwLockWriteGuard};

use super::*;

#[derive(Default)]
pub(crate) struct ConcurrencyControl {
    necessary: AtomicBool,
    rw: RwLock<()>,
}

pub(crate) enum Protector<'a> {
    Write(RwLockWriteGuard<'a, ()>),
    Read(RwLockReadGuard<'a, ()>),
    None,
}

impl ConcurrencyControl {
    fn enable(&self) {
        if !self.necessary.swap(true, SeqCst) {
            // upgrade the system to using transactional
            // concurrency control, which is a little
            // more expensive for every operation.
            let (tx, rx) = std::sync::mpsc::channel();

            let guard = pin();
            guard.defer(move || tx.send(()).unwrap());
            guard.flush();
            drop(guard);

            rx.recv().unwrap();
        }
    }

    pub(crate) fn read<'a>(&'a self, _: &'a Guard) -> Protector<'a> {
        if self.necessary.load(SeqCst) {
            Protector::Read(self.rw.read())
        } else {
            Protector::None
        }
    }

    pub(crate) fn write(&self) -> Protector<'_> {
        self.enable();
        Protector::Write(self.rw.write())
    }
}
<commit_msg>Fix race condition in the CC upgrade path<commit_after>use std::sync::atomic::AtomicBool;

use parking_lot::{RwLockReadGuard, RwLockWriteGuard};

use super::*;

#[derive(Default)]
pub(crate) struct ConcurrencyControl {
    necessary: AtomicBool,
    upgrade_complete: AtomicBool,
    rw: RwLock<()>,
}

pub(crate) enum Protector<'a> {
    Write(RwLockWriteGuard<'a, ()>),
    Read(RwLockReadGuard<'a, ()>),
    None,
}

impl ConcurrencyControl {
    fn enable(&self) {
        if !self.necessary.load(Acquire) && !self.necessary.swap(true, SeqCst) {
            // upgrade the system to using transactional
            // concurrency control, which is a little
            // more expensive for every operation.
            let (tx, rx) = std::sync::mpsc::channel();

            let guard = pin();
            guard.defer(move || tx.send(()).unwrap());
            guard.flush();
            drop(guard);

            rx.recv().unwrap();
            self.upgrade_complete.store(true, Release);
        }
    }

    pub(crate) fn read<'a>(&'a self, _: &'a Guard) -> Protector<'a> {
        if self.necessary.load(Acquire) {
            Protector::Read(self.rw.read())
        } else {
            Protector::None
        }
    }

    pub(crate) fn write(&self) -> Protector<'_> {
        self.enable();
        while !self.upgrade_complete.load(Acquire) {
            std::sync::atomic::spin_loop_hint()
        }
        Protector::Write(self.rw.write())
    }
}
<|endoftext|>


<commit_before><commit_msg>add lat lon to query<commit_after><|endoftext|>


<commit_before>use std::sync::mpsc::{Sender, Receiver};
use std::sync::{mpsc, Arc, TaskPool};
use std::collections::{HashMap};
use rand::{Rng, thread_rng};

use evaluation::{EvaluationFn};
use genotype::{GenoType};
use util::{shuffle};

pub struct MuLambda<G: GenoType> {
    threads: usize,
    iterations: usize,
    current_iteration: usize,
    mu: usize,     // number to keep
    lambda: usize, // number to generate
    genotype: G,
    evaluations: Arc<Vec<EvaluationFn>>
}

impl<G: GenoType + Clone + Send + 'static> MuLambda<G> {
    pub fn new(threads: usize,
               iterations: usize,
               mu: usize,
               lambda: usize,
               genotype: G,
               funcs: Vec<EvaluationFn>) -> MuLambda<G> {
        MuLambda {
            threads: threads,
            iterations: iterations,
            current_iteration: 0,
            mu: mu,
            lambda: lambda,
            genotype: genotype,
            evaluations: Arc::new(funcs)
        }
    }

    pub fn evaluate(&mut self) -> Vec<G> {
        let total = self.mu + self.lambda;
        let mut primer: Vec<G> = range(0, total).map(|_| self.genotype.clone()).collect();
        let mut rng = thread_rng();
        while self.current_iteration < self.iterations {
            primer = self.iterate(&mut rng, primer.as_mut_slice(), self.current_iteration);
            self.current_iteration += 1;
        }
        primer.clone()
    }

    fn iterate<R: Rng>(&self, rng: &mut R, primer: &mut [G], iteration: usize) -> Vec<G> {
        // shuffle the population
        shuffle(rng, primer);
        // calculate the fitness for each individual (in a separate thread)
        let n = primer.len();
        let pool = TaskPool::new(self.threads);
        let (tx, rx): (Sender<(G, f64)>, Receiver<(G, f64)>) = mpsc::channel();
        for adult in primer {
            let mut individual = adult.clone();
            let sender = tx.clone();
            let fns = self.evaluations.clone();
            pool.execute(move || {
                let mut new_rng = thread_rng();
                let dungeon = individual.generate(&mut new_rng);
                let fitness = individual.evaluate(&dungeon, fns.as_slice());
                let mut stats: HashMap<String, f64> = HashMap::new();
                stats.insert(String::from_str("iteration"), iteration as f64);
                stats.insert(String::from_str("ranking"), fitness);
                individual.statistics(&stats);
                sender.send((individual, fitness)).unwrap();
            });
        }
        let mut colony: Vec<(G, f64)> = range(0, n).map(|_| rx.recv().unwrap()).collect();
        // sort by fitness
        colony.sort_by(|&(_, f1), &(_, f2)| {
            match f1.partial_cmp(&f2) {
                Some(ordering) => ordering,
                None => panic!(format!("{:?} and {:?} could not be ordered.", f1, f2))
            }
        });
        // keep mu
        let mut survivors: Vec<G> = colony.iter().map(|&(ref i, _)| i.clone()).take(self.mu).collect();
        // add the next generation
        let mut laggards: Vec<G> = colony.iter().map(|&(ref i, _)| i.clone()).skip(self.mu).collect();
        let next_generation: Vec<G> = laggards.drain().map(|mut individual| {
            let mut new_rng = thread_rng();
            individual.mutate(&mut new_rng);
            individual.generate(&mut new_rng);
            let mut stats: HashMap<String, f64> = HashMap::new();
            stats.insert(String::from_str("iteration"), (iteration + 1) as f64);
            individual.statistics(&stats);
            individual
        }).collect();
        survivors.push_all(next_generation.as_slice());
        survivors
    }
}
<commit_msg>Make sure primer is properly initialized.<commit_after>use std::sync::mpsc::{Sender, Receiver};
use std::sync::{mpsc, Arc, TaskPool};
use std::collections::{HashMap};
use rand::{Rng, thread_rng};

use evaluation::{EvaluationFn};
use genotype::{GenoType};
use util::{shuffle};

pub struct MuLambda<G: GenoType> {
    threads: usize,
    iterations: usize,
    current_iteration: usize,
    mu: usize,     // number to keep
    lambda: usize, // number to generate
    genotype: G,
    evaluations: Arc<Vec<EvaluationFn>>
}

impl<G: GenoType + Clone + Send + 'static> MuLambda<G> {
    pub fn new(threads: usize,
               iterations: usize,
               mu: usize,
               lambda: usize,
               genotype: G,
               funcs: Vec<EvaluationFn>) -> MuLambda<G> {
        MuLambda {
            threads: threads,
            iterations: iterations,
            current_iteration: 0,
            mu: mu,
            lambda: lambda,
            genotype: genotype,
            evaluations: Arc::new(funcs)
        }
    }

    pub fn evaluate(&mut self) -> Vec<G> {
        let total = self.mu + self.lambda;
        let mut rng = thread_rng();
        let mut primer: Vec<G> = range(0, total).map(|_| {
            let mut infant = self.genotype.clone();
            infant.mutate(&mut rng);
            infant
        }).collect();
        while self.current_iteration < self.iterations {
            primer = self.iterate(&mut rng, primer.as_mut_slice(), self.current_iteration);
            self.current_iteration += 1;
        }
        primer.clone()
    }

    fn iterate<R: Rng>(&self, rng: &mut R, primer: &mut [G], iteration: usize) -> Vec<G> {
        // shuffle the population
        shuffle(rng, primer);
        // calculate the fitness for each individual (in a separate thread)
        let n = primer.len();
        let pool = TaskPool::new(self.threads);
        let (tx, rx): (Sender<(G, f64)>, Receiver<(G, f64)>) = mpsc::channel();
        for adult in primer {
            let mut individual = adult.clone();
            let sender = tx.clone();
            let fns = self.evaluations.clone();
            pool.execute(move || {
                let mut new_rng = thread_rng();
                let dungeon = individual.generate(&mut new_rng);
                let fitness = individual.evaluate(&dungeon, fns.as_slice());
                let mut stats: HashMap<String, f64> = HashMap::new();
                stats.insert(String::from_str("iteration"), iteration as f64);
                stats.insert(String::from_str("ranking"), fitness);
                individual.statistics(&stats);
                sender.send((individual, fitness)).unwrap();
            });
        }
        let mut colony: Vec<(G, f64)> = range(0, n).map(|_| rx.recv().unwrap()).collect();
        // sort by fitness
        colony.sort_by(|&(_, f1), &(_, f2)| {
            match f1.partial_cmp(&f2) {
                Some(ordering) => ordering,
                None => panic!(format!("{:?} and {:?} could not be ordered.", f1, f2))
            }
        });
        // keep mu
        let mut survivors: Vec<G> = colony.iter().map(|&(ref i, _)| i.clone()).take(self.mu).collect();
        // add the next generation
        let mut laggards: Vec<G> = colony.iter().map(|&(ref i, _)| i.clone()).skip(self.mu).collect();
        let next_generation: Vec<G> = laggards.drain().map(|mut individual| {
            let mut new_rng = thread_rng();
            individual.mutate(&mut new_rng);
            individual.generate(&mut new_rng);
            let mut stats: HashMap<String, f64> = HashMap::new();
            stats.insert(String::from_str("iteration"), (iteration + 1) as f64);
            individual.statistics(&stats);
            individual
        }).collect();
        survivors.push_all(next_generation.as_slice());
        survivors
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::str;
use num::FromPrimitive;

#[derive(Debug, Default, Clone)]
pub struct FuncConst {
    pub name: String,
    pub arg_count: u32,
    pub local_count: u32,
    pub body: Vec<u8>
}

#[derive(Default)]
pub struct ConstTable {
    pub funcs: Vec<FuncConst>,
    pub bc_counter: usize
}

impl fmt::Debug for ConstTable {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        //TODO
        unimplemented!()
    }
}

// Eats a null byte terminated string
fn eat_string(data: &[u8], const_table: &mut ConstTable) -> String {
    use std::ffi::CString;

    let str_start = const_table.bc_counter;
    let mut str_len: usize = 0;
    while data[str_start + str_len] != 0x00 {
        str_len += 1;
    }
    let string = CString::new(&data[str_start..(str_start+str_len)]).unwrap();
    const_table.bc_counter = str_len + 1; // + 1 for null byte
    debug!("Ate string {:?} of length {}", string, str_len);
    string.into_string().unwrap()
}

pub fn read_const_table(data: &[u8]) -> ConstTable {

    let mut const_table: ConstTable = Default::default();

    // TODO: Refactor these macros
    macro_rules! get_next_4_bytes {
        () => {{
            let val = (data[const_table.bc_counter] as u32) << 24 |
            (data[const_table.bc_counter + 1] as u32) << 16 |
            (data[const_table.bc_counter + 2] as u32) << 8 |
            (data[const_table.bc_counter + 3] as u32);
            const_table.bc_counter += 4;
            debug!("get_next_4_bytes: 0x{:04X}", val);
            val
        }}
    }

    while const_table.bc_counter != data.len() {
        let instr = ConstInstr::from_u8(data[const_table.bc_counter]);

        const_table.bc_counter += 1;
        if instr.is_none() {
            warn!("Unimplemented constants table instruction: {:04X}", data[const_table.bc_counter - 1]);
            continue;
        }

        let instr = instr.unwrap();

        match instr {
            ConstInstr::FUNC => {
                // TODO: use this id
                let id = get_next_4_bytes!() as usize;
                let name = eat_string(
                    &data, &mut const_table
                );
                let arg_count = get_next_4_bytes!();
                let local_count = get_next_4_bytes!();
                let bc_length = get_next_4_bytes!() as usize;
                let body = data[const_table.bc_counter..{const_table.bc_counter += bc_length; const_table.bc_counter + 1}].to_vec();
                if id >= const_table.funcs.len() {
                    const_table.funcs.resize(id + 1, FuncConst{..Default::default()})
                }
                const_table.funcs.push(FuncConst {
                    name: name,
                    arg_count: arg_count,
                    local_count: local_count,
                    body: body
                });
                debug!("Added a function to the constants table");
            },
            ConstInstr::END => {
                debug!("Reached end of constants table");
                break;
            }
        }
    }
    const_table
}

enum_from_primitive! {
    #[allow(non_camel_case_types)]
    #[derive(Debug, PartialEq)]
    pub enum ConstInstr {
        FUNC = 0xF0,
        END = 0xED
    }
}
<commit_msg>Refactor get_next_4_bytes to a function in constants.rs<commit_after>use std::fmt;
use std::str;
use num::FromPrimitive;

#[derive(Debug, Default, Clone)]
pub struct FuncConst {
    pub name: String,
    pub arg_count: u32,
    pub local_count: u32,
    pub body: Vec<u8>
}

#[derive(Default)]
pub struct ConstTable {
    pub funcs: Vec<FuncConst>,
    pub bc_counter: usize
}

impl fmt::Debug for ConstTable {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        //TODO
        unimplemented!()
    }
}

// Eats a null byte terminated string
fn eat_string(data: &[u8], const_table: &mut ConstTable) -> String {
    use std::ffi::CString;

    let str_start = const_table.bc_counter;
    let mut str_len: usize = 0;
    while data[str_start + str_len] != 0x00 {
        str_len += 1;
    }
    let string = CString::new(&data[str_start..(str_start+str_len)]).unwrap();
    const_table.bc_counter += str_len + 1; // + 1 for null byte
    //debug!("Ate string {:?} of length {}", string, str_len);
    string.into_string().unwrap()
}

#[inline]
fn get_next_4_bytes(data: &[u8], const_table: &mut ConstTable) -> u32 {

    let val = (data[const_table.bc_counter] as u32) << 24 |
        (data[const_table.bc_counter + 1] as u32) << 16 |
        (data[const_table.bc_counter + 2] as u32) << 8 |
        (data[const_table.bc_counter + 3] as u32);
    const_table.bc_counter += 4;
    debug!("get_next_4_bytes: 0x{:04X}", val);
    val
}

pub fn read_const_table(data: &[u8]) -> ConstTable {

    let mut const_table: ConstTable = Default::default();

    macro_rules! get_next_4_bytes {
        () => (get_next_4_bytes(&data, &mut const_table))
    }

    while const_table.bc_counter != data.len() {
        let instr = ConstInstr::from_u8(data[const_table.bc_counter]);

        const_table.bc_counter += 1;
        if instr.is_none() {
            warn!("Unimplemented constants table instruction: {:04X}", data[const_table.bc_counter - 1]);
            continue;
        }

        let instr = instr.unwrap();

        match instr {
            ConstInstr::FUNC => {
                // TODO: use this id
                let id = get_next_4_bytes!() as usize;
                let name = eat_string(&data, &mut const_table);
                let arg_count = get_next_4_bytes!();
                let local_count = get_next_4_bytes!();
                let bc_length = get_next_4_bytes!() as usize;
                let body = data[const_table.bc_counter..{
                    const_table.bc_counter += bc_length;
                    const_table.bc_counter + 1
                }].to_vec();

                if id >= const_table.funcs.len() {
                    const_table.funcs.resize(id + 1,FuncConst{
                        ..Default::default()
                    })
                }

                info!("Added function \"{}\" to the constants table", name);
                const_table.funcs[id] = (FuncConst {
                    name: name,
                    arg_count: arg_count,
                    local_count: local_count,
                    body: body
                });
            },
            ConstInstr::END => {
                debug!("Reached end of constants table");
                break;
            }
        }
    }
    const_table
}

enum_from_primitive! {
    #[allow(non_camel_case_types)]
    #[derive(Debug, PartialEq)]
    pub enum ConstInstr {
        FUNC = 0xF0,
        END = 0xED
    }
}
<|endoftext|>


<commit_before>use std::{ptr, sync::atomic::{AtomicPtr, Ordering}};

static mut LEAKER: Option<Box<Vec<i32>>> = None;

fn main() {
    // Having memory "leaked" in globals is allowed.
    unsafe {
        LEAKER = Some(Box::new(vec![0; 42]));
    }

    // Make sure this is allowed even when `AtomicPtr` is used.
    {
        static LEAK: AtomicPtr<usize> = AtomicPtr::new(ptr::null_mut());
        LEAK.store(Box::into_raw(Box::new(0usize)), Ordering::SeqCst);
    }
}
<commit_msg>leak checker: also test AtomicPtr stored via 'swap'<commit_after>use std::{ptr, sync::atomic::{AtomicPtr, Ordering}};

static mut LEAKER: Option<Box<Vec<i32>>> = None;

fn main() {
    // Having memory "leaked" in globals is allowed.
    unsafe {
        LEAKER = Some(Box::new(vec![0; 42]));
    }

    // Make sure this is allowed even when `AtomicPtr` is used.
    {
        static LEAK: AtomicPtr<usize> = AtomicPtr::new(ptr::null_mut());
        LEAK.store(Box::into_raw(Box::new(0usize)), Ordering::SeqCst);

        static LEAK2: AtomicPtr<usize> = AtomicPtr::new(ptr::null_mut());
        // Make sure this also works when using 'swap'.
        LEAK2.swap(Box::into_raw(Box::new(0usize)), Ordering::SeqCst);
    }
}
<|endoftext|>


<commit_before>use alloc::borrow::Cow;
use alloc::string::String;
use core::fmt::{self, Debug, Display};
use core::slice;
use core::str::{self, Utf8Error};

extern "C" {
    #[link_name = "cxxbridge05$cxx_string$data"]
    fn string_data(this: &CxxString) -> *const u8;
    #[link_name = "cxxbridge05$cxx_string$length"]
    fn string_length(this: &CxxString) -> usize;
    #[link_name = "cxxbridge05$cxx_string$push"]
    fn string_push(this: &mut CxxString, ptr: *const u8, len: usize);
}

/// Binding to C++ `std::string`.
///
/// # Invariants
///
/// As an invariant of this API and the static analysis of the cxx::bridge
/// macro, in Rust code we can never obtain a `CxxString` by value. C++'s string
/// requires a move constructor and may hold internal pointers, which is not
/// compatible with Rust's move behavior. Instead in Rust code we will only ever
/// look at a CxxString through a reference or smart pointer, as in `&CxxString`
/// or `UniquePtr<CxxString>`.
#[repr(C)]
pub struct CxxString {
    _private: [u8; 0],
}

impl CxxString {
    /// Returns the length of the string in bytes.
    ///
    /// Matches the behavior of C++ [std::string::size][size].
    ///
    /// [size]: https://en.cppreference.com/w/cpp/string/basic_string/size
    pub fn len(&self) -> usize {
        unsafe { string_length(self) }
    }

    /// Returns true if `self` has a length of zero bytes.
    ///
    /// Matches the behavior of C++ [std::string::empty][empty].
    ///
    /// [empty]: https://en.cppreference.com/w/cpp/string/basic_string/empty
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns a byte slice of this string's contents.
    pub fn as_bytes(&self) -> &[u8] {
        let data = self.as_ptr();
        let len = self.len();
        unsafe { slice::from_raw_parts(data, len) }
    }

    /// Produces a pointer to the first character of the string.
    ///
    /// Matches the behavior of C++ [std::string::data][data].
    ///
    /// Note that the return type may look like `const char *` but is not a
    /// `const char *` in the typical C sense, as C++ strings may contain
    /// internal null bytes. As such, the returned pointer only makes sense as a
    /// string in combination with the length returned by [`len()`][len].
    ///
    /// [data]: https://en.cppreference.com/w/cpp/string/basic_string/data
    /// [len]: #method.len
    pub fn as_ptr(&self) -> *const u8 {
        unsafe { string_data(self) }
    }

    /// Validates that the C++ string contains UTF-8 data and produces a view of
    /// it as a Rust &str, otherwise an error.
    pub fn to_str(&self) -> Result<&str, Utf8Error> {
        str::from_utf8(self.as_bytes())
    }

    /// If the contents of the C++ string are valid UTF-8, this function returns
    /// a view as a Cow::Borrowed &str. Otherwise replaces any invalid UTF-8
    /// sequences with the U+FFFD [replacement character] and returns a
    /// Cow::Owned String.
    ///
    /// [replacement character]: https://doc.rust-lang.org/std/char/constant.REPLACEMENT_CHARACTER.html
    pub fn to_string_lossy(&self) -> Cow<str> {
        String::from_utf8_lossy(self.as_bytes())
    }

    /// Appends a given string slice onto the end of this C++ string.
    pub fn push_str(&mut self, s: &str) {
        unsafe { string_push(self, s.as_ptr(), s.len()) }
    }
}

impl Display for CxxString {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(self.to_string_lossy().as_ref(), f)
    }
}

impl Debug for CxxString {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(self.to_string_lossy().as_ref(), f)
    }
}

impl PartialEq for CxxString {
    fn eq(&self, other: &CxxString) -> bool {
        self.as_bytes() == other.as_bytes()
    }
}

impl PartialEq<CxxString> for str {
    fn eq(&self, other: &CxxString) -> bool {
        self.as_bytes() == other.as_bytes()
    }
}

impl PartialEq<str> for CxxString {
    fn eq(&self, other: &str) -> bool {
        self.as_bytes() == other.as_bytes()
    }
}
<commit_msg>Allow pushing arbitrary bytes to CxxString<commit_after>use alloc::borrow::Cow;
use alloc::string::String;
use core::fmt::{self, Debug, Display};
use core::slice;
use core::str::{self, Utf8Error};

extern "C" {
    #[link_name = "cxxbridge05$cxx_string$data"]
    fn string_data(this: &CxxString) -> *const u8;
    #[link_name = "cxxbridge05$cxx_string$length"]
    fn string_length(this: &CxxString) -> usize;
    #[link_name = "cxxbridge05$cxx_string$push"]
    fn string_push(this: &mut CxxString, ptr: *const u8, len: usize);
}

/// Binding to C++ `std::string`.
///
/// # Invariants
///
/// As an invariant of this API and the static analysis of the cxx::bridge
/// macro, in Rust code we can never obtain a `CxxString` by value. C++'s string
/// requires a move constructor and may hold internal pointers, which is not
/// compatible with Rust's move behavior. Instead in Rust code we will only ever
/// look at a CxxString through a reference or smart pointer, as in `&CxxString`
/// or `UniquePtr<CxxString>`.
#[repr(C)]
pub struct CxxString {
    _private: [u8; 0],
}

impl CxxString {
    /// Returns the length of the string in bytes.
    ///
    /// Matches the behavior of C++ [std::string::size][size].
    ///
    /// [size]: https://en.cppreference.com/w/cpp/string/basic_string/size
    pub fn len(&self) -> usize {
        unsafe { string_length(self) }
    }

    /// Returns true if `self` has a length of zero bytes.
    ///
    /// Matches the behavior of C++ [std::string::empty][empty].
    ///
    /// [empty]: https://en.cppreference.com/w/cpp/string/basic_string/empty
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns a byte slice of this string's contents.
    pub fn as_bytes(&self) -> &[u8] {
        let data = self.as_ptr();
        let len = self.len();
        unsafe { slice::from_raw_parts(data, len) }
    }

    /// Produces a pointer to the first character of the string.
    ///
    /// Matches the behavior of C++ [std::string::data][data].
    ///
    /// Note that the return type may look like `const char *` but is not a
    /// `const char *` in the typical C sense, as C++ strings may contain
    /// internal null bytes. As such, the returned pointer only makes sense as a
    /// string in combination with the length returned by [`len()`][len].
    ///
    /// [data]: https://en.cppreference.com/w/cpp/string/basic_string/data
    /// [len]: #method.len
    pub fn as_ptr(&self) -> *const u8 {
        unsafe { string_data(self) }
    }

    /// Validates that the C++ string contains UTF-8 data and produces a view of
    /// it as a Rust &str, otherwise an error.
    pub fn to_str(&self) -> Result<&str, Utf8Error> {
        str::from_utf8(self.as_bytes())
    }

    /// If the contents of the C++ string are valid UTF-8, this function returns
    /// a view as a Cow::Borrowed &str. Otherwise replaces any invalid UTF-8
    /// sequences with the U+FFFD [replacement character] and returns a
    /// Cow::Owned String.
    ///
    /// [replacement character]: https://doc.rust-lang.org/std/char/constant.REPLACEMENT_CHARACTER.html
    pub fn to_string_lossy(&self) -> Cow<str> {
        String::from_utf8_lossy(self.as_bytes())
    }

    /// Appends a given string slice onto the end of this C++ string.
    pub fn push_str(&mut self, s: &str) {
        self.push_bytes(s.as_bytes());
    }

    /// Appends arbitrary bytes onto the end of this C++ string.
    pub fn push_bytes(&mut self, bytes: &[u8]) {
        unsafe { string_push(self, bytes.as_ptr(), bytes.len()) }
    }
}

impl Display for CxxString {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(self.to_string_lossy().as_ref(), f)
    }
}

impl Debug for CxxString {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(self.to_string_lossy().as_ref(), f)
    }
}

impl PartialEq for CxxString {
    fn eq(&self, other: &CxxString) -> bool {
        self.as_bytes() == other.as_bytes()
    }
}

impl PartialEq<CxxString> for str {
    fn eq(&self, other: &CxxString) -> bool {
        self.as_bytes() == other.as_bytes()
    }
}

impl PartialEq<str> for CxxString {
    fn eq(&self, other: &str) -> bool {
        self.as_bytes() == other.as_bytes()
    }
}
<|endoftext|>


<commit_before>//
// Copyright (c) Pirmin Kalberer. All rights reserved.
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
//

use core::Config;
use core::enum_serializer::EnumString;
use toml;
use serde;
use serde::de::{Deserialize, Deserializer};
use std::fmt;

#[derive(PartialEq, Deserialize, Debug)]
pub struct Extent {
    pub minx: f64,
    pub miny: f64,
    pub maxx: f64,
    pub maxy: f64,
}

/// Min and max grid cell numbers
#[derive(PartialEq,Debug)]
pub struct ExtentInt {
    pub minx: u32,
    pub miny: u32,
    pub maxx: u32,
    pub maxy: u32,
}

#[derive(PartialEq, Debug)]
pub enum Origin {
    TopLeft,
    BottomLeft, //TopRight, BottomRight
}

impl EnumString<Origin> for Origin {
    fn from_str(val: &str) -> Result<Origin, String> {
        match val {
            "TopLeft" => Ok(Origin::TopLeft),
            "BottomLeft" => Ok(Origin::BottomLeft),
            _ => Err(format!("Unexpected enum value '{}'", val)),
        }
    }
    fn as_str(&self) -> &'static str {
        match *self {
            Origin::TopLeft => "TopLeft",
            Origin::BottomLeft => "BottomLeft",
        }
    }
}

enum_string_serialization!(Origin OriginVisitor);

#[derive(PartialEq, Debug)]
pub enum Unit {
    M,
    DD,
    Ft,
}

impl EnumString<Unit> for Unit {
    fn from_str(val: &str) -> Result<Unit, String> {
        match val {
            "M" => Ok(Unit::M),
            "DD" => Ok(Unit::DD),
            "Ft" => Ok(Unit::Ft),
            _ => Err(format!("Unexpected enum value '{}'", val)),
        }
    }
    fn as_str(&self) -> &'static str {
        match *self {
            Unit::M => "M",
            Unit::DD => "DD",
            Unit::Ft => "Ft",
        }
    }
}

enum_string_serialization!(Unit UnitVisitor);

// Credits: MapCache by Thomas Bonfort (http://mapserver.org/mapcache/)
#[derive(Deserialize, Debug)]
pub struct Grid {
    /// The width and height of an individual tile, in pixels.
    width: u16,
    height: u16,
    /// The geographical extent covered by the grid, in ground units (e.g. meters, degrees, feet, etc.).
    /// Must be specified as 4 floating point numbers ordered as minx, miny, maxx, maxy.
    /// The (minx,miny) point defines the origin of the grid, i.e. the pixel at the bottom left of the
    /// bottom-left most tile is always placed on the (minx,miny) geographical point.
    /// The (maxx,maxy) point is used to determine how many tiles there are for each zoom level.
    pub extent: Extent,
    /// Spatial reference system (PostGIS SRID).
    pub srid: i32,
    /// Grid units
    pub units: Unit,
    /// This is a list of resolutions for each of the zoom levels defined by the grid.
    /// This must be supplied as a list of positive floating point values, ordered from largest to smallest.
    /// The largest value will correspond to the grid’s zoom level 0. Resolutions
    /// are expressed in “units-per-pixel”,
    /// depending on the unit used by the grid (e.g. resolutions are in meters per
    /// pixel for most grids used in webmapping).
    resolutions: Vec<f64>,
    /// Grid origin
    pub origin: Origin,
}

impl Grid {
    /// WGS84 grid
    pub fn wgs84() -> Grid {
        Grid {
            width: 256,
            height: 256,
            extent: Extent {
                minx: -180.0,
                miny: -90.0,
                maxx: 180.0,
                maxy: 90.0,
            },
            srid: 4236,
            units: Unit::DD,
            resolutions: vec![0.703125000000000,
                              0.351562500000000,
                              0.175781250000000,
                              8.78906250000000e-2,
                              4.39453125000000e-2,
                              2.19726562500000e-2,
                              1.09863281250000e-2,
                              5.49316406250000e-3,
                              2.74658203125000e-3,
                              1.37329101562500e-3,
                              6.86645507812500e-4,
                              3.43322753906250e-4,
                              1.71661376953125e-4,
                              8.58306884765625e-5,
                              4.29153442382812e-5,
                              2.14576721191406e-5,
                              1.07288360595703e-5,
                              5.36441802978516e-6],
            origin: Origin::BottomLeft,
        }
    }

    /// Web Mercator grid (Google maps compatible)
    pub fn web_mercator() -> Grid {
        Grid {
            width: 256,
            height: 256,
            extent: Extent {
                minx: -20037508.3427892480,
                miny: -20037508.3427892480,
                maxx: 20037508.3427892480,
                maxy: 20037508.3427892480,
            },
            srid: 3857,
            units: Unit::M,
            resolutions: vec![156543.0339280410,
                              78271.51696402048,
                              39135.75848201023,
                              19567.87924100512,
                              9783.939620502561,
                              4891.969810251280,
                              2445.984905125640,
                              1222.992452562820,
                              611.4962262814100,
                              305.7481131407048,
                              152.8740565703525,
                              76.43702828517624,
                              38.21851414258813,
                              19.10925707129406,
                              9.554628535647032,
                              4.777314267823516,
                              2.388657133911758,
                              1.194328566955879,
                              0.5971642834779395,
                              0.2985821417389700,
                              0.1492910708694850,
                              0.0746455354347424,
                              0.0373227677173712],
            origin: Origin::BottomLeft,
        }
    }

    pub fn nlevels(&self) -> u8 {
        self.resolutions.len() as u8
    }
    pub fn maxzoom(&self) -> u8 {
        self.nlevels() - 1
    }
    pub fn pixel_width(&self, zoom: u8) -> f64 {
        self.resolutions[zoom as usize] //TODO: assumes grid unit 'm'
    }
    pub fn scale_denominator(&self, zoom: u8) -> f64 {
        let pixel_screen_width = 0.0254 / 96.0; //FIXME: assumes 96dpi - check with mapnik
        self.pixel_width(zoom) / pixel_screen_width
    }
    /// Extent of a given tile in the grid given its x, y, and z in TMS adressing scheme
    pub fn tile_extent(&self, xtile: u32, ytile: u32, zoom: u8) -> Extent {
        // based on mapcache_grid_get_tile_extent
        let res = self.resolutions[zoom as usize];
        let tile_sx = self.width as f64;
        let tile_sy = self.height as f64;
        match self.origin {
            Origin::BottomLeft => {
                Extent {
                    minx: self.extent.minx + (res * xtile as f64 * tile_sx),
                    miny: self.extent.miny + (res * ytile as f64 * tile_sy),
                    maxx: self.extent.minx + (res * (xtile + 1) as f64 * tile_sx),
                    maxy: self.extent.miny + (res * (ytile + 1) as f64 * tile_sy),
                }
            }
            Origin::TopLeft => {
                Extent {
                    minx: self.extent.minx + (res * xtile as f64 * tile_sx),
                    miny: self.extent.maxy - (res * (ytile + 1) as f64 * tile_sy),
                    maxx: self.extent.minx + (res * (xtile + 1) as f64 * tile_sx),
                    maxy: self.extent.maxy - (res * ytile as f64 * tile_sy),
                }
            }
        }
    }
    /// reverse y tile for XYZ adressing scheme
    pub fn ytile_from_xyz(&self, ytile: u32, zoom: u8) -> u32 {
        let res = self.resolutions[zoom as usize];
        let unitheight = self.height as f64 * res;
        // TODO: cache maxy for each resolution
        let maxy = ((self.extent.maxy - self.extent.minx - 0.01 * unitheight) / unitheight)
            .ceil() as u32;
        let y = maxy.saturating_sub(ytile).saturating_sub(1); // y = maxy-ytile-1
        y
    }
    /// Extent of a given tile in XYZ adressing scheme
    pub fn tile_extent_xyz(&self, xtile: u32, ytile: u32, zoom: u8) -> Extent {
        let y = self.ytile_from_xyz(ytile, zoom);
        self.tile_extent(xtile, y, zoom)
    }
    /// (maxx, maxy) of grid level
    pub fn level_limit(&self, zoom: u8) -> (u32, u32) {
        let res = self.resolutions[zoom as usize];
        let unitheight = self.height as f64 * res;
        let unitwidth = self.width as f64 * res;

        let maxy = ((self.extent.maxy - self.extent.miny - 0.01 * unitheight) / unitheight)
            .ceil() as u32;
        let maxx = ((self.extent.maxx - self.extent.miny - 0.01 * unitwidth) / unitwidth)
            .ceil() as u32;
        (maxx, maxy)
    }
    /// Tile index limits covering extent
    pub fn tile_limits(&self, extent: Extent, tolerance: i32) -> Vec<ExtentInt> {
        // Based on mapcache_grid_compute_limits
        const EPSILON: f64 = 0.0000001;
        let nlevels = self.resolutions.len() as u8;
        (0..nlevels)
            .map(|i| {
                let res = self.resolutions[i as usize];
                let unitheight = self.height as f64 * res;
                let unitwidth = self.width as f64 * res;
                let (level_maxx, level_maxy) = self.level_limit(i);

                let (mut minx, mut maxx, mut miny, mut maxy) = match self.origin {
                    Origin::BottomLeft => {
                        ((((extent.minx - self.extent.minx) / unitwidth + EPSILON).floor() as
                          i32) - tolerance,
                         (((extent.maxx - self.extent.minx) / unitwidth - EPSILON).ceil() as
                          i32) + tolerance,
                         (((extent.miny - self.extent.miny) / unitheight + EPSILON).floor() as
                          i32) - tolerance,
                         (((extent.maxy - self.extent.miny) / unitheight - EPSILON).ceil() as
                          i32) + tolerance)
                    }
                    Origin::TopLeft => {
                        ((((extent.minx - self.extent.minx) / unitwidth + EPSILON).floor() as
                          i32) - tolerance,
                         (((extent.maxx - self.extent.minx) / unitwidth - EPSILON).ceil() as
                          i32) + tolerance,
                         (((self.extent.maxy - extent.maxy) / unitheight + EPSILON).floor() as
                          i32) - tolerance,
                         (((self.extent.maxy - extent.miny) / unitheight - EPSILON).ceil() as
                          i32) + tolerance)
                    }
                };

                // to avoid requesting out-of-range tiles
                if minx < 0 {
                    minx = 0;
                }
                if maxx > level_maxx as i32 {
                    maxx = level_maxx as i32
                };
                if miny < 0 {
                    miny = 0
                };
                if maxy > level_maxy as i32 {
                    maxy = level_maxy as i32
                };

                ExtentInt {
                    minx: minx as u32,
                    maxx: maxx as u32,
                    miny: miny as u32,
                    maxy: maxy as u32,
                }
            })
            .collect()
    }
}

impl Config<Grid> for Grid {
    fn from_config(config: &toml::Value) -> Result<Self, String> {
        if config.get("grid").is_none() {
            return Err("Missing configuration entry [grid]".to_string());
        }
        if let Some(predef) = config.get("grid").and_then(|g| g.get("predefined")) {
            predef
                .as_str()
                .ok_or("grid.predefined entry is not a string".to_string())
                .and_then(|gridname| match gridname {
                              "wgs84" => Ok(Grid::wgs84()),
                              "web_mercator" => Ok(Grid::web_mercator()),
                              _ => Err(format!("Unkown grid '{}'", gridname)),
                          })
        } else {
            let ref gridcfg = config["grid"];
            let grid = gridcfg.clone().try_into::<Grid>();
            grid.map_err(|e| format!("Error reading configuration - {}", e))
        }
    }
    fn gen_config() -> String {
        let toml = r#"
[grid]
# Predefined grids: web_mercator, wgs84
predefined = "web_mercator"
"#;
        toml.to_string()
    }
}
<commit_msg>Fix grid WGS84 srid<commit_after>//
// Copyright (c) Pirmin Kalberer. All rights reserved.
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
//

use core::Config;
use core::enum_serializer::EnumString;
use toml;
use serde;
use serde::de::{Deserialize, Deserializer};
use std::fmt;

#[derive(PartialEq, Deserialize, Debug)]
pub struct Extent {
    pub minx: f64,
    pub miny: f64,
    pub maxx: f64,
    pub maxy: f64,
}

/// Min and max grid cell numbers
#[derive(PartialEq,Debug)]
pub struct ExtentInt {
    pub minx: u32,
    pub miny: u32,
    pub maxx: u32,
    pub maxy: u32,
}

#[derive(PartialEq, Debug)]
pub enum Origin {
    TopLeft,
    BottomLeft, //TopRight, BottomRight
}

impl EnumString<Origin> for Origin {
    fn from_str(val: &str) -> Result<Origin, String> {
        match val {
            "TopLeft" => Ok(Origin::TopLeft),
            "BottomLeft" => Ok(Origin::BottomLeft),
            _ => Err(format!("Unexpected enum value '{}'", val)),
        }
    }
    fn as_str(&self) -> &'static str {
        match *self {
            Origin::TopLeft => "TopLeft",
            Origin::BottomLeft => "BottomLeft",
        }
    }
}

enum_string_serialization!(Origin OriginVisitor);

#[derive(PartialEq, Debug)]
pub enum Unit {
    M,
    DD,
    Ft,
}

impl EnumString<Unit> for Unit {
    fn from_str(val: &str) -> Result<Unit, String> {
        match val {
            "M" => Ok(Unit::M),
            "DD" => Ok(Unit::DD),
            "Ft" => Ok(Unit::Ft),
            _ => Err(format!("Unexpected enum value '{}'", val)),
        }
    }
    fn as_str(&self) -> &'static str {
        match *self {
            Unit::M => "M",
            Unit::DD => "DD",
            Unit::Ft => "Ft",
        }
    }
}

enum_string_serialization!(Unit UnitVisitor);

// Credits: MapCache by Thomas Bonfort (http://mapserver.org/mapcache/)
#[derive(Deserialize, Debug)]
pub struct Grid {
    /// The width and height of an individual tile, in pixels.
    width: u16,
    height: u16,
    /// The geographical extent covered by the grid, in ground units (e.g. meters, degrees, feet, etc.).
    /// Must be specified as 4 floating point numbers ordered as minx, miny, maxx, maxy.
    /// The (minx,miny) point defines the origin of the grid, i.e. the pixel at the bottom left of the
    /// bottom-left most tile is always placed on the (minx,miny) geographical point.
    /// The (maxx,maxy) point is used to determine how many tiles there are for each zoom level.
    pub extent: Extent,
    /// Spatial reference system (PostGIS SRID).
    pub srid: i32,
    /// Grid units
    pub units: Unit,
    /// This is a list of resolutions for each of the zoom levels defined by the grid.
    /// This must be supplied as a list of positive floating point values, ordered from largest to smallest.
    /// The largest value will correspond to the grid’s zoom level 0. Resolutions
    /// are expressed in “units-per-pixel”,
    /// depending on the unit used by the grid (e.g. resolutions are in meters per
    /// pixel for most grids used in webmapping).
    resolutions: Vec<f64>,
    /// Grid origin
    pub origin: Origin,
}

impl Grid {
    /// WGS84 grid
    pub fn wgs84() -> Grid {
        Grid {
            width: 256,
            height: 256,
            extent: Extent {
                minx: -180.0,
                miny: -90.0,
                maxx: 180.0,
                maxy: 90.0,
            },
            srid: 4326,
            units: Unit::DD,
            resolutions: vec![0.703125000000000,
                              0.351562500000000,
                              0.175781250000000,
                              8.78906250000000e-2,
                              4.39453125000000e-2,
                              2.19726562500000e-2,
                              1.09863281250000e-2,
                              5.49316406250000e-3,
                              2.74658203125000e-3,
                              1.37329101562500e-3,
                              6.86645507812500e-4,
                              3.43322753906250e-4,
                              1.71661376953125e-4,
                              8.58306884765625e-5,
                              4.29153442382812e-5,
                              2.14576721191406e-5,
                              1.07288360595703e-5,
                              5.36441802978516e-6],
            origin: Origin::BottomLeft,
        }
    }

    /// Web Mercator grid (Google maps compatible)
    pub fn web_mercator() -> Grid {
        Grid {
            width: 256,
            height: 256,
            extent: Extent {
                minx: -20037508.3427892480,
                miny: -20037508.3427892480,
                maxx: 20037508.3427892480,
                maxy: 20037508.3427892480,
            },
            srid: 3857,
            units: Unit::M,
            resolutions: vec![156543.0339280410,
                              78271.51696402048,
                              39135.75848201023,
                              19567.87924100512,
                              9783.939620502561,
                              4891.969810251280,
                              2445.984905125640,
                              1222.992452562820,
                              611.4962262814100,
                              305.7481131407048,
                              152.8740565703525,
                              76.43702828517624,
                              38.21851414258813,
                              19.10925707129406,
                              9.554628535647032,
                              4.777314267823516,
                              2.388657133911758,
                              1.194328566955879,
                              0.5971642834779395,
                              0.2985821417389700,
                              0.1492910708694850,
                              0.0746455354347424,
                              0.0373227677173712],
            origin: Origin::BottomLeft,
        }
    }

    pub fn nlevels(&self) -> u8 {
        self.resolutions.len() as u8
    }
    pub fn maxzoom(&self) -> u8 {
        self.nlevels() - 1
    }
    pub fn pixel_width(&self, zoom: u8) -> f64 {
        self.resolutions[zoom as usize] //TODO: assumes grid unit 'm'
    }
    pub fn scale_denominator(&self, zoom: u8) -> f64 {
        let pixel_screen_width = 0.0254 / 96.0; //FIXME: assumes 96dpi - check with mapnik
        self.pixel_width(zoom) / pixel_screen_width
    }
    /// Extent of a given tile in the grid given its x, y, and z in TMS adressing scheme
    pub fn tile_extent(&self, xtile: u32, ytile: u32, zoom: u8) -> Extent {
        // based on mapcache_grid_get_tile_extent
        let res = self.resolutions[zoom as usize];
        let tile_sx = self.width as f64;
        let tile_sy = self.height as f64;
        match self.origin {
            Origin::BottomLeft => {
                Extent {
                    minx: self.extent.minx + (res * xtile as f64 * tile_sx),
                    miny: self.extent.miny + (res * ytile as f64 * tile_sy),
                    maxx: self.extent.minx + (res * (xtile + 1) as f64 * tile_sx),
                    maxy: self.extent.miny + (res * (ytile + 1) as f64 * tile_sy),
                }
            }
            Origin::TopLeft => {
                Extent {
                    minx: self.extent.minx + (res * xtile as f64 * tile_sx),
                    miny: self.extent.maxy - (res * (ytile + 1) as f64 * tile_sy),
                    maxx: self.extent.minx + (res * (xtile + 1) as f64 * tile_sx),
                    maxy: self.extent.maxy - (res * ytile as f64 * tile_sy),
                }
            }
        }
    }
    /// reverse y tile for XYZ adressing scheme
    pub fn ytile_from_xyz(&self, ytile: u32, zoom: u8) -> u32 {
        let res = self.resolutions[zoom as usize];
        let unitheight = self.height as f64 * res;
        // TODO: cache maxy for each resolution
        let maxy = ((self.extent.maxy - self.extent.minx - 0.01 * unitheight) / unitheight)
            .ceil() as u32;
        let y = maxy.saturating_sub(ytile).saturating_sub(1); // y = maxy-ytile-1
        y
    }
    /// Extent of a given tile in XYZ adressing scheme
    pub fn tile_extent_xyz(&self, xtile: u32, ytile: u32, zoom: u8) -> Extent {
        let y = self.ytile_from_xyz(ytile, zoom);
        self.tile_extent(xtile, y, zoom)
    }
    /// (maxx, maxy) of grid level
    pub fn level_limit(&self, zoom: u8) -> (u32, u32) {
        let res = self.resolutions[zoom as usize];
        let unitheight = self.height as f64 * res;
        let unitwidth = self.width as f64 * res;

        let maxy = ((self.extent.maxy - self.extent.miny - 0.01 * unitheight) / unitheight)
            .ceil() as u32;
        let maxx = ((self.extent.maxx - self.extent.miny - 0.01 * unitwidth) / unitwidth)
            .ceil() as u32;
        (maxx, maxy)
    }
    /// Tile index limits covering extent
    pub fn tile_limits(&self, extent: Extent, tolerance: i32) -> Vec<ExtentInt> {
        // Based on mapcache_grid_compute_limits
        const EPSILON: f64 = 0.0000001;
        let nlevels = self.resolutions.len() as u8;
        (0..nlevels)
            .map(|i| {
                let res = self.resolutions[i as usize];
                let unitheight = self.height as f64 * res;
                let unitwidth = self.width as f64 * res;
                let (level_maxx, level_maxy) = self.level_limit(i);

                let (mut minx, mut maxx, mut miny, mut maxy) = match self.origin {
                    Origin::BottomLeft => {
                        ((((extent.minx - self.extent.minx) / unitwidth + EPSILON).floor() as
                          i32) - tolerance,
                         (((extent.maxx - self.extent.minx) / unitwidth - EPSILON).ceil() as
                          i32) + tolerance,
                         (((extent.miny - self.extent.miny) / unitheight + EPSILON).floor() as
                          i32) - tolerance,
                         (((extent.maxy - self.extent.miny) / unitheight - EPSILON).ceil() as
                          i32) + tolerance)
                    }
                    Origin::TopLeft => {
                        ((((extent.minx - self.extent.minx) / unitwidth + EPSILON).floor() as
                          i32) - tolerance,
                         (((extent.maxx - self.extent.minx) / unitwidth - EPSILON).ceil() as
                          i32) + tolerance,
                         (((self.extent.maxy - extent.maxy) / unitheight + EPSILON).floor() as
                          i32) - tolerance,
                         (((self.extent.maxy - extent.miny) / unitheight - EPSILON).ceil() as
                          i32) + tolerance)
                    }
                };

                // to avoid requesting out-of-range tiles
                if minx < 0 {
                    minx = 0;
                }
                if maxx > level_maxx as i32 {
                    maxx = level_maxx as i32
                };
                if miny < 0 {
                    miny = 0
                };
                if maxy > level_maxy as i32 {
                    maxy = level_maxy as i32
                };

                ExtentInt {
                    minx: minx as u32,
                    maxx: maxx as u32,
                    miny: miny as u32,
                    maxy: maxy as u32,
                }
            })
            .collect()
    }
}

impl Config<Grid> for Grid {
    fn from_config(config: &toml::Value) -> Result<Self, String> {
        if config.get("grid").is_none() {
            return Err("Missing configuration entry [grid]".to_string());
        }
        if let Some(predef) = config.get("grid").and_then(|g| g.get("predefined")) {
            predef
                .as_str()
                .ok_or("grid.predefined entry is not a string".to_string())
                .and_then(|gridname| match gridname {
                              "wgs84" => Ok(Grid::wgs84()),
                              "web_mercator" => Ok(Grid::web_mercator()),
                              _ => Err(format!("Unkown grid '{}'", gridname)),
                          })
        } else {
            let ref gridcfg = config["grid"];
            let grid = gridcfg.clone().try_into::<Grid>();
            grid.map_err(|e| format!("Error reading configuration - {}", e))
        }
    }
    fn gen_config() -> String {
        let toml = r#"
[grid]
# Predefined grids: web_mercator, wgs84
predefined = "web_mercator"
"#;
        toml.to_string()
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use std::f32::consts;

use {clamp, Normal3f, Point2f, Point3f, Transform, Vector3f};
use bounds::Bounds3f;
use interaction::{Interaction, SurfaceInteraction};
use paramset::ParamSet;
use ray::Ray;
use sampling::concentric_sample_disk;
use shapes::Shape;

#[derive(Debug)]
pub struct Disk {
    height: f32,
    radius: f32,
    inner_radius: f32,
    phi_max: f32,
    object_to_world: Transform,
    world_to_object: Transform,
    reverse_orientation: bool,
    transform_swaps_handedness: bool,
}

impl Disk {
    pub fn new(height: f32,
               radius: f32,
               inner_radius: f32,
               phi_max: f32,
               object_to_world: Transform,
               reverse_orientation: bool)
               -> Disk {
        assert!(radius > 0.0 && inner_radius >= 0.0 && phi_max > 0.0);
        let transform_swaps_handedness = object_to_world.swaps_handedness();
        Disk {
            height: height,
            radius: radius,
            inner_radius: inner_radius,
            phi_max: clamp(phi_max, 0.0, 360.0).to_radians(),
            world_to_object: object_to_world.inverse(),
            object_to_world: object_to_world,
            reverse_orientation,
            transform_swaps_handedness,
        }
    }

    pub fn create(o2w: &Transform,
                  reverse_orientation: bool,
                  params: &mut ParamSet)
                  -> Arc<Shape + Send + Sync> {
        let height = params.find_one_float("height", 0.0);
        let radius = params.find_one_float("radius", 1.0);
        let inner_radius = params.find_one_float("innerradius", 0.0);
        let phimax = params.find_one_float("phimax", 360.0);

        Arc::new(Disk::new(height,
                           radius,
                           inner_radius,
                           phimax,
                           o2w.clone(),
                           reverse_orientation))
    }
}

impl Shape for Disk {
    fn intersect(&self, r: &Ray) -> Option<(SurfaceInteraction, f32)> {
        // Transform ray to object space
        let (ray, _o_err, _d_err) = r.transform(&self.world_to_object);
        // Compute plane intersection for disk
        if ray.d.z == 0.0 {
            // Reject disk intersection for rays parallel to the disk plane
            return None;
        }
        let t_shape_hit = (self.height - ray.o.z) / ray.d.z;
        if t_shape_hit <= 0.0 || t_shape_hit > ray.t_max {
            return None;
        }
        // See if hit point is inside radii and phi_max
        let mut p_hit = ray.at(t_shape_hit);
        let dist2 = p_hit.x * p_hit.x + p_hit.y * p_hit.y;
        if dist2 > self.radius * self.radius || dist2 < self.inner_radius * self.inner_radius {
            return None;
        }
        let mut phi = p_hit.y.atan2(p_hit.x);
        if phi < 0.0 {
            phi += 2.0 * consts::PI;
        }
        if phi > self.phi_max {
            return None;
        }
        // Find parametric representation of disk hit
        let u = phi / self.phi_max;
        let r_hit = dist2.sqrt();
        let one_minus_v = (r_hit - self.inner_radius) / (self.radius - self.inner_radius);
        let v = 1.0 - one_minus_v;
        let dpdu = Vector3f::new(-self.phi_max * p_hit.y, self.phi_max * p_hit.x, 0.0);
        let dpdv = Vector3f::new(p_hit.x, p_hit.y, 0.0) * (self.inner_radius - self.radius) / r_hit;
        let dndu = Normal3f::new(0.0, 0.0, 0.0);
        let dndv = Normal3f::new(0.0, 0.0, 0.0);

        // Refine disk intersection point
        p_hit.z = self.height;

        // Compute error bounds for intersection point
        let p_err = Vector3f::new(0.0, 0.0, 0.0);
        // Initialize SurfaceInteraction from parametric information
        let isect = SurfaceInteraction::new(p_hit,
                                            p_err,
                                            Point2f::new(u, v),
                                            -ray.d,
                                            dpdu,
                                            dpdv,
                                            dndu,
                                            dndv,
                                            self);
        // Update t_hit for quadric intersection

        Some((isect.transform(&self.object_to_world), t_shape_hit))
    }

    fn object_bounds(&self) -> Bounds3f {
        Bounds3f::from_points(&Point3f::new(-self.radius, -self.radius, self.height),
                              &Point3f::new(self.radius, self.radius, self.height))
    }

    fn world_bounds(&self) -> Bounds3f {
        let ob = self.object_bounds();
        let p1 = &self.object_to_world * &ob.p_min;
        let p2 = &self.object_to_world * &ob.p_max;
        let p_min = Point3f::new(p1.x.min(p2.x), p1.y.min(p2.y), p1.z.min(p2.z));
        let p_max = Point3f::new(p1.x.max(p2.x), p1.y.max(p2.y), p1.z.max(p2.z));
        Bounds3f::from_points(&p_min, &p_max)
    }

    fn sample(&self, u: &Point2f) -> (Interaction, f32) {
        let pd = concentric_sample_disk(u);
        let p_obj = Point3f::new(pd.x * self.radius, pd.y * self.radius, self.height);
        let mut it = Interaction::empty();
        it.n = (&self.object_to_world * &Normal3f::new(0.0, 0.0, 1.0)).normalize();
        if self.reverse_orientation {
            it.n = -it.n;
        }
        let (p, p_err) = self.object_to_world
            .transform_point_with_error(&p_obj, &Vector3f::new(0.0, 0.0, 0.0));
        it.p = p;
        it.p_error = p_err;
        let pdf = 1.0 / self.area();

        (it, pdf)
    }

    fn area(&self) -> f32 {
        self.phi_max * 0.5 * (self.radius * self.radius - self.inner_radius * self.inner_radius)
    }

    fn reverse_orientation(&self) -> bool {
        self.reverse_orientation
    }

    fn transform_swaps_handedness(&self) -> bool {
        self.transform_swaps_handedness
    }
}
<commit_msg>Fix disk dPdv computation<commit_after>use std::sync::Arc;
use std::f32::consts;

use {clamp, Normal3f, Point2f, Point3f, Transform, Vector3f};
use bounds::Bounds3f;
use interaction::{Interaction, SurfaceInteraction};
use paramset::ParamSet;
use ray::Ray;
use sampling::concentric_sample_disk;
use shapes::Shape;

#[derive(Debug)]
pub struct Disk {
    height: f32,
    radius: f32,
    inner_radius: f32,
    phi_max: f32,
    object_to_world: Transform,
    world_to_object: Transform,
    reverse_orientation: bool,
    transform_swaps_handedness: bool,
}

impl Disk {
    pub fn new(height: f32,
               radius: f32,
               inner_radius: f32,
               phi_max: f32,
               object_to_world: Transform,
               reverse_orientation: bool)
               -> Disk {
        assert!(radius > 0.0 && inner_radius >= 0.0 && phi_max > 0.0);
        let transform_swaps_handedness = object_to_world.swaps_handedness();
        Disk {
            height: height,
            radius: radius,
            inner_radius: inner_radius,
            phi_max: clamp(phi_max, 0.0, 360.0).to_radians(),
            world_to_object: object_to_world.inverse(),
            object_to_world: object_to_world,
            reverse_orientation,
            transform_swaps_handedness,
        }
    }

    pub fn create(o2w: &Transform,
                  reverse_orientation: bool,
                  params: &mut ParamSet)
                  -> Arc<Shape + Send + Sync> {
        let height = params.find_one_float("height", 0.0);
        let radius = params.find_one_float("radius", 1.0);
        let inner_radius = params.find_one_float("innerradius", 0.0);
        let phimax = params.find_one_float("phimax", 360.0);

        Arc::new(Disk::new(height,
                           radius,
                           inner_radius,
                           phimax,
                           o2w.clone(),
                           reverse_orientation))
    }
}

impl Shape for Disk {
    fn intersect(&self, r: &Ray) -> Option<(SurfaceInteraction, f32)> {
        // Transform ray to object space
        let (ray, _o_err, _d_err) = r.transform(&self.world_to_object);
        // Compute plane intersection for disk
        if ray.d.z == 0.0 {
            // Reject disk intersection for rays parallel to the disk plane
            return None;
        }
        let t_shape_hit = (self.height - ray.o.z) / ray.d.z;
        if t_shape_hit <= 0.0 || t_shape_hit > ray.t_max {
            return None;
        }
        // See if hit point is inside radii and phi_max
        let mut p_hit = ray.at(t_shape_hit);
        let dist2 = p_hit.x * p_hit.x + p_hit.y * p_hit.y;
        if dist2 > self.radius * self.radius || dist2 < self.inner_radius * self.inner_radius {
            return None;
        }
        let mut phi = p_hit.y.atan2(p_hit.x);
        if phi < 0.0 {
            phi += 2.0 * consts::PI;
        }
        if phi > self.phi_max {
            return None;
        }
        // Find parametric representation of disk hit
        let u = phi / self.phi_max;
        let r_hit = dist2.sqrt();
        let one_minus_v = (r_hit - self.inner_radius) / (self.radius - self.inner_radius);
        let v = 1.0 - one_minus_v;
        let dpdu = Vector3f::new(-self.phi_max * p_hit.y, self.phi_max * p_hit.x, 0.0);
        let dpdv = Vector3f::new(p_hit.x, p_hit.y, 0.0) * (self.radius - self.inner_radius) / r_hit;
        let dndu = Normal3f::new(0.0, 0.0, 0.0);
        let dndv = Normal3f::new(0.0, 0.0, 0.0);

        // Refine disk intersection point
        p_hit.z = self.height;

        // Compute error bounds for intersection point
        let p_err = Vector3f::new(0.0, 0.0, 0.0);
        // Initialize SurfaceInteraction from parametric information
        let isect = SurfaceInteraction::new(p_hit,
                                            p_err,
                                            Point2f::new(u, v),
                                            -ray.d,
                                            dpdu,
                                            dpdv,
                                            dndu,
                                            dndv,
                                            self);
        // Update t_hit for quadric intersection

        Some((isect.transform(&self.object_to_world), t_shape_hit))
    }

    fn object_bounds(&self) -> Bounds3f {
        Bounds3f::from_points(&Point3f::new(-self.radius, -self.radius, self.height),
                              &Point3f::new(self.radius, self.radius, self.height))
    }

    fn world_bounds(&self) -> Bounds3f {
        let ob = self.object_bounds();
        let p1 = &self.object_to_world * &ob.p_min;
        let p2 = &self.object_to_world * &ob.p_max;
        let p_min = Point3f::new(p1.x.min(p2.x), p1.y.min(p2.y), p1.z.min(p2.z));
        let p_max = Point3f::new(p1.x.max(p2.x), p1.y.max(p2.y), p1.z.max(p2.z));
        Bounds3f::from_points(&p_min, &p_max)
    }

    fn sample(&self, u: &Point2f) -> (Interaction, f32) {
        let pd = concentric_sample_disk(u);
        let p_obj = Point3f::new(pd.x * self.radius, pd.y * self.radius, self.height);
        let mut it = Interaction::empty();
        it.n = (&self.object_to_world * &Normal3f::new(0.0, 0.0, 1.0)).normalize();
        if self.reverse_orientation {
            it.n = -it.n;
        }
        let (p, p_err) = self.object_to_world
            .transform_point_with_error(&p_obj, &Vector3f::new(0.0, 0.0, 0.0));
        it.p = p;
        it.p_error = p_err;
        let pdf = 1.0 / self.area();

        (it, pdf)
    }

    fn area(&self) -> f32 {
        self.phi_max * 0.5 * (self.radius * self.radius - self.inner_radius * self.inner_radius)
    }

    fn reverse_orientation(&self) -> bool {
        self.reverse_orientation
    }

    fn transform_swaps_handedness(&self) -> bool {
        self.transform_swaps_handedness
    }
}
<|endoftext|>


<commit_before>
#![allow(clippy::All)]
#![warn(clippy::pedantic)]

#[warn(clippy::if_not_els)]
fn main() {

}
<commit_msg>Add copyright statement©<commit_after>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(clippy::All)]
#![warn(clippy::pedantic)]

#[warn(clippy::if_not_els)]
fn main() {

}
<|endoftext|>