<commit_before>extern crate gcc;
extern crate metadeps;

use std::env;
use std::fs;
use std::path::PathBuf;
use std::process::Command;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(t) => t,
        Err(e) => panic!("{} return the error {}", stringify!($e), e),
    })
}

fn main() {
    // Use the installed libcares if it is available.
    if metadeps::probe().is_ok() {
        return
    }

    // MSVC builds are different.
    let target = env::var("TARGET").unwrap();
    if target.contains("msvc") {
        build_msvc(&target);
        return
    }

    // Set up compiler options.
    let mut cflags = env::var("CFLAGS").unwrap_or(String::new());
    if target.contains("i686") {
        cflags.push_str(" -m32");
    } else if target.contains("x86_64") {
        cflags.push_str(" -m64");
    }
    if !target.contains("i686") {
        cflags.push_str(" -fPIC");
    }

    let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let build = dst.join("build");
    let _ = fs::create_dir(&build);

    let mut config_opts = Vec::new();
    config_opts.push("--enable-static=yes".to_string());
    config_opts.push("--enable-shared=no".to_string());
    config_opts.push("--enable-optimize".to_string());
    config_opts.push(format!("--prefix={}", dst.display()));

    // Prepare.
    let src = env::current_dir().unwrap();
    run(
        Command::new("sh")
            .current_dir(&src.join("c-ares"))
            .arg("buildconf")
    );
    run(
        Command::new("sh")
            .env("CFLAGS", &cflags)
            .current_dir(&build)
            .arg("-c")
            .arg(
                format!(
                    "{} {}",
                    src.join("c-ares/configure").display(),
                    config_opts.join(" ")
                )
            )
    );

    // Compile.
    run(
        Command::new(make())
            .arg(format!("-j{}", env::var("NUM_JOBS").unwrap()))
            .current_dir(&build)
    );

    // Link to compiled library.
    println!("cargo:rustc-link-search={}/.libs", build.display());
    println!("cargo:rustc-link-lib=static=cares");
}

fn run(cmd: &mut Command) {
    println!("running: {:?}", cmd);
    assert!(t!(cmd.status()).success());
}

fn make() -> &'static str {
    if cfg!(target_os = "freebsd") {"gmake"} else {"make"}
}

fn build_msvc(target: &str) {
    // Prepare.
    let src = env::current_dir().unwrap();
    let c_ares_dir = &src.join("c-ares");
    run(
        Command::new("cmd")
            .current_dir(c_ares_dir)
            .arg("/c")
            .arg("buildconf.bat")
    );

    // Compile.
    let mut cmd = gcc::windows_registry::find(target, "nmake.exe").unwrap();
    cmd.current_dir(c_ares_dir);
    cmd.args(&["/f", "Makefile.msvc", "CFG=lib-release", "c-ares"]);
    run(&mut cmd);

    // Install library.
    let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let build = dst.join("build");
    let mut cmd = gcc::windows_registry::find(target, "nmake.exe").unwrap();
    cmd.current_dir(c_ares_dir);
    cmd.args(&["/f", "Makefile.msvc", "/a", "CFG=lib-release", "install"]);
    cmd.env("INSTALL_DIR", format!("{}", build.display()));
    run(&mut cmd);

    // Link to compiled library.
    println!("cargo:rustc-link-search={}/lib", build.display());
    println!("cargo:rustc-link-lib=static=libcares");
}
<commit_msg>clippy<commit_after>extern crate gcc;
extern crate metadeps;

use std::env;
use std::fs;
use std::path::PathBuf;
use std::process::Command;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(t) => t,
        Err(e) => panic!("{} return the error {}", stringify!($e), e),
    })
}

fn main() {
    // Use the installed libcares if it is available.
    if metadeps::probe().is_ok() {
        return
    }

    // MSVC builds are different.
    let target = env::var("TARGET").unwrap();
    if target.contains("msvc") {
        build_msvc(&target);
        return
    }

    // Set up compiler options.
    let mut cflags = env::var("CFLAGS").unwrap_or_else(|_| String::new());
    if target.contains("i686") {
        cflags.push_str(" -m32");
    } else if target.contains("x86_64") {
        cflags.push_str(" -m64");
    }
    if !target.contains("i686") {
        cflags.push_str(" -fPIC");
    }

    let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let build = dst.join("build");
    let _ = fs::create_dir(&build);

    let mut config_opts = Vec::new();
    config_opts.push("--enable-static=yes".to_string());
    config_opts.push("--enable-shared=no".to_string());
    config_opts.push("--enable-optimize".to_string());
    config_opts.push(format!("--prefix={}", dst.display()));

    // Prepare.
    let src = env::current_dir().unwrap();
    run(
        Command::new("sh")
            .current_dir(&src.join("c-ares"))
            .arg("buildconf")
    );
    run(
        Command::new("sh")
            .env("CFLAGS", &cflags)
            .current_dir(&build)
            .arg("-c")
            .arg(
                format!(
                    "{} {}",
                    src.join("c-ares/configure").display(),
                    config_opts.join(" ")
                )
            )
    );

    // Compile.
    run(
        Command::new(make())
            .arg(format!("-j{}", env::var("NUM_JOBS").unwrap()))
            .current_dir(&build)
    );

    // Link to compiled library.
    println!("cargo:rustc-link-search={}/.libs", build.display());
    println!("cargo:rustc-link-lib=static=cares");
}

fn run(cmd: &mut Command) {
    println!("running: {:?}", cmd);
    assert!(t!(cmd.status()).success());
}

fn make() -> &'static str {
    if cfg!(target_os = "freebsd") {"gmake"} else {"make"}
}

fn build_msvc(target: &str) {
    // Prepare.
    let src = env::current_dir().unwrap();
    let c_ares_dir = &src.join("c-ares");
    run(
        Command::new("cmd")
            .current_dir(c_ares_dir)
            .arg("/c")
            .arg("buildconf.bat")
    );

    // Compile.
    let mut cmd = gcc::windows_registry::find(target, "nmake.exe").unwrap();
    cmd.current_dir(c_ares_dir);
    cmd.args(&["/f", "Makefile.msvc", "CFG=lib-release", "c-ares"]);
    run(&mut cmd);

    // Install library.
    let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let build = dst.join("build");
    let mut cmd = gcc::windows_registry::find(target, "nmake.exe").unwrap();
    cmd.current_dir(c_ares_dir);
    cmd.args(&["/f", "Makefile.msvc", "/a", "CFG=lib-release", "install"]);
    cmd.env("INSTALL_DIR", format!("{}", build.display()));
    run(&mut cmd);

    // Link to compiled library.
    println!("cargo:rustc-link-search={}/lib", build.display());
    println!("cargo:rustc-link-lib=static=libcares");
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use std::ops::{Deref, DerefMut};

use ndarray::Array2;
use jagged_array::Jagged2;

use render::Renderer;
use resman::AudioBuffer;
use routing::{Edge, GraphWatcher, NodeData, NodeHandle};
use routing::effect::{PrimitiveEffect, EffectData};
use streaming_iterator::StreamingIterator;
use util::unpack_f32;

#[derive(Debug)]
struct NodeMap {
    nodes: HashMap<NodeHandle, Node>,
}

#[derive(Default, Debug)]
pub struct RefRenderer {
    nodes: NodeMap,
    /// inputs[slot][sample] represents the value of the external input at
    /// the given slot and time. On OOB, it is assumed to be 0.
    inputs: Vec<Vec<f32>>,
    /// Next expected sample to be queried.
    /// This is tracked because if we do a seek, the inputs need to be zero'd.
    head: u64,
}

#[derive(Default, Debug)]
struct Node {
    data: Option<MyNodeData>,
    inbound: HashSet<Edge>
}

#[derive(Debug)]
enum MyNodeData {
    /// This node is a non-primitive effect.
    UserNode(NodeMap),
    /// Primitive effect (delay, constant, etc).
    Primitive(PrimitiveEffect),
    /// External audio.
    Buffer(AudioBuffer),
}

impl Renderer for RefRenderer {
    fn fill_buffer(&mut self, buff: &mut Array2<f32>, idx: u64, inputs: Jagged2<f32>) {
        // Store inputs for future use
        {
            if idx != self.head {
                for slot in &mut self.inputs {
                    *slot = Vec::new();
                }
            }
            if self.inputs.len() < buff.len() {
                self.inputs.resize(buff.len(), Default::default());
            }
            let mut stream = inputs.stream();
            let mut self_it = self.inputs.iter_mut();
            while let (Some(row), Some(vec_dest)) = (stream.next(), self_it.next()) {
                // NB: Improper indexing on 32-bit OS, but will OOM first.
                vec_dest.resize(idx as usize, 0f32);
                vec_dest.extend(row);
            }
        }

        // Calculate outputs
        let (n_slots, n_times) = buff.dim().into();
        for slot in 0..n_slots as u32 {
            for time in idx..idx+n_times as u64 {
                buff[[slot as usize, time as usize]] = self.get_sample(time, slot);
            }
        }
        // Keep track of the playhead
        self.head = idx + n_times as u64;
    }
}
impl RefRenderer {
    fn get_sample(&mut self, time: u64, slot: u32) -> f32 {
        let node = &self.nodes[&NodeHandle::toplevel()];
        // find all edges to ([Null], slot=slot)
        let edges_out = node.inbound.iter().filter(|in_edge| {
            in_edge.to_slot() == slot
        });
        // Sum the outputs
        let total: f64 = edges_out.map(|edge| {
            self.get_value(&self.nodes, edge, time, &Vec::new())
        }).sum();
        total as f32
    }
    /// Get the value on an edge at a particular time
    /// When backtracking from the output, we push each Node onto the context if we enter inside of
    ///   it (i.e. if it's a nested DAG) & pop when exiting.
    fn get_value(&self, nodes: &NodeMap, edge: &Edge, time: u64, context: &Vec<(&NodeMap, NodeHandle)>) -> f64 {
        let from = edge.from_full();
        if *from.node_handle() == None {
            // Reading from one of the inputs to the top of `context`
            // TODO: we can avoid cloning by reversing the pop after recursing.
            let mut new_context = context.clone();
            let (new_nodes, head) = new_context.pop().unwrap();
            // Sum the inputs to the matching slot
            self.sum_input_to_slot(new_nodes, &new_nodes[&head], time, edge.from_slot(), &new_context)
        } else {
            // Reading from another node within the DAG
            let node = &nodes[&from];
            match *node.data.as_ref().expect("Expected node to have associated data") {
                MyNodeData::UserNode(ref new_nodes) => {
                    let mut new_context = context.clone();
                    new_context.push((nodes, from));
                    // Now find the *output* of the sub dag (or 0 if the sub dag has no outputs)
                    new_nodes.get(&NodeHandle::toplevel()).map_or(0f64, |root_node| {
                        self.sum_input_to_slot(new_nodes, root_node, time, edge.from_slot(), &new_context)
                    })
                },
                MyNodeData::Primitive(prim) => match prim {
                    // Output = sum of all inputs to slot 0.
                    PrimitiveEffect::Delay => {
                        // The only nonzero output is slot=0.
                        if edge.from_slot() != 0 {
                            warn!("Attempt to read from Delay slot != 0");
                            0f64
                        } else {
                            let delay_frames = self.sum_input_to_slot(nodes, node, time, 1, context);
                            // Clamp delay value to [0, u64::max]
                            let delay_int = if delay_frames < 0f64 {
                                0u64
                            } else if delay_frames > u64::max_value() as f64 {
                                // TODO: u64::max isn't precisely representable in f64;
                                // will this cause issues?
                                u64::max_value()
                            } else {
                                // Note: this conversion is flooring.
                                delay_frames as u64
                            };
                            // t<0 -> value is 0.
                            time.checked_sub(delay_int).map_or(0f64, |origin_time| {
                                self.sum_input_to_slot(nodes, node, origin_time, 0, context)
                            })
                        }
                    },
                    PrimitiveEffect::F32Constant => {
                        // Float value is encoded via the slot.
                        let value = edge.from_slot();
                        unpack_f32(value) as f64
                    },
                    PrimitiveEffect::Multiply => {
                        // The only nonzero output is slot=0.
                        if edge.from_slot() != 0 {
                            warn!("Attempt to read from Multiply slot != 0");
                            0f64
                        } else {
                            // Sum all inputs from slot=0 and slot=2 into two separate
                            // variables, then multiply them.
                            let val_a = self.sum_input_to_slot(nodes, node, time, 0, context);
                            let val_b = self.sum_input_to_slot(nodes, node, time, 1, context);
                            val_a * val_b
                        }
                    },
                    PrimitiveEffect::Divide => {
                        // The only nonzero output is slot=0.
                        if edge.from_slot() != 0 {
                            warn!("Attempt to read from MultInv slot != 0");
                            0f64
                        } else {
                            // Sum all inputs
                            let dividend = self.sum_input_to_slot(nodes, node, time, 0, context);
                            let divisor = self.sum_input_to_slot(nodes, node, time, 1, context);
                            dividend / divisor
                        }
                    },
                    PrimitiveEffect::Minimum => {
                        // The only nonzero output is slot=0.
                        if edge.from_slot() != 0 {
                            warn!("Attempt to read from Modulo slot != 0");
                            0f64
                        } else {
                            let input_a = self.sum_input_to_slot(nodes, node, time, 0, context);
                            let input_b = self.sum_input_to_slot(nodes, node, time, 1, context);
                            input_a.min(input_b)
                        }
                    }
                    PrimitiveEffect::Modulo => {
                        // The only nonzero output is slot=0.
                        if edge.from_slot() != 0 {
                            warn!("Attempt to read from Modulo slot != 0");
                            0f64
                        } else {
                            // Sum all dividends
                            let dividend = self.sum_input_to_slot(nodes, node, time, 0, context);
                            // Sum all divisors
                            let divisor = self.sum_input_to_slot(nodes, node, time, 1, context);
                            let rem = dividend % divisor;
                            if rem < 0f64 {
                                // TODO: We may be losing precision here, if rem is small.
                                // We should find a way to do true modulus.
                                rem + divisor
                            } else {
                                rem
                            }
                        }
                    },
                },
                MyNodeData::Buffer(ref buf) => buf.get(time, edge.from_slot()) as f64,
            }
        }
    }
    /// Return the sum of all inputs into a specific slot of the given
    /// node at the given time.
    fn sum_input_to_slot(&self, nodes: &NodeMap, node: &Node, time: u64, slot: u32, context: &Vec<(&NodeMap, NodeHandle)>) -> f64 {
        if node.data.is_none() && context.is_empty() {
            // Read top-level input, or 0 if non-existent input.
            *self.inputs.get(slot as usize).and_then(|v| v.get(time as usize)).unwrap_or(&0f32) as f64
        } else {
            // Sum internal inputs
            let edges_in = node.inbound.iter().filter(|in_edge| {
                in_edge.to_slot() == slot
            });
            edges_in.map(|edge| self.get_value(nodes, edge, time, context)).sum()
        }
    }

    fn make_node(&self, effect: &NodeData) -> MyNodeData {
        match *effect.data() {
            EffectData::Primitive(e) => MyNodeData::Primitive(e),
            EffectData::Buffer(ref buff) => MyNodeData::Buffer(buff.clone()),
            EffectData::RouteGraph(ref graph) => {
                let mut nodes: NodeMap = Default::default();

                for (node, data) in graph.iter_nodes() {
                    nodes.insert(*node, Node::new(Some(self.make_node(data))));
                }
                for edge in graph.iter_edges() {
                    nodes.get_mut(&edge.to_full()).unwrap().inbound.insert(edge.clone());
                }
                MyNodeData::UserNode(nodes)
            }
        }
    }
}

impl GraphWatcher for RefRenderer {
    fn on_add_node(&mut self, handle: &NodeHandle, data: &NodeData) {
        let my_node_data = self.make_node(data);
        self.nodes.insert(*handle, Node::new(Some(my_node_data)));
    }
    fn on_del_node(&mut self, handle: &NodeHandle) {
        self.nodes.remove(handle);
    }
    fn on_add_edge(&mut self, edge: &Edge) {
        self.nodes.get_mut(&edge.to_full()).unwrap().inbound.insert(edge.clone());
    }
    fn on_del_edge(&mut self, edge: &Edge) {
        self.nodes.get_mut(&edge.to_full()).unwrap().inbound.remove(edge);
    }
}

impl Node {
    fn new(data: Option<MyNodeData>) -> Self {
        Node {
            data: data,
            inbound: HashSet::new(),
        }
    }
}

impl Default for NodeMap {
    fn default() -> Self {
        // Create a NodeMap that already has an entry for the toplevel so that it can receive
        // edges.
        let nodes = Some((NodeHandle::toplevel(), Default::default())).into_iter().collect();
        Self { nodes }
    }
}

impl Deref for NodeMap {
    type Target = HashMap<NodeHandle, Node>;
    fn deref(&self) -> &Self::Target {
        &self.nodes
    }
}

impl DerefMut for NodeMap {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.nodes
    }
}
<commit_msg>Better handling of inputs; handle direct passthrough<commit_after>use std::collections::{HashMap, HashSet};
use std::ops::{Deref, DerefMut};

use ndarray::Array2;
use jagged_array::Jagged2;

use render::Renderer;
use resman::AudioBuffer;
use routing::{Edge, GraphWatcher, NodeData, NodeHandle};
use routing::effect::{PrimitiveEffect, EffectData};
use streaming_iterator::StreamingIterator;
use util::unpack_f32;

#[derive(Debug)]
struct NodeMap {
    nodes: HashMap<NodeHandle, Node>,
}

#[derive(Default, Debug)]
pub struct RefRenderer {
    nodes: NodeMap,
    /// inputs[slot][sample] represents the value of the external input at
    /// the given slot and time. On OOB, it is assumed to be 0.
    inputs: Vec<Vec<f32>>,
    /// Next expected sample to be queried.
    /// This is tracked because if we do a seek, the inputs need to be zero'd.
    head: u64,
}

#[derive(Default, Debug)]
struct Node {
    data: Option<MyNodeData>,
    inbound: HashSet<Edge>
}

#[derive(Debug)]
enum MyNodeData {
    /// This node is a non-primitive effect.
    UserNode(NodeMap),
    /// Primitive effect (delay, constant, etc).
    Primitive(PrimitiveEffect),
    /// External audio.
    Buffer(AudioBuffer),
}

impl Renderer for RefRenderer {
    fn fill_buffer(&mut self, buff: &mut Array2<f32>, idx: u64, inputs: Jagged2<f32>) {
        // Store inputs for future use
        {
            if idx != self.head {
                for slot in &mut self.inputs {
                    *slot = Vec::new();
                }
            }
            if self.inputs.len() < buff.len() {
                self.inputs.resize(buff.len(), Default::default());
            }
            let mut stream = inputs.stream();
            let mut self_it = self.inputs.iter_mut();
            while let (Some(row), Some(vec_dest)) = (stream.next(), self_it.next()) {
                // NB: Improper indexing on 32-bit OS, but will OOM first.
                vec_dest.resize(idx as usize, 0f32);
                vec_dest.extend(row);
            }
        }

        // Calculate outputs
        let (n_slots, n_times) = buff.dim().into();
        for slot in 0..n_slots as u32 {
            for time in idx..idx+n_times as u64 {
                buff[[slot as usize, time as usize]] = self.get_sample(time, slot);
            }
        }
        // Keep track of the playhead
        self.head = idx + n_times as u64;
    }
}
impl RefRenderer {
    fn get_sample(&mut self, time: u64, slot: u32) -> f32 {
        let node = &self.nodes[&NodeHandle::toplevel()];
        self.sum_input_to_slot(&self.nodes, &node, time, slot, &Vec::new()) as f32
    }
    /// Get the value on an edge at a particular time
    /// When backtracking from the output, we push each Node onto the context if we enter inside of
    ///   it (i.e. if it's a nested DAG) & pop when exiting.
    fn get_value(&self, nodes: &NodeMap, edge: &Edge, time: u64, context: &Vec<(&NodeMap, NodeHandle)>) -> f64 {
        let from = edge.from_full();
        if *from.node_handle() == None {
            if context.is_empty() {
                // toplevel input (i.e. external input)
                let slot = edge.from_slot() as usize;
                *self.inputs.get(slot).and_then(|v| v.get(time as usize)).unwrap_or(&0f32) as f64
            } else {
                // Reading from one of the inputs to the top of `context`
                // TODO: we can avoid cloning by reversing the pop after recursing.
                let mut new_context = context.clone();
                let (new_nodes, head) = new_context.pop().unwrap();
                // Sum the inputs to the matching slot
                self.sum_input_to_slot(new_nodes, &new_nodes[&head], time, edge.from_slot(), &new_context)
            }
        } else {
            // Reading from another node within the DAG
            let node = &nodes[&from];
            match *node.data.as_ref().expect("Expected node to have associated data") {
                MyNodeData::UserNode(ref new_nodes) => {
                    let mut new_context = context.clone();
                    new_context.push((nodes, from));
                    // Now find the *output* of the sub dag (or 0 if the sub dag has no outputs)
                    new_nodes.get(&NodeHandle::toplevel()).map_or(0f64, |root_node| {
                        self.sum_input_to_slot(new_nodes, root_node, time, edge.from_slot(), &new_context)
                    })
                },
                MyNodeData::Primitive(prim) => match prim {
                    // Output = sum of all inputs to slot 0.
                    PrimitiveEffect::Delay => {
                        // The only nonzero output is slot=0.
                        if edge.from_slot() != 0 {
                            warn!("Attempt to read from Delay slot != 0");
                            0f64
                        } else {
                            let delay_frames = self.sum_input_to_slot(nodes, node, time, 1, context);
                            // Clamp delay value to [0, u64::max]
                            let delay_int = if delay_frames < 0f64 {
                                0u64
                            } else if delay_frames > u64::max_value() as f64 {
                                // TODO: u64::max isn't precisely representable in f64;
                                // will this cause issues?
                                u64::max_value()
                            } else {
                                // Note: this conversion is flooring.
                                delay_frames as u64
                            };
                            // t<0 -> value is 0.
                            time.checked_sub(delay_int).map_or(0f64, |origin_time| {
                                self.sum_input_to_slot(nodes, node, origin_time, 0, context)
                            })
                        }
                    },
                    PrimitiveEffect::F32Constant => {
                        // Float value is encoded via the slot.
                        let value = edge.from_slot();
                        unpack_f32(value) as f64
                    },
                    PrimitiveEffect::Multiply => {
                        // The only nonzero output is slot=0.
                        if edge.from_slot() != 0 {
                            warn!("Attempt to read from Multiply slot != 0");
                            0f64
                        } else {
                            // Sum all inputs from slot=0 and slot=2 into two separate
                            // variables, then multiply them.
                            let val_a = self.sum_input_to_slot(nodes, node, time, 0, context);
                            let val_b = self.sum_input_to_slot(nodes, node, time, 1, context);
                            val_a * val_b
                        }
                    },
                    PrimitiveEffect::Divide => {
                        // The only nonzero output is slot=0.
                        if edge.from_slot() != 0 {
                            warn!("Attempt to read from MultInv slot != 0");
                            0f64
                        } else {
                            // Sum all inputs
                            let dividend = self.sum_input_to_slot(nodes, node, time, 0, context);
                            let divisor = self.sum_input_to_slot(nodes, node, time, 1, context);
                            dividend / divisor
                        }
                    },
                    PrimitiveEffect::Minimum => {
                        // The only nonzero output is slot=0.
                        if edge.from_slot() != 0 {
                            warn!("Attempt to read from Modulo slot != 0");
                            0f64
                        } else {
                            let input_a = self.sum_input_to_slot(nodes, node, time, 0, context);
                            let input_b = self.sum_input_to_slot(nodes, node, time, 1, context);
                            input_a.min(input_b)
                        }
                    }
                    PrimitiveEffect::Modulo => {
                        // The only nonzero output is slot=0.
                        if edge.from_slot() != 0 {
                            warn!("Attempt to read from Modulo slot != 0");
                            0f64
                        } else {
                            // Sum all dividends
                            let dividend = self.sum_input_to_slot(nodes, node, time, 0, context);
                            // Sum all divisors
                            let divisor = self.sum_input_to_slot(nodes, node, time, 1, context);
                            let rem = dividend % divisor;
                            if rem < 0f64 {
                                // TODO: We may be losing precision here, if rem is small.
                                // We should find a way to do true modulus.
                                rem + divisor
                            } else {
                                rem
                            }
                        }
                    },
                },
                MyNodeData::Buffer(ref buf) => buf.get(time, edge.from_slot()) as f64,
            }
        }
    }
    /// Return the sum of all inputs into a specific slot of the given
    /// node at the given time.
    fn sum_input_to_slot(&self, nodes: &NodeMap, node: &Node, time: u64, slot: u32, context: &Vec<(&NodeMap, NodeHandle)>) -> f64 {
        let edges_in = node.inbound.iter().filter(|in_edge| {
            in_edge.to_slot() == slot
        });
        edges_in.map(|edge| self.get_value(nodes, edge, time, context)).sum()
    }

    fn make_node(&self, effect: &NodeData) -> MyNodeData {
        match *effect.data() {
            EffectData::Primitive(e) => MyNodeData::Primitive(e),
            EffectData::Buffer(ref buff) => MyNodeData::Buffer(buff.clone()),
            EffectData::RouteGraph(ref graph) => {
                let mut nodes: NodeMap = Default::default();

                for (node, data) in graph.iter_nodes() {
                    nodes.insert(*node, Node::new(Some(self.make_node(data))));
                }
                for edge in graph.iter_edges() {
                    nodes.get_mut(&edge.to_full()).unwrap().inbound.insert(edge.clone());
                }
                MyNodeData::UserNode(nodes)
            }
        }
    }
}

impl GraphWatcher for RefRenderer {
    fn on_add_node(&mut self, handle: &NodeHandle, data: &NodeData) {
        let my_node_data = self.make_node(data);
        self.nodes.insert(*handle, Node::new(Some(my_node_data)));
    }
    fn on_del_node(&mut self, handle: &NodeHandle) {
        self.nodes.remove(handle);
    }
    fn on_add_edge(&mut self, edge: &Edge) {
        self.nodes.get_mut(&edge.to_full()).unwrap().inbound.insert(edge.clone());
    }
    fn on_del_edge(&mut self, edge: &Edge) {
        self.nodes.get_mut(&edge.to_full()).unwrap().inbound.remove(edge);
    }
}

impl Node {
    fn new(data: Option<MyNodeData>) -> Self {
        Node {
            data: data,
            inbound: HashSet::new(),
        }
    }
}

impl Default for NodeMap {
    fn default() -> Self {
        // Create a NodeMap that already has an entry for the toplevel so that it can receive
        // edges.
        let nodes = Some((NodeHandle::toplevel(), Default::default())).into_iter().collect();
        Self { nodes }
    }
}

impl Deref for NodeMap {
    type Target = HashMap<NodeHandle, Node>;
    fn deref(&self) -> &Self::Target {
        &self.nodes
    }
}

impl DerefMut for NodeMap {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.nodes
    }
}
<|endoftext|>


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

use std::collections::HashMap;
use std::iter::IntoIterator;
use std::slice::IterMut;

use uuid::Uuid;

use super::engine::{HasName, HasUuid};

/// Map UUID and name to T items.
#[derive(Debug)]
pub struct Table<T: HasName + HasUuid> {
    items: Vec<T>,
    name_map: HashMap<String, usize>,
    uuid_map: HashMap<Uuid, usize>,
}

impl<'a, T: HasName + HasUuid> IntoIterator for &'a mut Table<T> {
    type Item = &'a mut T;
    type IntoIter = IterMut<'a, T>;

    fn into_iter(mut self) -> IterMut<'a, T> {
        self.items.iter_mut()
    }
}

/// All operations are O(1).
/// The implementation does not priviledge the name key over the UUID key
/// in any way. They are both treated as constants once the item has been
/// inserted. In order to rename a T item, it must be removed, renamed, and
/// reinserted under the new name.
impl<T: HasName + HasUuid> Table<T> {
    pub fn new() -> Self {
        Table {
            items: Vec::new(),
            name_map: HashMap::new(),
            uuid_map: HashMap::new(),
        }

    }

    /// Empty this table of all its items, returning them in a vector.
    pub fn empty(self) -> Vec<T> {
        self.items
    }

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

    pub fn len(&self) -> usize {
        self.items.len()
    }

    /// Returns true if map has an item corresponding to this name, else false.
    pub fn contains_name(&self, name: &str) -> bool {
        self.name_map.contains_key(name)
    }

    /// Returns true if map has an item corresponding to this uuid, else false.
    #[allow(dead_code)]
    pub fn contains_uuid(&self, uuid: &Uuid) -> bool {
        self.uuid_map.contains_key(uuid)
    }

    /// Get item by name.
    pub fn get_by_name(&self, name: &str) -> Option<&T> {
        self.name_map.get(name).map(|index| &self.items[*index])
    }

    /// Get item by uuid.
    pub fn get_by_uuid(&self, uuid: &Uuid) -> Option<&T> {
        self.uuid_map.get(uuid).map(|index| &self.items[*index])
    }

    /// Get mutable item by name.
    pub fn get_mut_by_name(&mut self, name: &str) -> Option<&mut T> {
        if let Some(index) = self.name_map.get(name) {
            Some(&mut self.items[*index])
        } else {
            None
        }
    }

    /// Get mutable item by uuid.
    pub fn get_mut_by_uuid(&mut self, uuid: &Uuid) -> Option<&mut T> {
        if let Some(index) = self.uuid_map.get(uuid) {
            Some(&mut self.items[*index])
        } else {
            None
        }
    }

    /// Removes the item corresponding to name if there is one.
    pub fn remove_by_name(&mut self, name: &str) -> Option<T> {
        if let Some(index) = self.name_map.remove(name) {
            // Insert mappings for the about-to-be swapped element
            {
                let last_item = &self.items
                                     .last()
                                     .expect("name_map is non-empty <-> items is non-empty");
                self.name_map.insert(last_item.name().into(), index);
                self.uuid_map.insert(last_item.uuid().clone(), index);
            }

            // Remove the item we want to remove and also the uuid mapping
            let item = self.items.swap_remove(index);
            self.uuid_map.remove(item.uuid());

            // Remove the name again, in case there is only one item.
            self.name_map.remove(name);

            Some(item)
        } else {
            None
        }
    }

    /// Removes the item corresponding to the uuid if there is one.
    pub fn remove_by_uuid(&mut self, uuid: &Uuid) -> Option<T> {
        if let Some(index) = self.uuid_map.remove(uuid) {
            // Insert mappings for the about-to-be swapped element
            {
                let last_item = &self.items
                                     .last()
                                     .expect("uuid_map is non-empty <-> items is non-empty");
                self.name_map.insert(last_item.name().into(), index);
                self.uuid_map.insert(last_item.uuid().clone(), index);
            }

            // Remove the item we want to remove and also the uuid mapping
            let item = self.items.swap_remove(index);
            self.name_map.remove(item.name());

            // Remove the uuid again, in case there is only one item.
            self.uuid_map.remove(uuid);

            Some(item)
        } else {
            None
        }
    }

    /// Inserts an item for given uuid and name.
    /// Returns a list of the items displaced, which may be empty if no items
    /// are displaced, have one entry if the uuid and the name map to the same
    /// item, and may have two entries if the uuid and the name map to
    /// different items.
    pub fn insert(&mut self, item: T) -> Vec<T> {
        let name_item = self.remove_by_name(item.name());
        let uuid_item = self.remove_by_uuid(item.uuid());

        let future_last_index = self.items.len();
        self.name_map
            .insert(item.name().into(), future_last_index);
        self.uuid_map
            .insert(item.uuid().clone(), future_last_index);

        self.items.push(item);

        match (name_item, uuid_item) {
            (None, None) => vec![],
            (None, Some(item)) => vec![item],
            (Some(item), None) => vec![item],
            (Some(p1), Some(p2)) => vec![p1, p2],
        }
    }
}

#[cfg(test)]
mod tests {

    use rand;
    use uuid::Uuid;

    use super::super::engine::{HasName, HasUuid};

    use super::Table;

    #[derive(Debug)]
    struct TestThing {
        name: String,
        uuid: Uuid,
        stuff: u32,
    }

    // A global invariant checker for the table.
    // Verifies proper relationship between internal data structures.
    fn table_invariant<T>(table: &Table<T>) -> ()
        where T: HasName + HasUuid
    {
        let ref items = table.items;
        let ref name_map = table.name_map;
        let ref uuid_map = table.uuid_map;
        for i in 0..items.len() {
            let name = items[i].name();
            let uuid = items[i].uuid();
            assert!(name_map.get(name).unwrap() == &i);
            assert!(uuid_map.get(uuid).unwrap() == &i);
        }

        for name in name_map.keys() {
            let index = name_map.get(name).unwrap();
            assert!(items[*index].name() == name);
        }

        for uuid in uuid_map.keys() {
            let index = uuid_map.get(uuid).unwrap();
            assert!(items[*index].uuid() == uuid);
        }

    }

    impl TestThing {
        pub fn new(name: &str, uuid: &Uuid) -> TestThing {
            TestThing {
                name: name.to_owned(),
                uuid: uuid.clone(),
                stuff: rand::random::<u32>(),
            }
        }
    }

    impl HasUuid for TestThing {
        fn uuid(&self) -> &Uuid {
            &self.uuid
        }
    }

    impl HasName for TestThing {
        fn name(&self) -> &str {
            &self.name
        }
    }

    #[test]
    /// Remove a test object by its uuid.
    /// Mutate the removed test object.
    /// Verify that the table is now empty and that removing by name yields
    /// no result.
    fn remove_existing_item() {
        let mut t: Table<TestThing> = Table::new();
        table_invariant(&t);

        let uuid = Uuid::new_v4();
        let name = "name";
        t.insert(TestThing::new(&name, &uuid));
        table_invariant(&t);

        assert!(t.get_by_name(&name).is_some());
        assert!(t.get_by_uuid(&uuid).is_some());
        let thing = t.remove_by_uuid(&uuid);
        table_invariant(&t);
        assert!(thing.is_some());
        let mut thing = thing.unwrap();
        thing.stuff = 0;
        assert!(t.is_empty());
        assert!(t.remove_by_name(&name).is_none());
        table_invariant(&t);

        assert!(t.get_by_name(&name).is_none());
        assert!(t.get_by_uuid(&uuid).is_none());
    }

    #[test]
    /// Insert a thing and then insert another thing with same keys.
    /// The previously inserted thing should be returned.
    /// You can't insert the identical thing, because that would be a move.
    /// This is good, because then you can't have a thing that is both in
    /// the table and not in the table.
    fn insert_same_keys() {
        let mut t: Table<TestThing> = Table::new();
        table_invariant(&t);

        let uuid = Uuid::new_v4();
        let name = "name";
        let thing = TestThing::new(&name, &uuid);
        let thing_key = thing.stuff;
        let displaced = t.insert(thing);
        table_invariant(&t);

        // There was nothing previously, so displaced must be empty.
        assert!(displaced.is_empty());

        // t now contains the inserted thing.
        assert!(t.contains_name(&name));
        assert!(t.contains_uuid(&uuid));
        assert!(t.get_by_uuid(&uuid).unwrap().stuff == thing_key);

        // Add another thing with the same keys.
        let thing2 = TestThing::new(&name, &uuid);
        let thing_key2 = thing2.stuff;
        let displaced = t.insert(thing2);
        table_invariant(&t);

        // It has displaced the old thing.
        assert!(displaced.len() == 1);
        let ref displaced_item = displaced[0];
        assert!(displaced_item.name() == name);
        assert!(displaced_item.uuid() == &uuid);

        // But it contains a thing with the same keys.
        assert!(t.contains_name(&name));
        assert!(t.contains_uuid(&uuid));
        assert!(t.get_by_uuid(&uuid).unwrap().stuff == thing_key2);
        assert!(t.len() == 1);
    }

    #[test]
    /// Insert a thing and then insert another thing with the same name.
    /// The previously inserted thing should be returned.
    fn insert_same_name() {
        let mut t: Table<TestThing> = Table::new();
        table_invariant(&t);

        let uuid = Uuid::new_v4();
        let name = "name";
        let thing = TestThing::new(&name, &uuid);
        let thing_key = thing.stuff;

        // There was nothing in the table before, so displaced is empty.
        let displaced = t.insert(thing);
        table_invariant(&t);
        assert!(displaced.is_empty());

        // t now contains thing.
        assert!(t.contains_name(&name));
        assert!(t.contains_uuid(&uuid));

        // Insert new item with different UUID.
        let uuid2 = Uuid::new_v4();
        let thing2 = TestThing::new(&name, &uuid2);
        let thing_key2 = thing2.stuff;
        let displaced = t.insert(thing2);
        table_invariant(&t);

        // The items displaced consist exactly of the first item.
        assert!(displaced.len() == 1);
        let ref displaced_item = displaced[0];
        assert!(displaced_item.name() == name);
        assert!(displaced_item.uuid() == &uuid);
        assert!(displaced_item.stuff == thing_key);

        // The table contains the new item and has no memory of the old.
        assert!(t.contains_name(&name));
        assert!(t.contains_uuid(&uuid2));
        assert!(!t.contains_uuid(&uuid));
        assert!(t.get_by_uuid(&uuid2).unwrap().stuff == thing_key2);
        assert!(t.get_by_name(&name).unwrap().stuff == thing_key2);
        assert!(t.len() == 1);
    }
}
<commit_msg>Omit unnecessary allow directive<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::collections::HashMap;
use std::iter::IntoIterator;
use std::slice::IterMut;

use uuid::Uuid;

use super::engine::{HasName, HasUuid};

/// Map UUID and name to T items.
#[derive(Debug)]
pub struct Table<T: HasName + HasUuid> {
    items: Vec<T>,
    name_map: HashMap<String, usize>,
    uuid_map: HashMap<Uuid, usize>,
}

impl<'a, T: HasName + HasUuid> IntoIterator for &'a mut Table<T> {
    type Item = &'a mut T;
    type IntoIter = IterMut<'a, T>;

    fn into_iter(mut self) -> IterMut<'a, T> {
        self.items.iter_mut()
    }
}

/// All operations are O(1).
/// The implementation does not priviledge the name key over the UUID key
/// in any way. They are both treated as constants once the item has been
/// inserted. In order to rename a T item, it must be removed, renamed, and
/// reinserted under the new name.
impl<T: HasName + HasUuid> Table<T> {
    pub fn new() -> Self {
        Table {
            items: Vec::new(),
            name_map: HashMap::new(),
            uuid_map: HashMap::new(),
        }

    }

    /// Empty this table of all its items, returning them in a vector.
    pub fn empty(self) -> Vec<T> {
        self.items
    }

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

    pub fn len(&self) -> usize {
        self.items.len()
    }

    /// Returns true if map has an item corresponding to this name, else false.
    pub fn contains_name(&self, name: &str) -> bool {
        self.name_map.contains_key(name)
    }

    /// Returns true if map has an item corresponding to this uuid, else false.
    pub fn contains_uuid(&self, uuid: &Uuid) -> bool {
        self.uuid_map.contains_key(uuid)
    }

    /// Get item by name.
    pub fn get_by_name(&self, name: &str) -> Option<&T> {
        self.name_map.get(name).map(|index| &self.items[*index])
    }

    /// Get item by uuid.
    pub fn get_by_uuid(&self, uuid: &Uuid) -> Option<&T> {
        self.uuid_map.get(uuid).map(|index| &self.items[*index])
    }

    /// Get mutable item by name.
    pub fn get_mut_by_name(&mut self, name: &str) -> Option<&mut T> {
        if let Some(index) = self.name_map.get(name) {
            Some(&mut self.items[*index])
        } else {
            None
        }
    }

    /// Get mutable item by uuid.
    pub fn get_mut_by_uuid(&mut self, uuid: &Uuid) -> Option<&mut T> {
        if let Some(index) = self.uuid_map.get(uuid) {
            Some(&mut self.items[*index])
        } else {
            None
        }
    }

    /// Removes the item corresponding to name if there is one.
    pub fn remove_by_name(&mut self, name: &str) -> Option<T> {
        if let Some(index) = self.name_map.remove(name) {
            // Insert mappings for the about-to-be swapped element
            {
                let last_item = &self.items
                                     .last()
                                     .expect("name_map is non-empty <-> items is non-empty");
                self.name_map.insert(last_item.name().into(), index);
                self.uuid_map.insert(last_item.uuid().clone(), index);
            }

            // Remove the item we want to remove and also the uuid mapping
            let item = self.items.swap_remove(index);
            self.uuid_map.remove(item.uuid());

            // Remove the name again, in case there is only one item.
            self.name_map.remove(name);

            Some(item)
        } else {
            None
        }
    }

    /// Removes the item corresponding to the uuid if there is one.
    pub fn remove_by_uuid(&mut self, uuid: &Uuid) -> Option<T> {
        if let Some(index) = self.uuid_map.remove(uuid) {
            // Insert mappings for the about-to-be swapped element
            {
                let last_item = &self.items
                                     .last()
                                     .expect("uuid_map is non-empty <-> items is non-empty");
                self.name_map.insert(last_item.name().into(), index);
                self.uuid_map.insert(last_item.uuid().clone(), index);
            }

            // Remove the item we want to remove and also the uuid mapping
            let item = self.items.swap_remove(index);
            self.name_map.remove(item.name());

            // Remove the uuid again, in case there is only one item.
            self.uuid_map.remove(uuid);

            Some(item)
        } else {
            None
        }
    }

    /// Inserts an item for given uuid and name.
    /// Returns a list of the items displaced, which may be empty if no items
    /// are displaced, have one entry if the uuid and the name map to the same
    /// item, and may have two entries if the uuid and the name map to
    /// different items.
    pub fn insert(&mut self, item: T) -> Vec<T> {
        let name_item = self.remove_by_name(item.name());
        let uuid_item = self.remove_by_uuid(item.uuid());

        let future_last_index = self.items.len();
        self.name_map
            .insert(item.name().into(), future_last_index);
        self.uuid_map
            .insert(item.uuid().clone(), future_last_index);

        self.items.push(item);

        match (name_item, uuid_item) {
            (None, None) => vec![],
            (None, Some(item)) => vec![item],
            (Some(item), None) => vec![item],
            (Some(p1), Some(p2)) => vec![p1, p2],
        }
    }
}

#[cfg(test)]
mod tests {

    use rand;
    use uuid::Uuid;

    use super::super::engine::{HasName, HasUuid};

    use super::Table;

    #[derive(Debug)]
    struct TestThing {
        name: String,
        uuid: Uuid,
        stuff: u32,
    }

    // A global invariant checker for the table.
    // Verifies proper relationship between internal data structures.
    fn table_invariant<T>(table: &Table<T>) -> ()
        where T: HasName + HasUuid
    {
        let ref items = table.items;
        let ref name_map = table.name_map;
        let ref uuid_map = table.uuid_map;
        for i in 0..items.len() {
            let name = items[i].name();
            let uuid = items[i].uuid();
            assert!(name_map.get(name).unwrap() == &i);
            assert!(uuid_map.get(uuid).unwrap() == &i);
        }

        for name in name_map.keys() {
            let index = name_map.get(name).unwrap();
            assert!(items[*index].name() == name);
        }

        for uuid in uuid_map.keys() {
            let index = uuid_map.get(uuid).unwrap();
            assert!(items[*index].uuid() == uuid);
        }

    }

    impl TestThing {
        pub fn new(name: &str, uuid: &Uuid) -> TestThing {
            TestThing {
                name: name.to_owned(),
                uuid: uuid.clone(),
                stuff: rand::random::<u32>(),
            }
        }
    }

    impl HasUuid for TestThing {
        fn uuid(&self) -> &Uuid {
            &self.uuid
        }
    }

    impl HasName for TestThing {
        fn name(&self) -> &str {
            &self.name
        }
    }

    #[test]
    /// Remove a test object by its uuid.
    /// Mutate the removed test object.
    /// Verify that the table is now empty and that removing by name yields
    /// no result.
    fn remove_existing_item() {
        let mut t: Table<TestThing> = Table::new();
        table_invariant(&t);

        let uuid = Uuid::new_v4();
        let name = "name";
        t.insert(TestThing::new(&name, &uuid));
        table_invariant(&t);

        assert!(t.get_by_name(&name).is_some());
        assert!(t.get_by_uuid(&uuid).is_some());
        let thing = t.remove_by_uuid(&uuid);
        table_invariant(&t);
        assert!(thing.is_some());
        let mut thing = thing.unwrap();
        thing.stuff = 0;
        assert!(t.is_empty());
        assert!(t.remove_by_name(&name).is_none());
        table_invariant(&t);

        assert!(t.get_by_name(&name).is_none());
        assert!(t.get_by_uuid(&uuid).is_none());
    }

    #[test]
    /// Insert a thing and then insert another thing with same keys.
    /// The previously inserted thing should be returned.
    /// You can't insert the identical thing, because that would be a move.
    /// This is good, because then you can't have a thing that is both in
    /// the table and not in the table.
    fn insert_same_keys() {
        let mut t: Table<TestThing> = Table::new();
        table_invariant(&t);

        let uuid = Uuid::new_v4();
        let name = "name";
        let thing = TestThing::new(&name, &uuid);
        let thing_key = thing.stuff;
        let displaced = t.insert(thing);
        table_invariant(&t);

        // There was nothing previously, so displaced must be empty.
        assert!(displaced.is_empty());

        // t now contains the inserted thing.
        assert!(t.contains_name(&name));
        assert!(t.contains_uuid(&uuid));
        assert!(t.get_by_uuid(&uuid).unwrap().stuff == thing_key);

        // Add another thing with the same keys.
        let thing2 = TestThing::new(&name, &uuid);
        let thing_key2 = thing2.stuff;
        let displaced = t.insert(thing2);
        table_invariant(&t);

        // It has displaced the old thing.
        assert!(displaced.len() == 1);
        let ref displaced_item = displaced[0];
        assert!(displaced_item.name() == name);
        assert!(displaced_item.uuid() == &uuid);

        // But it contains a thing with the same keys.
        assert!(t.contains_name(&name));
        assert!(t.contains_uuid(&uuid));
        assert!(t.get_by_uuid(&uuid).unwrap().stuff == thing_key2);
        assert!(t.len() == 1);
    }

    #[test]
    /// Insert a thing and then insert another thing with the same name.
    /// The previously inserted thing should be returned.
    fn insert_same_name() {
        let mut t: Table<TestThing> = Table::new();
        table_invariant(&t);

        let uuid = Uuid::new_v4();
        let name = "name";
        let thing = TestThing::new(&name, &uuid);
        let thing_key = thing.stuff;

        // There was nothing in the table before, so displaced is empty.
        let displaced = t.insert(thing);
        table_invariant(&t);
        assert!(displaced.is_empty());

        // t now contains thing.
        assert!(t.contains_name(&name));
        assert!(t.contains_uuid(&uuid));

        // Insert new item with different UUID.
        let uuid2 = Uuid::new_v4();
        let thing2 = TestThing::new(&name, &uuid2);
        let thing_key2 = thing2.stuff;
        let displaced = t.insert(thing2);
        table_invariant(&t);

        // The items displaced consist exactly of the first item.
        assert!(displaced.len() == 1);
        let ref displaced_item = displaced[0];
        assert!(displaced_item.name() == name);
        assert!(displaced_item.uuid() == &uuid);
        assert!(displaced_item.stuff == thing_key);

        // The table contains the new item and has no memory of the old.
        assert!(t.contains_name(&name));
        assert!(t.contains_uuid(&uuid2));
        assert!(!t.contains_uuid(&uuid));
        assert!(t.get_by_uuid(&uuid2).unwrap().stuff == thing_key2);
        assert!(t.get_by_name(&name).unwrap().stuff == thing_key2);
        assert!(t.len() == 1);
    }
}
<|endoftext|>


<commit_before>use std::io::Write;

use Result;
use layout::Component;

pub struct ThreeDICE;

impl super::Format for ThreeDICE {
    fn print(&self, components: &[Component], writer: &mut Write) -> Result<()> {
        let mut first = true;
        for &Component { ref name, position: (x, y), dimension: (width, height) } in components {
            if !first {
                ok!(writer.write(b"\n"));
            } else {
                first = false;
            }
            ok!(writer.write_all(format!(
"{}:
  position {:.0}, {:.0};
  dimension {:.0}, {:.0};

  power: values 0;
", name, x * 1e6, y * 1e6, width * 1e6, height * 1e6).as_bytes()));
        }
        Ok(())
    }
}
<commit_msg>Fix the 3D-ICE formatter<commit_after>use std::io::Write;

use Result;
use layout::Component;

pub struct ThreeDICE;

impl super::Format for ThreeDICE {
    fn print(&self, components: &[Component], writer: &mut Write) -> Result<()> {
        let mut first = true;
        for &Component { ref name, position: (x, y), dimension: (width, height) } in components {
            if !first {
                ok!(writer.write(b"\n"));
            } else {
                first = false;
            }
            ok!(writer.write_all(format!(
"{}:
  position {:.0}, {:.0};
  dimension {:.0}, {:.0};

  power values 0;
", name, x * 1e6, y * 1e6, width * 1e6, height * 1e6).as_bytes()));
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>use alga::general::Id;
use na;
use query::{PointQuery, PointProjection, RichPointQuery};
use shape::{BaseMesh, BaseMeshElement, TriMesh, Polyline};
use bounding_volume::AABB;
use partitioning::{BVTCostFn, BVTVisitor};
use math::{Point, Isometry};

impl<P, M, I, E> PointQuery<P, M> for BaseMesh<P, I, E>
    where P: Point,
          M: Isometry<P>,
          E: BaseMeshElement<I, P> + PointQuery<P, Id> + RichPointQuery<P, Id> {
    #[inline]
    fn project_point(&self, m: &M, point: &P, solid: bool) -> PointProjection<P> {
        let (projection, _) = self.project_point_with_extra_info(m, point, solid);
        projection
    }

    #[inline]
    fn contains_point(&self, m: &M, point: &P) -> bool {
        let ls_pt = m.inverse_transform_point(point);
        let mut test = PointContainementTest { mesh: self, point: &ls_pt, found: false };

        self.bvt().visit(&mut test);

        test.found
    }
}

impl<P, M, I, E> RichPointQuery<P, M> for BaseMesh<P, I, E>
    where P: Point,
          M: Isometry<P>,
          E: BaseMeshElement<I, P> + RichPointQuery<P, Id>
{
    type ExtraInfo = PointProjectionInfo<E::ExtraInfo>;

    #[inline]
    fn project_point_with_extra_info(&self, m: &M, point: &P, _: bool)
        -> (PointProjection<P>, Self::ExtraInfo)
    {
        let ls_pt = m.inverse_transform_point(point);
        let mut cost_fn = BaseMeshPointProjCostFn { mesh: self, point: &ls_pt };

        let (mut proj, extra_info) = self.bvt().best_first_search(&mut cost_fn).unwrap().1;
        proj.point = m.transform_point(&proj.point);

        (proj, extra_info)
    }
}

/*
 * Costs function.
 */
struct BaseMeshPointProjCostFn<'a, P: 'a + Point, I: 'a, E: 'a> {
    mesh:  &'a BaseMesh<P, I, E>,
    point: &'a P
}

impl<'a, P, I, E> BVTCostFn<P::Real, usize, AABB<P>> for BaseMeshPointProjCostFn<'a, P, I, E>
    where P: Point,
          E: BaseMeshElement<I, P> + RichPointQuery<P, Id> {
    type UserData = (PointProjection<P>, PointProjectionInfo<E::ExtraInfo>);

    #[inline]
    fn compute_bv_cost(&mut self, aabb: &AABB<P>) -> Option<P::Real> {
        Some(aabb.distance_to_point(&Id::new(), self.point, true))
    }

    #[inline]
    fn compute_b_cost(&mut self, b: &usize) -> Option<(P::Real, Self::UserData)> {
        let (proj, extra_info) = self.mesh
            .element_at(*b)
            .project_point_with_extra_info(&Id::new(), self.point, true);

        let extra_info = PointProjectionInfo {
            element_index          : *b,
            barycentric_coordinates: extra_info,
        };

        Some((na::distance(self.point, &proj.point), (proj, extra_info)))
    }
}

/*
 * Visitor.
 */
/// Bounding Volume Tree visitor collecting nodes that may contain a given point.
struct PointContainementTest<'a, P: 'a + Point, I: 'a, E: 'a> {
    mesh:  &'a BaseMesh<P, I, E>,
    point: &'a P,
    found: bool
}

impl<'a, P, I, E> BVTVisitor<usize, AABB<P>> for PointContainementTest<'a, P, I, E>
    where P: Point,
          E: BaseMeshElement<I, P> + PointQuery<P, Id> {
    #[inline]
    fn visit_internal(&mut self, bv: &AABB<P>) -> bool {
        !self.found && bv.contains_point(&Id::new(), self.point)
    }

    #[inline]
    fn visit_leaf(&mut self, b: &usize, bv: &AABB<P>) {
        if !self.found &&
           bv.contains_point(&Id::new(), self.point) &&
           self.mesh.element_at(*b).contains_point(&Id::new(), self.point) {
            self.found = true;
        }
    }
}

/// Additional point pojection info for base meshes
pub struct PointProjectionInfo<C> {
    /// The index of the base mesh element the point was projected on
    ///
    /// The terminology is a bit confusing here, as this is not the index of a
    /// base mesh vertex, but rather of a base mesh element. Meaning, it is
    /// intended to be passed to `BaseMesh::element_at`.
    pub element_index: usize,

    /// The barycentry coordinates of the projected point
    ///
    /// The type of this field depends on the type of the base mesh element.
    pub barycentric_coordinates: C,
}

/*
 * fwd impls to exact meshes.
 */
impl<P: Point, M: Isometry<P>> PointQuery<P, M> for TriMesh<P> {
    #[inline]
    fn project_point(&self, m: &M, point: &P, solid: bool) -> PointProjection<P> {
        self.base_mesh().project_point(m, point, solid)
    }

    #[inline]
    fn distance_to_point(&self, m: &M, point: &P, solid: bool) -> P::Real {
        self.base_mesh().distance_to_point(m, point, solid)
    }

    #[inline]
    fn contains_point(&self, m: &M, point: &P) -> bool {
        self.base_mesh().contains_point(m, point)
    }
}

impl<P: Point, M: Isometry<P>> PointQuery<P, M> for Polyline<P> {
    #[inline]
    fn project_point(&self, m: &M, point: &P, solid: bool) -> PointProjection<P> {
        self.base_mesh().project_point(m, point, solid)
    }

    #[inline]
    fn distance_to_point(&self, m: &M, point: &P, solid: bool) -> P::Real {
        self.base_mesh().distance_to_point(m, point, solid)
    }

    #[inline]
    fn contains_point(&self, m: &M, point: &P) -> bool {
        self.base_mesh().contains_point(m, point)
    }
}
<commit_msg>Implement `RichPointQuery` for `Polyline`<commit_after>use alga::general::Id;
use na;
use query::{PointQuery, PointProjection, RichPointQuery};
use shape::{BaseMesh, BaseMeshElement, Segment, TriMesh, Polyline};
use bounding_volume::AABB;
use partitioning::{BVTCostFn, BVTVisitor};
use math::{Point, Isometry};

impl<P, M, I, E> PointQuery<P, M> for BaseMesh<P, I, E>
    where P: Point,
          M: Isometry<P>,
          E: BaseMeshElement<I, P> + PointQuery<P, Id> + RichPointQuery<P, Id> {
    #[inline]
    fn project_point(&self, m: &M, point: &P, solid: bool) -> PointProjection<P> {
        let (projection, _) = self.project_point_with_extra_info(m, point, solid);
        projection
    }

    #[inline]
    fn contains_point(&self, m: &M, point: &P) -> bool {
        let ls_pt = m.inverse_transform_point(point);
        let mut test = PointContainementTest { mesh: self, point: &ls_pt, found: false };

        self.bvt().visit(&mut test);

        test.found
    }
}

impl<P, M, I, E> RichPointQuery<P, M> for BaseMesh<P, I, E>
    where P: Point,
          M: Isometry<P>,
          E: BaseMeshElement<I, P> + RichPointQuery<P, Id>
{
    type ExtraInfo = PointProjectionInfo<E::ExtraInfo>;

    #[inline]
    fn project_point_with_extra_info(&self, m: &M, point: &P, _: bool)
        -> (PointProjection<P>, Self::ExtraInfo)
    {
        let ls_pt = m.inverse_transform_point(point);
        let mut cost_fn = BaseMeshPointProjCostFn { mesh: self, point: &ls_pt };

        let (mut proj, extra_info) = self.bvt().best_first_search(&mut cost_fn).unwrap().1;
        proj.point = m.transform_point(&proj.point);

        (proj, extra_info)
    }
}

/*
 * Costs function.
 */
struct BaseMeshPointProjCostFn<'a, P: 'a + Point, I: 'a, E: 'a> {
    mesh:  &'a BaseMesh<P, I, E>,
    point: &'a P
}

impl<'a, P, I, E> BVTCostFn<P::Real, usize, AABB<P>> for BaseMeshPointProjCostFn<'a, P, I, E>
    where P: Point,
          E: BaseMeshElement<I, P> + RichPointQuery<P, Id> {
    type UserData = (PointProjection<P>, PointProjectionInfo<E::ExtraInfo>);

    #[inline]
    fn compute_bv_cost(&mut self, aabb: &AABB<P>) -> Option<P::Real> {
        Some(aabb.distance_to_point(&Id::new(), self.point, true))
    }

    #[inline]
    fn compute_b_cost(&mut self, b: &usize) -> Option<(P::Real, Self::UserData)> {
        let (proj, extra_info) = self.mesh
            .element_at(*b)
            .project_point_with_extra_info(&Id::new(), self.point, true);

        let extra_info = PointProjectionInfo {
            element_index          : *b,
            barycentric_coordinates: extra_info,
        };

        Some((na::distance(self.point, &proj.point), (proj, extra_info)))
    }
}

/*
 * Visitor.
 */
/// Bounding Volume Tree visitor collecting nodes that may contain a given point.
struct PointContainementTest<'a, P: 'a + Point, I: 'a, E: 'a> {
    mesh:  &'a BaseMesh<P, I, E>,
    point: &'a P,
    found: bool
}

impl<'a, P, I, E> BVTVisitor<usize, AABB<P>> for PointContainementTest<'a, P, I, E>
    where P: Point,
          E: BaseMeshElement<I, P> + PointQuery<P, Id> {
    #[inline]
    fn visit_internal(&mut self, bv: &AABB<P>) -> bool {
        !self.found && bv.contains_point(&Id::new(), self.point)
    }

    #[inline]
    fn visit_leaf(&mut self, b: &usize, bv: &AABB<P>) {
        if !self.found &&
           bv.contains_point(&Id::new(), self.point) &&
           self.mesh.element_at(*b).contains_point(&Id::new(), self.point) {
            self.found = true;
        }
    }
}

/// Additional point pojection info for base meshes
pub struct PointProjectionInfo<C> {
    /// The index of the base mesh element the point was projected on
    ///
    /// The terminology is a bit confusing here, as this is not the index of a
    /// base mesh vertex, but rather of a base mesh element. Meaning, it is
    /// intended to be passed to `BaseMesh::element_at`.
    pub element_index: usize,

    /// The barycentry coordinates of the projected point
    ///
    /// The type of this field depends on the type of the base mesh element.
    pub barycentric_coordinates: C,
}

/*
 * fwd impls to exact meshes.
 */
impl<P: Point, M: Isometry<P>> PointQuery<P, M> for TriMesh<P> {
    #[inline]
    fn project_point(&self, m: &M, point: &P, solid: bool) -> PointProjection<P> {
        self.base_mesh().project_point(m, point, solid)
    }

    #[inline]
    fn distance_to_point(&self, m: &M, point: &P, solid: bool) -> P::Real {
        self.base_mesh().distance_to_point(m, point, solid)
    }

    #[inline]
    fn contains_point(&self, m: &M, point: &P) -> bool {
        self.base_mesh().contains_point(m, point)
    }
}

impl<P: Point, M: Isometry<P>> PointQuery<P, M> for Polyline<P> {
    #[inline]
    fn project_point(&self, m: &M, point: &P, solid: bool) -> PointProjection<P> {
        let (projection, _) = self.project_point_with_extra_info(m, point, solid);
        projection
    }

    #[inline]
    fn distance_to_point(&self, m: &M, point: &P, solid: bool) -> P::Real {
        self.base_mesh().distance_to_point(m, point, solid)
    }

    #[inline]
    fn contains_point(&self, m: &M, point: &P) -> bool {
        self.base_mesh().contains_point(m, point)
    }
}

impl<P: Point, M: Isometry<P>> RichPointQuery<P, M> for Polyline<P> {
    type ExtraInfo = PointProjectionInfo<<Segment<P> as RichPointQuery<P, M>>::ExtraInfo>;

    #[inline]
    fn project_point_with_extra_info(&self, m: &M, point: &P, solid: bool)
        -> (PointProjection<P>, Self::ExtraInfo)
    {
        self.base_mesh().project_point_with_extra_info(m, point, solid)
    }
}
<|endoftext|>


<commit_before>/* Fundamental layout structures and algorithms. */

use arc = std::arc;
use arc::ARC;
use au = gfx::geometry;
use au::au;
use core::dvec::DVec;
use core::to_str::ToStr;
use core::rand;
use css::styles::SpecifiedStyle;
use css::values::{BoxSizing, Length, Px, CSSDisplay, Specified, BgColor, BgColorTransparent};
use dl = gfx::display_list;
use dom::element::{ElementKind, HTMLDivElement, HTMLImageElement};
use dom::node::{Element, Node, NodeData, NodeKind, NodeTree};
use geom::rect::Rect;
use geom::size::Size2D;
use geom::point::Point2D;
use image::{Image, ImageHolder};
use layout::context::LayoutContext;
use layout::debug::BoxedDebugMethods;
use layout::flow::FlowContext;
use layout::text::TextBoxData;
use servo_text::text_run::TextRun;
use std::net::url::Url;
use task::spawn;
use util::color::Color;
use util::tree;
use vec::{push, push_all};

/**
Render boxes (`struct RenderBox`) are the leafs of the layout
tree. They cannot position themselves. In general, render boxes do not
have a simple correspondence with CSS boxes as in the specification:

 * Several render boxes may correspond to the same CSS box or DOM
   node. For example, a CSS text box broken across two lines is
   represented by two render boxes.

 * Some CSS boxes are not created at all, such as some anonymous block
   boxes induced by inline boxes with block-level sibling boxes. In
   that case, Servo uses an InlineFlow with BlockFlow siblings; the
   InlineFlow is block-level, but not a block container. It is
   positioned as if it were a block box, but its children are
   positioned according to inline flow.

Fundamental box types include:

 * GenericBox: an empty box that contributes only borders, margins,
padding, backgrounds. It is analogous to a CSS nonreplaced content box.

 * ImageBox: a box that represents a (replaced content) image and its
   accompanying borders, shadows, etc.

 * TextBox: a box representing a single run of text with a distinct
   style. A TextBox may be split into two or more render boxes across
   line breaks. Several TextBoxes may correspond to a single DOM text
   node. Split text boxes are implemented by referring to subsets of a
   master TextRun object.

*/

/* A box's kind influences how its styles are interpreted during
   layout.  For example, replaced content such as images are resized
   differently than tables, text, or other content.

   It also holds data specific to different box types, such as text.
*/
struct RenderBoxData {
    /* originating DOM node */
    node : Node,
    /* reference to containing flow context, which this box
       participates in */
    ctx  : @FlowContext,
    /* position of this box relative to owning flow */
    mut position : Rect<au>,
    font_size : Length,
    /* TODO (Issue #87): debug only */
    mut id: int
}

enum RenderBoxType {
    RenderBox_Generic,
    RenderBox_Image,
    RenderBox_Text,
}

pub enum RenderBox {
    GenericBox(RenderBoxData),
    ImageBox(RenderBoxData, ImageHolder),
    TextBox(RenderBoxData, TextBoxData),
    UnscannedTextBox(RenderBoxData, ~str)
}

enum InlineSpacerSide {
    LogicalBefore,
    LogicalAfter,
}

trait RenderBoxMethods {
    pure fn d(&self) -> &self/RenderBoxData;

    pure fn is_replaced() -> bool;
    pure fn can_split() -> bool;
    pure fn is_whitespace_only() -> bool;
    pure fn can_merge_with_box(@self, other: @RenderBox) -> bool;
    pure fn requires_inline_spacers() -> bool;
    pure fn content_box() -> Rect<au>;
    pure fn border_box() -> Rect<au>;

    fn get_min_width(&LayoutContext) -> au;
    fn get_pref_width(&LayoutContext) -> au;
    fn get_used_width() -> (au, au);
    fn get_used_height() -> (au, au);
    fn create_inline_spacer_for_side(&LayoutContext, InlineSpacerSide) -> Option<@RenderBox>;
    fn build_display_list(&dl::DisplayListBuilder, dirty: &Rect<au>,
                          offset: &Point2D<au>, &dl::DisplayList);
}

fn RenderBoxData(node: Node, ctx: @FlowContext, id: int) -> RenderBoxData {
    RenderBoxData {
        node : node,
        mut ctx  : ctx,
        mut position : au::zero_rect(),
        font_size: Px(0.0),
        id : id
    }
}

impl RenderBox : RenderBoxMethods {
    pure fn d(&self) -> &self/RenderBoxData {
        match *self {
            GenericBox(ref d)  => d,
            ImageBox(ref d, _) => d,
            TextBox(ref d, _)  => d,
            UnscannedTextBox(ref d, _) => d,
        }
    }

    pure fn is_replaced() -> bool {
        match self {
           ImageBox(*) => true, // TODO: form elements, etc
            _ => false
        }
    }

    pure fn can_split() -> bool {
        match self {
            TextBox(*) => true,
            _ => false
        }
    }

    pure fn is_whitespace_only() -> bool {
        match self {
            UnscannedTextBox(_, raw_text) => raw_text.is_whitespace(),
            _ => false
        }
    }

    pure fn can_merge_with_box(@self, other: @RenderBox) -> bool {
        assert !core::box::ptr_eq(self, other);

        match (self, other) {
            (@UnscannedTextBox(*), @UnscannedTextBox(*)) => true,
            (@TextBox(_,d1), @TextBox(_,d2)) => { core::box::ptr_eq(d1.run, d2.run) }
            (_, _) => false
        }
    }

    /** In general, these functions are transitively impure because they
     * may cause glyphs to be allocated. For now, it's impure because of
     * holder.get_image()
    */
    fn get_min_width(ctx: &LayoutContext) -> au {
        match self {
            // TODO: this should account for min/pref widths of the
            // box element in isolation. That includes
            // border/margin/padding but not child widths. The block
            // FlowContext will combine the width of this element and
            // that of its children to arrive at the context width.
            GenericBox(*) => au(0),
            // TODO: consult CSS 'width', margin, border.
            // TODO: If image isn't available, consult 'width'.
            ImageBox(_,i) => au::from_px(i.get_size().get_default(Size2D(0,0)).width),
            TextBox(_,d) => d.run.min_width_for_range(ctx, d.offset, d.length),
            UnscannedTextBox(*) => fail ~"Shouldn't see unscanned boxes here."
        }
    }

    fn get_pref_width(_ctx: &LayoutContext) -> au {
        match self {
            // TODO: this should account for min/pref widths of the
            // box element in isolation. That includes
            // border/margin/padding but not child widths. The block
            // FlowContext will combine the width of this element and
            // that of its children to arrive at the context width.
            GenericBox(*) => au(0),
            ImageBox(_,i) => au::from_px(i.get_size().get_default(Size2D(0,0)).width),

            // a text box cannot span lines, so assume that this is an unsplit text box.

            // TODO: If text boxes have been split to wrap lines, then
            // they could report a smaller pref width during incremental reflow.
            // maybe text boxes should report nothing, and the parent flow could
            // factor in min/pref widths of any text runs that it owns.
            TextBox(_,d) => {
                let mut max_line_width: au = au(0);
                do d.run.iter_natural_lines_for_range(d.offset, d.length) |line_offset, line_len| {
                    let mut line_width: au = au(0);
                    do d.run.glyphs.iter_glyphs_for_range(line_offset, line_len) |_char_i, glyph| {
                        line_width += glyph.advance()
                    };

                    if max_line_width < line_width {
                        max_line_width = line_width;
                    };
                    true
                }

                max_line_width
            },
            UnscannedTextBox(*) => fail ~"Shouldn't see unscanned boxes here."
        }
    }

    /* Returns the amount of left, right "fringe" used by this
    box. This should be based on margin, border, padding, width. */
    fn get_used_width() -> (au, au) {
        // TODO: this should actually do some computation!
        // See CSS 2.1, Section 10.3, 10.4.

        (au(0), au(0))
    }

    /* Returns the amount of left, right "fringe" used by this
    box. This should be based on margin, border, padding, width. */
    fn get_used_height() -> (au, au) {
        // TODO: this should actually do some computation!
        // See CSS 2.1, Section 10.5, 10.6.

        (au(0), au(0))
    }

    /* Whether "spacer" boxes are needed to stand in for this DOM node */
    pure fn requires_inline_spacers() -> bool {
        return false;
    }

    /* The box formed by the content edge, as defined in CSS 2.1 Section 8.1.
       Coordinates are relative to the owning flow. */
    pure fn content_box() -> Rect<au> {
        match self {
            ImageBox(_,i) => {
                let size = i.size();
                Rect {
                    origin: copy self.d().position.origin,
                    size:   Size2D(au::from_px(size.width),
                                   au::from_px(size.height))
                }
            },
            GenericBox(*) => {
                copy self.d().position
                /* FIXME: The following hits an ICE for whatever reason

                let origin = self.d().position.origin;
                let size   = self.d().position.size;
                let (offset_left, offset_right) = self.get_used_width();
                let (offset_top, offset_bottom) = self.get_used_height();

                Rect {
                    origin: Point2D(origin.x + offset_left, origin.y + offset_top),
                    size:   Size2D(size.width - (offset_left + offset_right),
                                   size.height - (offset_top + offset_bottom))
                }*/
            },
            TextBox(*) => {
                copy self.d().position
            },
            UnscannedTextBox(*) => fail ~"Shouldn't see unscanned boxes here."
        }
    }

    /* The box formed by the border edge, as defined in CSS 2.1 Section 8.1.
       Coordinates are relative to the owning flow. */
    pure fn border_box() -> Rect<au> {
        // TODO: actually compute content_box + padding + border
        self.content_box()
    }

    // TODO: implement this, generating spacer
    fn create_inline_spacer_for_side(_ctx: &LayoutContext, _side: InlineSpacerSide) -> Option<@RenderBox> {
        None
    }

    // TODO: to implement stacking contexts correctly, we need to
    // create a set of display lists, one per each layer of a stacking
    // context. (CSS 2.1, Section 9.9.1). Each box is passed the list
    // set representing the box's stacking context. When asked to
    // construct its constituent display items, each box puts its
    // DisplayItems into the correct stack layer (according to CSS 2.1
    // Appendix E).  and then builder flattens the list at the end.

    /* Methods for building a display list. This is a good candidate
       for a function pointer as the number of boxes explodes.

    # Arguments

    * `builder` - the display list builder which manages the coordinate system and options.
    * `dirty` - Dirty rectangle, in the coordinate system of the owning flow (self.ctx)
    * `origin` - Total offset from display list root flow to this box's owning flow
    * `list` - List to which items should be appended
    */
    fn build_display_list(_builder: &dl::DisplayListBuilder, dirty: &Rect<au>,
                          offset: &Point2D<au>, list: &dl::DisplayList) {
        if !self.d().position.intersects(dirty) {
            return;
        }

        let bounds : Rect<au> = Rect(self.d().position.origin.add(offset),
                                     copy self.d().position.size);

        match self {
            UnscannedTextBox(*) => fail ~"Shouldn't see unscanned boxes here.",
            TextBox(_,d) => {
                list.push(~dl::Text(bounds, ~(copy *d.run), d.offset, d.length))
            },
            // TODO: items for background, border, outline
            GenericBox(*) => { },
            ImageBox(_,i) => {
                match i.get_image() {
                    Some(image) => list.push(~dl::Image(bounds, arc::clone(&image))),
                    /* No image data at all? Okay, add some fallback content instead. */
                    None => {
                        // TODO: shouldn't need to unbox CSSValue by now
                        let boxed_color = self.d().node.style().background_color;
                        let color = match boxed_color {
                            Specified(BgColor(c)) => c,
                            Specified(BgColorTransparent) | _ => util::color::rgba(0,0,0,0.0)
                        };
                        list.push(~dl::SolidColor(bounds, color.red, color.green, color.blue));
                    }
                }
            }
        }
    }
}

impl RenderBox : BoxedDebugMethods {
    fn dump(@self) {
        self.dump_indent(0u);
    }

    /* Dumps the node tree, for debugging, with indentation. */
    fn dump_indent(@self, indent: uint) {
        let mut s = ~"";
        for uint::range(0u, indent) |_i| {
            s += ~"    ";
        }

        s += self.debug_str();
        debug!("%s", s);
    }

    fn debug_str(@self) -> ~str {
        let repr = match self {
            @GenericBox(*) => ~"GenericBox",
            @ImageBox(*) => ~"ImageBox",
            @TextBox(_,d) => fmt!("TextBox(text=%s)", str::substr(d.run.text, d.offset, d.length)),
            @UnscannedTextBox(_,s) => fmt!("UnscannedTextBox(%s)", s)
        };

        fmt!("box b%?: %?", self.d().id, repr)
    }
}
<commit_msg>Make GenericBox display background colors again<commit_after>/* Fundamental layout structures and algorithms. */

use arc = std::arc;
use arc::ARC;
use au = gfx::geometry;
use au::au;
use core::dvec::DVec;
use core::to_str::ToStr;
use core::rand;
use css::styles::SpecifiedStyle;
use css::values::{BoxSizing, Length, Px, CSSDisplay, Specified, BgColor, BgColorTransparent};
use dl = gfx::display_list;
use dom::element::{ElementKind, HTMLDivElement, HTMLImageElement};
use dom::node::{Element, Node, NodeData, NodeKind, NodeTree};
use geom::rect::Rect;
use geom::size::Size2D;
use geom::point::Point2D;
use image::{Image, ImageHolder};
use layout::context::LayoutContext;
use layout::debug::BoxedDebugMethods;
use layout::flow::FlowContext;
use layout::text::TextBoxData;
use servo_text::text_run::TextRun;
use std::net::url::Url;
use task::spawn;
use util::color::Color;
use util::tree;
use vec::{push, push_all};

/**
Render boxes (`struct RenderBox`) are the leafs of the layout
tree. They cannot position themselves. In general, render boxes do not
have a simple correspondence with CSS boxes as in the specification:

 * Several render boxes may correspond to the same CSS box or DOM
   node. For example, a CSS text box broken across two lines is
   represented by two render boxes.

 * Some CSS boxes are not created at all, such as some anonymous block
   boxes induced by inline boxes with block-level sibling boxes. In
   that case, Servo uses an InlineFlow with BlockFlow siblings; the
   InlineFlow is block-level, but not a block container. It is
   positioned as if it were a block box, but its children are
   positioned according to inline flow.

Fundamental box types include:

 * GenericBox: an empty box that contributes only borders, margins,
padding, backgrounds. It is analogous to a CSS nonreplaced content box.

 * ImageBox: a box that represents a (replaced content) image and its
   accompanying borders, shadows, etc.

 * TextBox: a box representing a single run of text with a distinct
   style. A TextBox may be split into two or more render boxes across
   line breaks. Several TextBoxes may correspond to a single DOM text
   node. Split text boxes are implemented by referring to subsets of a
   master TextRun object.

*/

/* A box's kind influences how its styles are interpreted during
   layout.  For example, replaced content such as images are resized
   differently than tables, text, or other content.

   It also holds data specific to different box types, such as text.
*/
struct RenderBoxData {
    /* originating DOM node */
    node : Node,
    /* reference to containing flow context, which this box
       participates in */
    ctx  : @FlowContext,
    /* position of this box relative to owning flow */
    mut position : Rect<au>,
    font_size : Length,
    /* TODO (Issue #87): debug only */
    mut id: int
}

enum RenderBoxType {
    RenderBox_Generic,
    RenderBox_Image,
    RenderBox_Text,
}

pub enum RenderBox {
    GenericBox(RenderBoxData),
    ImageBox(RenderBoxData, ImageHolder),
    TextBox(RenderBoxData, TextBoxData),
    UnscannedTextBox(RenderBoxData, ~str)
}

enum InlineSpacerSide {
    LogicalBefore,
    LogicalAfter,
}

trait RenderBoxMethods {
    pure fn d(&self) -> &self/RenderBoxData;

    pure fn is_replaced() -> bool;
    pure fn can_split() -> bool;
    pure fn is_whitespace_only() -> bool;
    pure fn can_merge_with_box(@self, other: @RenderBox) -> bool;
    pure fn requires_inline_spacers() -> bool;
    pure fn content_box() -> Rect<au>;
    pure fn border_box() -> Rect<au>;

    fn get_min_width(&LayoutContext) -> au;
    fn get_pref_width(&LayoutContext) -> au;
    fn get_used_width() -> (au, au);
    fn get_used_height() -> (au, au);
    fn create_inline_spacer_for_side(&LayoutContext, InlineSpacerSide) -> Option<@RenderBox>;
    fn build_display_list(&dl::DisplayListBuilder, dirty: &Rect<au>,
                          offset: &Point2D<au>, &dl::DisplayList);
}

fn RenderBoxData(node: Node, ctx: @FlowContext, id: int) -> RenderBoxData {
    RenderBoxData {
        node : node,
        mut ctx  : ctx,
        mut position : au::zero_rect(),
        font_size: Px(0.0),
        id : id
    }
}

impl RenderBox : RenderBoxMethods {
    pure fn d(&self) -> &self/RenderBoxData {
        match *self {
            GenericBox(ref d)  => d,
            ImageBox(ref d, _) => d,
            TextBox(ref d, _)  => d,
            UnscannedTextBox(ref d, _) => d,
        }
    }

    pure fn is_replaced() -> bool {
        match self {
           ImageBox(*) => true, // TODO: form elements, etc
            _ => false
        }
    }

    pure fn can_split() -> bool {
        match self {
            TextBox(*) => true,
            _ => false
        }
    }

    pure fn is_whitespace_only() -> bool {
        match self {
            UnscannedTextBox(_, raw_text) => raw_text.is_whitespace(),
            _ => false
        }
    }

    pure fn can_merge_with_box(@self, other: @RenderBox) -> bool {
        assert !core::box::ptr_eq(self, other);

        match (self, other) {
            (@UnscannedTextBox(*), @UnscannedTextBox(*)) => true,
            (@TextBox(_,d1), @TextBox(_,d2)) => { core::box::ptr_eq(d1.run, d2.run) }
            (_, _) => false
        }
    }

    /** In general, these functions are transitively impure because they
     * may cause glyphs to be allocated. For now, it's impure because of
     * holder.get_image()
    */
    fn get_min_width(ctx: &LayoutContext) -> au {
        match self {
            // TODO: this should account for min/pref widths of the
            // box element in isolation. That includes
            // border/margin/padding but not child widths. The block
            // FlowContext will combine the width of this element and
            // that of its children to arrive at the context width.
            GenericBox(*) => au(0),
            // TODO: consult CSS 'width', margin, border.
            // TODO: If image isn't available, consult 'width'.
            ImageBox(_,i) => au::from_px(i.get_size().get_default(Size2D(0,0)).width),
            TextBox(_,d) => d.run.min_width_for_range(ctx, d.offset, d.length),
            UnscannedTextBox(*) => fail ~"Shouldn't see unscanned boxes here."
        }
    }

    fn get_pref_width(_ctx: &LayoutContext) -> au {
        match self {
            // TODO: this should account for min/pref widths of the
            // box element in isolation. That includes
            // border/margin/padding but not child widths. The block
            // FlowContext will combine the width of this element and
            // that of its children to arrive at the context width.
            GenericBox(*) => au(0),
            ImageBox(_,i) => au::from_px(i.get_size().get_default(Size2D(0,0)).width),

            // a text box cannot span lines, so assume that this is an unsplit text box.

            // TODO: If text boxes have been split to wrap lines, then
            // they could report a smaller pref width during incremental reflow.
            // maybe text boxes should report nothing, and the parent flow could
            // factor in min/pref widths of any text runs that it owns.
            TextBox(_,d) => {
                let mut max_line_width: au = au(0);
                do d.run.iter_natural_lines_for_range(d.offset, d.length) |line_offset, line_len| {
                    let mut line_width: au = au(0);
                    do d.run.glyphs.iter_glyphs_for_range(line_offset, line_len) |_char_i, glyph| {
                        line_width += glyph.advance()
                    };

                    if max_line_width < line_width {
                        max_line_width = line_width;
                    };
                    true
                }

                max_line_width
            },
            UnscannedTextBox(*) => fail ~"Shouldn't see unscanned boxes here."
        }
    }

    /* Returns the amount of left, right "fringe" used by this
    box. This should be based on margin, border, padding, width. */
    fn get_used_width() -> (au, au) {
        // TODO: this should actually do some computation!
        // See CSS 2.1, Section 10.3, 10.4.

        (au(0), au(0))
    }

    /* Returns the amount of left, right "fringe" used by this
    box. This should be based on margin, border, padding, width. */
    fn get_used_height() -> (au, au) {
        // TODO: this should actually do some computation!
        // See CSS 2.1, Section 10.5, 10.6.

        (au(0), au(0))
    }

    /* Whether "spacer" boxes are needed to stand in for this DOM node */
    pure fn requires_inline_spacers() -> bool {
        return false;
    }

    /* The box formed by the content edge, as defined in CSS 2.1 Section 8.1.
       Coordinates are relative to the owning flow. */
    pure fn content_box() -> Rect<au> {
        match self {
            ImageBox(_,i) => {
                let size = i.size();
                Rect {
                    origin: copy self.d().position.origin,
                    size:   Size2D(au::from_px(size.width),
                                   au::from_px(size.height))
                }
            },
            GenericBox(*) => {
                copy self.d().position
                /* FIXME: The following hits an ICE for whatever reason

                let origin = self.d().position.origin;
                let size   = self.d().position.size;
                let (offset_left, offset_right) = self.get_used_width();
                let (offset_top, offset_bottom) = self.get_used_height();

                Rect {
                    origin: Point2D(origin.x + offset_left, origin.y + offset_top),
                    size:   Size2D(size.width - (offset_left + offset_right),
                                   size.height - (offset_top + offset_bottom))
                }*/
            },
            TextBox(*) => {
                copy self.d().position
            },
            UnscannedTextBox(*) => fail ~"Shouldn't see unscanned boxes here."
        }
    }

    /* The box formed by the border edge, as defined in CSS 2.1 Section 8.1.
       Coordinates are relative to the owning flow. */
    pure fn border_box() -> Rect<au> {
        // TODO: actually compute content_box + padding + border
        self.content_box()
    }

    // TODO: implement this, generating spacer
    fn create_inline_spacer_for_side(_ctx: &LayoutContext, _side: InlineSpacerSide) -> Option<@RenderBox> {
        None
    }

    // TODO: to implement stacking contexts correctly, we need to
    // create a set of display lists, one per each layer of a stacking
    // context. (CSS 2.1, Section 9.9.1). Each box is passed the list
    // set representing the box's stacking context. When asked to
    // construct its constituent display items, each box puts its
    // DisplayItems into the correct stack layer (according to CSS 2.1
    // Appendix E).  and then builder flattens the list at the end.

    /* Methods for building a display list. This is a good candidate
       for a function pointer as the number of boxes explodes.

    # Arguments

    * `builder` - the display list builder which manages the coordinate system and options.
    * `dirty` - Dirty rectangle, in the coordinate system of the owning flow (self.ctx)
    * `origin` - Total offset from display list root flow to this box's owning flow
    * `list` - List to which items should be appended
    */
    fn build_display_list(_builder: &dl::DisplayListBuilder, dirty: &Rect<au>,
                          offset: &Point2D<au>, list: &dl::DisplayList) {
        if !self.d().position.intersects(dirty) {
            return;
        }

        let bounds : Rect<au> = Rect(self.d().position.origin.add(offset),
                                     copy self.d().position.size);

        // TODO: shouldn't need to unbox CSSValue by now
        let boxed_bgcolor = self.d().node.style().background_color;
        let bgcolor = match boxed_bgcolor {
            Specified(BgColor(c)) => c,
            Specified(BgColorTransparent) | _ => util::color::rgba(0,0,0,0.0)
        };

        match self {
            UnscannedTextBox(*) => fail ~"Shouldn't see unscanned boxes here.",
            TextBox(_,d) => {
                list.push(~dl::Text(bounds, ~(copy *d.run), d.offset, d.length))
            },
            // TODO: items for background, border, outline
            GenericBox(_) => {
                use std::cmp::FuzzyEq;
                if !bgcolor.alpha.fuzzy_eq(&0.0) {
                    list.push(~dl::SolidColor(bounds, bgcolor.red, bgcolor.green, bgcolor.blue));
                }
            },
            ImageBox(_,i) => {
                match i.get_image() {
                    Some(image) => list.push(~dl::Image(bounds, arc::clone(&image))),
                    /* No image data at all? Okay, add some fallback content instead. */
                    None => {
                        list.push(~dl::SolidColor(bounds, bgcolor.red, bgcolor.green, bgcolor.blue));
                    }
                }
            }
        }
    }
}

impl RenderBox : BoxedDebugMethods {
    fn dump(@self) {
        self.dump_indent(0u);
    }

    /* Dumps the node tree, for debugging, with indentation. */
    fn dump_indent(@self, indent: uint) {
        let mut s = ~"";
        for uint::range(0u, indent) |_i| {
            s += ~"    ";
        }

        s += self.debug_str();
        debug!("%s", s);
    }

    fn debug_str(@self) -> ~str {
        let repr = match self {
            @GenericBox(*) => ~"GenericBox",
            @ImageBox(*) => ~"ImageBox",
            @TextBox(_,d) => fmt!("TextBox(text=%s)", str::substr(d.run.text, d.offset, d.length)),
            @UnscannedTextBox(_,s) => fmt!("UnscannedTextBox(%s)", s)
        };

        fmt!("box b%?: %?", self.d().id, repr)
    }
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
// Copyright © 2014-2018 Miguel Peláez <kernelfreeze@outlook.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
// files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use core::resource_manager::resource::Resource;
use core::resource_manager::resource_type::ResourceType;

use core::settings::Settings;

#[test]
fn resource_path_litecraft() {
    let resource = Resource::litecraft("logo", ResourceType::Texture);

    assert_eq!(
        resource.folder("resources"),
        "resources/litecraft/textures/logo.png"
    );
}

#[test]
fn resource_path_minecraft() {
    let resource = Resource::minecraft_path("creeper", "entity", ResourceType::Texture);

    assert_eq!(
        resource.folder("assets"),
        "assets/minecraft/textures/entity/creeper.png"
    );
}

#[test]
#[should_panic]
fn resource_not_found() {
    let settings = Settings::new();
    let resource = Resource::litecraft("panic", ResourceType::Text).load(&settings);
}

#[test]
#[should_panic]
fn resource_binary_not_found() {
    let settings = Settings::new();
    let resource = Resource::litecraft("panic", ResourceType::Text).load_binary(&settings);
}
<commit_msg>Fix tests<commit_after>// The MIT License (MIT)
// Copyright © 2014-2018 Miguel Peláez <kernelfreeze@outlook.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
// files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use core::resource_manager::resource::Resource;
use core::resource_manager::resource_type::ResourceType;

#[test]
fn resource_path_litecraft() {
    let resource = Resource::litecraft("logo", ResourceType::Texture);

    assert_eq!(
        resource.folder("resources"),
        "resources/litecraft/textures/logo.png"
    );
}

#[test]
fn resource_load_logo() {
    let resource = Resource::litecraft("logo", ResourceType::Texture);
    resource.load_binary();

    assert_eq!(
        resource.folder("resources"),
        "resources/litecraft/textures/logo.png"
    );
}

#[test]
#[should_panic]
fn resource_load_as_text_logo() {
    let resource = Resource::litecraft("logo", ResourceType::Texture);
    resource.load();

    assert_eq!(
        resource.folder("resources"),
        "resources/litecraft/textures/logo.png"
    );
}

#[test]
fn resource_path_minecraft() {
    let resource = Resource::minecraft_path("creeper", "entity", ResourceType::Texture);

    assert_eq!(
        resource.folder("assets"),
        "assets/minecraft/textures/entity/creeper.png"
    );
}

#[test]
#[should_panic]
fn resource_not_found() {
    let resource = Resource::litecraft("panic", ResourceType::Text);
    resource.load();
}

#[test]
#[should_panic]
fn resource_binary_not_found() {
    let resource = Resource::litecraft("panic", ResourceType::Text);
    resource.load_binary();
}
<|endoftext|>