<commit_before>// CITA
// Copyright 2016-2019 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

extern crate clap;
extern crate dotenv;
extern crate error;
extern crate fs2;
#[macro_use]
extern crate libproto;
#[macro_use]
extern crate logger;
extern crate pubsub;
#[macro_use]
extern crate util;

use clap::App;
use fs2::FileExt;
use libproto::router::{MsgType, RoutingKey, SubModules};
use postman::Postman;
use pubsub::start_pubsub;
use std::fs::{self, File, OpenOptions};
use std::sync::mpsc::channel;
use util::set_panic_handler;

mod postman;

const SNAPSHOT_LOCK: &str = ".cita_snapshot";

fn main() {
    micro_service_init!("cita-snapshot", "CITA:snapshot");

    // 1. Aquire client's lock
    let locker = lock();

    // 2. Parse command-line options
    let matches = App::new("snapshot")
        .version("2.0")
        .author("Cryptape")
        .about("CITA Block Chain Node powered by Rust")
        .arg_from_usage("-m, --cmd=[snapshot] 'snapshot or restore'")
        .arg_from_usage("-f, --file=[snapshot] 'the file of snapshot'") //snap file path
        .arg_from_usage("-s, --start_height=[0] 'start height'") //latest or valid ancient block_id
        .arg_from_usage("-e, --end_height=[1000] 'end height'") //todo remove
        .get_matches();
    let command = matches.value_of("cmd").expect("provide specific command");
    let command = cast_command(command);
    let file = matches
        .value_of("file")
        .expect("provice specific snapshot-file path");
    let file = file.to_owned();
    let start_height = matches.value_of("start_height").unwrap_or("0");
    let start_height = cast_height(start_height);
    let end_height = matches.value_of("end_height").unwrap_or("0");
    let end_height = cast_height(end_height);

    // 3. Start message-bus watcher in background
    let (mq_req_sender, mq_req_receiver) = channel();
    let (mq_resp_sender, mq_resp_receiver) = channel();
    start_pubsub(
        "snapshot",
        routing_key!([
            Net >> SnapshotResp,
            Consensus >> SnapshotResp,
            Executor >> SnapshotResp,
            Chain >> SnapshotResp,
            Auth >> SnapshotResp,
        ]),
        mq_req_sender,
        mq_resp_receiver,
    );

    // 4. Create a postman and start serving
    let mut postman = Postman::new(
        mq_req_receiver,
        mq_resp_sender,
        command,
        start_height,
        end_height,
        file,
    );
    postman.clear_message_bus();
    match postman.serve() {
        Ok(()) => info!("successful to {}", postman.command),
        Err(err) => error!("failed to {}: {:?}", postman.command, err),
    }

    // 5. Release client's lock
    unlock(&locker);
}

fn lock() -> File {
    let locker = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open(SNAPSHOT_LOCK)
        .unwrap_or_else(|_| panic!("failed to open lock-file {}", SNAPSHOT_LOCK));
    locker
        .try_lock_exclusive()
        .expect("snapshot already started.");
    locker
}

fn unlock(locker: &File) {
    locker.unlock().unwrap();
    fs::remove_file(SNAPSHOT_LOCK).expect("failed to release lock-file");
}

fn cast_command(command: &str) -> String {
    assert!(
        command == "snapshot" || command == "restore",
        "given command is equal either snapshot or restore: {}",
        command,
    );
    command.to_string()
}

fn cast_height(s: &str) -> u64 {
    if s.starts_with("0x") || s.starts_with("0X") {
        u64::from_str_radix(&s[2..], 16).unwrap()
    } else {
        u64::from_str_radix(s, 10).unwrap()
    }
}
<commit_msg>Use crossbeam for snapshot_tool.<commit_after>// CITA
// Copyright 2016-2019 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

extern crate clap;
extern crate dotenv;
extern crate error;
extern crate fs2;
#[macro_use]
extern crate libproto;
#[macro_use]
extern crate logger;
extern crate pubsub;
#[macro_use]
extern crate util;

use clap::App;
use fs2::FileExt;
use libproto::router::{MsgType, RoutingKey, SubModules};
use postman::Postman;
use pubsub::channel;
use pubsub::start_pubsub;
use std::fs::{self, File, OpenOptions};
use util::set_panic_handler;

mod postman;

const SNAPSHOT_LOCK: &str = ".cita_snapshot";

fn main() {
    micro_service_init!("cita-snapshot", "CITA:snapshot");

    // 1. Aquire client's lock
    let locker = lock();

    // 2. Parse command-line options
    let matches = App::new("snapshot")
        .version("2.0")
        .author("Cryptape")
        .about("CITA Block Chain Node powered by Rust")
        .arg_from_usage("-m, --cmd=[snapshot] 'snapshot or restore'")
        .arg_from_usage("-f, --file=[snapshot] 'the file of snapshot'") //snap file path
        .arg_from_usage("-s, --start_height=[0] 'start height'") //latest or valid ancient block_id
        .arg_from_usage("-e, --end_height=[1000] 'end height'") //todo remove
        .get_matches();
    let command = matches.value_of("cmd").expect("provide specific command");
    let command = cast_command(command);
    let file = matches
        .value_of("file")
        .expect("provice specific snapshot-file path");
    let file = file.to_owned();
    let start_height = matches.value_of("start_height").unwrap_or("0");
    let start_height = cast_height(start_height);
    let end_height = matches.value_of("end_height").unwrap_or("0");
    let end_height = cast_height(end_height);

    // 3. Start message-bus watcher in background
    let (mq_req_sender, mq_req_receiver) = channel::unbounded();
    let (mq_resp_sender, mq_resp_receiver) = channel::unbounded();
    start_pubsub(
        "snapshot",
        routing_key!([
            Net >> SnapshotResp,
            Consensus >> SnapshotResp,
            Executor >> SnapshotResp,
            Chain >> SnapshotResp,
            Auth >> SnapshotResp,
        ]),
        mq_req_sender,
        mq_resp_receiver,
    );

    // 4. Create a postman and start serving
    let mut postman = Postman::new(
        mq_req_receiver,
        mq_resp_sender,
        command,
        start_height,
        end_height,
        file,
    );
    postman.clear_message_bus();
    match postman.serve() {
        Ok(()) => info!("successful to {}", postman.command),
        Err(err) => error!("failed to {}: {:?}", postman.command, err),
    }

    // 5. Release client's lock
    unlock(&locker);
}

fn lock() -> File {
    let locker = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open(SNAPSHOT_LOCK)
        .unwrap_or_else(|_| panic!("failed to open lock-file {}", SNAPSHOT_LOCK));
    locker
        .try_lock_exclusive()
        .expect("snapshot already started.");
    locker
}

fn unlock(locker: &File) {
    locker.unlock().unwrap();
    fs::remove_file(SNAPSHOT_LOCK).expect("failed to release lock-file");
}

fn cast_command(command: &str) -> String {
    assert!(
        command == "snapshot" || command == "restore",
        "given command is equal either snapshot or restore: {}",
        command,
    );
    command.to_string()
}

fn cast_height(s: &str) -> u64 {
    if s.starts_with("0x") || s.starts_with("0X") {
        u64::from_str_radix(&s[2..], 16).unwrap()
    } else {
        u64::from_str_radix(s, 10).unwrap()
    }
}
<|endoftext|>


<commit_before>use std::collections::{BTreeMap, HashMap};
use std::collections::hash_map;
use std::i32;
use std::hash::Hash;
use std::iter::{FromIterator, IntoIterator};
use std::cmp::{max, min};
use std::fmt;
use euclid::{Point2D, Size2D};

/// A structure for storing a piece of a grid map.
///
/// All contents are guaranteed to be stored in the rectangle between (0, 0) (inclusive) and `dim`
/// (exclusive).
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Prefab<T> {
    terrain: HashMap<Point2D<i32>, usize>,
    elements: Vec<T>,
    dim: Size2D<u32>,
}

impl<T: Clone + Eq + Hash> Prefab<T> {
    fn new() -> Prefab<T> {
        Prefab {
            terrain: HashMap::new(),
            elements: Vec::new(),
            dim: Size2D::new(0, 0),
        }
    }

    pub fn get<'a>(&'a self, pos: Point2D<i32>) -> Option<&'a T> {
        self.terrain.get(&pos).map(|&idx| &self.elements[idx])
    }

    pub fn map<F: Fn(T) -> U, U>(self, f: F) -> Prefab<U> {
        Prefab {
            terrain: self.terrain,
            elements: self.elements.into_iter().map(f).collect(),
            dim: self.dim,
        }
    }

    pub fn dim(&self) -> Size2D<u32> { self.dim }

    pub fn iter<'a>(&'a self) -> PrefabIterator<'a, T> {
        PrefabIterator {
            prefab: self,
            iter: self.terrain.iter(),
        }
    }
}

pub struct PrefabIterator<'a, T: 'a> {
    prefab: &'a Prefab<T>,
    iter: hash_map::Iter<'a, Point2D<i32>, usize>,
}

impl<'a, T: 'a> Iterator for PrefabIterator<'a, T> {
    type Item = (Point2D<i32>, &'a T);

    fn next(&mut self) -> Option<Self::Item> {
        match self.iter.next() {
            Some((&pos, &idx)) => Some((pos, &self.prefab.elements[idx])),
            _ => None,
        }
    }
}

impl<T: Clone + Eq + Hash> FromIterator<(Point2D<i32>, T)> for Prefab<T> {
    fn from_iter<I: IntoIterator<Item = (Point2D<i32>, T)>>(iter: I) -> Self {
        // List of unique values.
        let mut element_idx: HashMap<T, usize> = HashMap::new();
        let mut ret = Prefab::new();

        let mut min_x = i32::MAX;
        let mut min_y = i32::MAX;

        // Temporary storage before positions have been normalized.
        let mut temp_buffer = Vec::new();

        for (p, e) in iter.into_iter() {
            min_x = min(min_x, p.x);
            min_y = min(min_y, p.y);

            let val = *element_idx.entry(e.clone()).or_insert_with(|| {
                ret.elements.push(e);
                ret.elements.len() - 1
            });

            temp_buffer.push((p, val));
        }

        // Normalization: Snap bounding box to origin.
        let mut max_x = 0;
        let mut max_y = 0;

        for (mut p, e) in temp_buffer.into_iter() {
            p.x -= min_x;
            assert!(p.x >= 0);
            p.y -= min_y;
            assert!(p.y >= 0);

            max_x = max(p.x as u32, max_x);
            max_y = max(p.y as u32, max_y);

            ret.terrain.insert(p, e);
        }

        ret.dim = Size2D::new(max_x + 1, max_y + 1);

        ret
    }
}

impl Prefab<char> {
    fn from_text<F>(map: &str, project: F) -> Prefab<char>
        where F: Fn(usize, usize) -> (i32, i32)
    {
        let mut buf = Vec::new();
        for (y, line) in map.lines().enumerate() {
            for (x, c) in line.chars().enumerate() {
                let (map_x, map_y) = project(x, y);
                if !c.is_whitespace() {
                    buf.push((Point2D::new(map_x, map_y), c));
                }
            }
        }

        Prefab::from_iter(buf.into_iter())
    }

    pub fn from_text_map(map: &str) -> Prefab<char> {
        Prefab::from_text(map, |x, y| (x as i32, y as i32))
    }

    pub fn from_text_hexmap(map: &str) -> Prefab<char> {
        Prefab::from_text(map, |x, y| ((x + y) as i32 / 2, y as i32))
    }
}

impl<T: fmt::Display + Clone + Eq + Hash> fmt::Display for Prefab<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for y in 0..self.dim.height {
            for x in 0..self.dim.width {
                if let Some(c) = self.get(Point2D::new(x as i32, y as i32)) {
                    write!(f, "{}", c)?;
                } else {
                    write!(f, " ")?;
                }
            }
            writeln!(f, "")?;
        }
        Ok(())
    }
}

impl<T: fmt::Display + Clone + Eq + Hash> Prefab<T> {
    /// Return a wrapper for printing the map in hex layout.
    ///
    /// Without the wrapper the print format will be a traditional dense text map.
    pub fn hexmap_display<'a>(&'a self) -> HexmapDisplay<'a, T> { HexmapDisplay(self) }
}

/// Wrapper type for displaying the `Prefab` as a text hexmap.
pub struct HexmapDisplay<'a, T: 'a>(&'a Prefab<T>);

impl<'a, T: fmt::Display + Clone + Eq + Hash> fmt::Display for HexmapDisplay<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let max_width = (self.0.dim.width * 2 + self.0.dim.height) as i32;

        // Find the smallest displayed x-coordinate that actually shows up in the map.
        let min_x = (0..self.0.dim.width)
                        .flat_map(move |x| {
                            (0..self.0.dim.height).map(move |y| Point2D::new(x as i32, y as i32))
                        })
                        .filter(|&p| self.0.get(p).is_some())
                        .map(|p| p.x * 2 - p.y)
                        .min()
                        .unwrap_or(0);

        for y in 0..(self.0.dim.height as i32) {
            for x in min_x..(min_x + max_width) {
                if (x - y) % 2 != 0 {
                    write!(f, " ")?;
                    continue;
                }
                let map_x = (x + y) / 2;
                let map_y = y;
                if let Some(c) = self.0.get(Point2D::new(map_x, map_y)) {
                    write!(f, "{}", c)?;
                } else {
                    write!(f, " ")?;
                }
            }
            writeln!(f, "")?;
        }
        Ok(())
    }
}

/// Build a text map legend given an alphabet and a sequence of elements.
///
/// Each unique element will be assigned a letter from the alphabet. A preference function can
/// provide an additional alphabet prefix for specific values, which will be sampled before the
/// main alphabet. This will allow having standard special characters for eg. certain types of
/// terrain tiles. When no special alphabet is required, the preference function can return an
/// empty string.
pub struct LegendBuilder<T, F> {
    pub legend: BTreeMap<char, T>,
    seen_values: BTreeMap<T, char>,
    prefix_fn: F,
    alphabet: String,
}

impl<T, F> LegendBuilder<T, F>
    where T: Ord + Eq + Clone,
          F: Fn(&T) -> &'static str
{
    /// Initialize the legend builder.
    pub fn new(alphabet: String, prefix_fn: F) -> LegendBuilder<T, F> {
        LegendBuilder {
            legend: BTreeMap::new(),
            seen_values: BTreeMap::new(),
            prefix_fn: prefix_fn,
            alphabet: alphabet,
        }
    }

    /// Show a value to `LegendBuilder` and get its legend key.
    ///
    /// Returns an error if the alphabet has been exhausted.
    pub fn add(&mut self, value: &T) -> Result<char, ()> {
        if let Some(&c) = self.seen_values.get(value) {
            return Ok(c);
        }

        for c in (self.prefix_fn)(value).chars().chain(self.alphabet.chars()) {
            if self.legend.contains_key(&c) {
                continue;
            }

            self.legend.insert(c, value.clone());
            self.seen_values.insert(value.clone(), c);
            return Ok(c);
        }
        Err(())
    }
}

#[cfg(test)]
mod test {
    use euclid::Point2D;
    use super::Prefab;

    #[test]
    fn test_from_text() {
        let a = Prefab::from_text_map("
###
#..
##.
#..
");
        let b = Prefab::from_text_hexmap("
    # # #
   # . .
  # # .
 # . .
");

        assert_eq!(a, b);

        assert_eq!(Some(&'#'), a.get(Point2D::new(0, 0)));
        assert_eq!(Some(&'.'), a.get(Point2D::new(1, 1)));
        assert_eq!(Some(&'#'), a.get(Point2D::new(1, 2)));
    }

    /// Remove whitespace differences from text map strings.
    fn normalize(dirty: &str) -> String {
        // XXX: This should also normalize indetation by removing the longest whitespace prefix
        // shared by every line from each line.

        let mut ret = String::new();
        // Remove trailing whitespace and empty lines.
        let dirty = dirty.trim_right();
        // Remove heading empty lines in iterator construction.
        for line in dirty.lines().skip_while(|line| line.trim() == "") {
            ret.push_str(line.trim_right());
            ret.push('\n');
        }
        ret
    }

    #[test]
    fn test_print() {
        let hex_text = "
      # #
   # . .
  # # . .
 # . .
@ @ @ @";

        let dense_text = "
 ##
#..
##..
#..
@@@@";
        let map = Prefab::from_text_hexmap(&hex_text);

        assert_eq!(normalize(&format!("{}", map.hexmap_display())),
                   normalize(hex_text));
        assert_eq!(normalize(&format!("{}", map)), normalize(dense_text));
    }

    #[test]
    fn test_left_align() {
        let big_hex = "
                                                           * *
                                                        * * * *
                                                     * * * * * *
                                                  * * * * * * * *
                                               * * * * * * * * * *
                                            * * * * * * * * * * * *
                                         * * * * * * * * * * * * * *
                                      * * * * * * * * * * * * * * * *
                                   * * * * * * * * * * * * * * * * * *
                                * * * * * * * * * * * * * * * * * * * *
                             * * * * * * * * * * * * * * * * * * * * * *
                          * * * * * * * * * * * * * * * * * * * * * * * *
                       * * * * * * * * * * * * * * ^ * * * * * * * * * * *
                    * * * * * * * * * * * * * * * * * * * * * * * * * * * *
                 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
              * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
           * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
        * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * , , % # # , , , * * * * * * * * * * * * * *
  * * * * * * * * * * * * * * * * * * * , , , , , , , , * * * * * * * * * * * * * *
   * * * * * * * * * * * * * * * * * * , , , * * , , , * * * * * * * * * * * * * *
    * * * * * * * * * * * * * * * * * , , , , , , , , * * * * * * * * * * * * *
     * * * * * * * * * * * * * * * * , , , , , , , , * * * * * * * * * * * *
      * * * * * * * * * * * * * * * , , , , , , , , * * * * * * * * * * *
       * * * * * * * * * * * * * * , , , , , , , , * * * * * * * * * *
        * * * * * * * * * * * * * , , , , , , , , * * * * * * * * *
         * * * * * * * * * * * * * * * * * * * * * * * * * * * *
          * * * * * * * * * * * * * * * * * * * * * * * * * *
           * * * * * * * * * * * * * * * * * * * * * * * *
            * * * * * * * * * * * * * * * * * * * * * *
             * * * * * * * * * * * * * * * * * * * *
              * * * * * * * * * * * * * * * * * *
               * * * * * * * * * * * * * * * *
                * * * * * * * * * * * * * *
                 * * * * * * * * * * * *
                  * * * * * * * * * *
                   * * * * * * * *
                    * * * * * *
                     * * * *
                      * *";
        let map = Prefab::from_text_hexmap(&big_hex);

        let map2 = Prefab::from_text_hexmap(&format!("{}", map.hexmap_display()));
        assert_eq!(map, map2);

        assert_eq!(normalize(&format!("{}", map.hexmap_display())),
                   normalize(big_hex));

    }
}
<commit_msg>LegendBuilder fix<commit_after>use std::collections::{BTreeMap, HashMap};
use std::collections::hash_map;
use std::i32;
use std::hash::Hash;
use std::iter::{FromIterator, IntoIterator};
use std::cmp::{max, min};
use std::fmt;
use euclid::{Point2D, Size2D};

/// A structure for storing a piece of a grid map.
///
/// All contents are guaranteed to be stored in the rectangle between (0, 0) (inclusive) and `dim`
/// (exclusive).
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Prefab<T> {
    terrain: HashMap<Point2D<i32>, usize>,
    elements: Vec<T>,
    dim: Size2D<u32>,
}

impl<T: Clone + Eq + Hash> Prefab<T> {
    fn new() -> Prefab<T> {
        Prefab {
            terrain: HashMap::new(),
            elements: Vec::new(),
            dim: Size2D::new(0, 0),
        }
    }

    pub fn get<'a>(&'a self, pos: Point2D<i32>) -> Option<&'a T> {
        self.terrain.get(&pos).map(|&idx| &self.elements[idx])
    }

    pub fn map<F: FnMut(T) -> U, U>(self, f: F) -> Prefab<U> {
        Prefab {
            terrain: self.terrain,
            elements: self.elements.into_iter().map(f).collect(),
            dim: self.dim,
        }
    }

    pub fn dim(&self) -> Size2D<u32> { self.dim }

    pub fn iter<'a>(&'a self) -> PrefabIterator<'a, T> {
        PrefabIterator {
            prefab: self,
            iter: self.terrain.iter(),
        }
    }
}

pub struct PrefabIterator<'a, T: 'a> {
    prefab: &'a Prefab<T>,
    iter: hash_map::Iter<'a, Point2D<i32>, usize>,
}

impl<'a, T: 'a> Iterator for PrefabIterator<'a, T> {
    type Item = (Point2D<i32>, &'a T);

    fn next(&mut self) -> Option<Self::Item> {
        match self.iter.next() {
            Some((&pos, &idx)) => Some((pos, &self.prefab.elements[idx])),
            _ => None,
        }
    }
}

impl<T: Clone + Eq + Hash> FromIterator<(Point2D<i32>, T)> for Prefab<T> {
    fn from_iter<I: IntoIterator<Item = (Point2D<i32>, T)>>(iter: I) -> Self {
        // List of unique values.
        let mut element_idx: HashMap<T, usize> = HashMap::new();
        let mut ret = Prefab::new();

        let mut min_x = i32::MAX;
        let mut min_y = i32::MAX;

        // Temporary storage before positions have been normalized.
        let mut temp_buffer = Vec::new();

        for (p, e) in iter.into_iter() {
            min_x = min(min_x, p.x);
            min_y = min(min_y, p.y);

            let val = *element_idx.entry(e.clone()).or_insert_with(|| {
                ret.elements.push(e);
                ret.elements.len() - 1
            });

            temp_buffer.push((p, val));
        }

        // Normalization: Snap bounding box to origin.
        let mut max_x = 0;
        let mut max_y = 0;

        for (mut p, e) in temp_buffer.into_iter() {
            p.x -= min_x;
            assert!(p.x >= 0);
            p.y -= min_y;
            assert!(p.y >= 0);

            max_x = max(p.x as u32, max_x);
            max_y = max(p.y as u32, max_y);

            ret.terrain.insert(p, e);
        }

        ret.dim = Size2D::new(max_x + 1, max_y + 1);

        ret
    }
}

impl Prefab<char> {
    fn from_text<F>(map: &str, project: F) -> Prefab<char>
        where F: Fn(usize, usize) -> (i32, i32)
    {
        let mut buf = Vec::new();
        for (y, line) in map.lines().enumerate() {
            for (x, c) in line.chars().enumerate() {
                let (map_x, map_y) = project(x, y);
                if !c.is_whitespace() {
                    buf.push((Point2D::new(map_x, map_y), c));
                }
            }
        }

        Prefab::from_iter(buf.into_iter())
    }

    pub fn from_text_map(map: &str) -> Prefab<char> {
        Prefab::from_text(map, |x, y| (x as i32, y as i32))
    }

    pub fn from_text_hexmap(map: &str) -> Prefab<char> {
        Prefab::from_text(map, |x, y| ((x + y) as i32 / 2, y as i32))
    }
}

impl<T: fmt::Display + Clone + Eq + Hash> fmt::Display for Prefab<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for y in 0..self.dim.height {
            for x in 0..self.dim.width {
                if let Some(c) = self.get(Point2D::new(x as i32, y as i32)) {
                    write!(f, "{}", c)?;
                } else {
                    write!(f, " ")?;
                }
            }
            writeln!(f, "")?;
        }
        Ok(())
    }
}

impl<T: fmt::Display + Clone + Eq + Hash> Prefab<T> {
    /// Return a wrapper for printing the map in hex layout.
    ///
    /// Without the wrapper the print format will be a traditional dense text map.
    pub fn hexmap_display<'a>(&'a self) -> HexmapDisplay<'a, T> { HexmapDisplay(self) }
}

/// Wrapper type for displaying the `Prefab` as a text hexmap.
pub struct HexmapDisplay<'a, T: 'a>(&'a Prefab<T>);

impl<'a, T: fmt::Display + Clone + Eq + Hash> fmt::Display for HexmapDisplay<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let max_width = (self.0.dim.width * 2 + self.0.dim.height) as i32;

        // Find the smallest displayed x-coordinate that actually shows up in the map.
        let min_x = (0..self.0.dim.width)
                        .flat_map(move |x| {
                            (0..self.0.dim.height).map(move |y| Point2D::new(x as i32, y as i32))
                        })
                        .filter(|&p| self.0.get(p).is_some())
                        .map(|p| p.x * 2 - p.y)
                        .min()
                        .unwrap_or(0);

        for y in 0..(self.0.dim.height as i32) {
            for x in min_x..(min_x + max_width) {
                if (x - y) % 2 != 0 {
                    write!(f, " ")?;
                    continue;
                }
                let map_x = (x + y) / 2;
                let map_y = y;
                if let Some(c) = self.0.get(Point2D::new(map_x, map_y)) {
                    write!(f, "{}", c)?;
                } else {
                    write!(f, " ")?;
                }
            }
            writeln!(f, "")?;
        }
        Ok(())
    }
}

/// Build a text map legend given an alphabet and a sequence of elements.
///
/// Each unique element will be assigned a letter from the alphabet. A preference function can
/// provide an additional alphabet prefix for specific values, which will be sampled before the
/// main alphabet. This will allow having standard special characters for eg. certain types of
/// terrain tiles. When no special alphabet is required, the preference function can return an
/// empty string.
pub struct LegendBuilder<T, F> {
    pub legend: BTreeMap<char, T>,
    seen_values: BTreeMap<T, char>,
    prefix_fn: F,
    alphabet: String,
}

impl<T, F> LegendBuilder<T, F>
    where T: Ord + Eq + Clone,
          F: FnMut(&T) -> &'static str
{
    /// Initialize the legend builder.
    pub fn new(alphabet: String, prefix_fn: F) -> LegendBuilder<T, F> {
        LegendBuilder {
            legend: BTreeMap::new(),
            seen_values: BTreeMap::new(),
            prefix_fn: prefix_fn,
            alphabet: alphabet,
        }
    }

    /// Show a value to `LegendBuilder` and get its legend key.
    ///
    /// Returns an error if the alphabet has been exhausted.
    pub fn add(&mut self, value: &T) -> Result<char, ()> {
        if let Some(&c) = self.seen_values.get(value) {
            return Ok(c);
        }

        for c in (self.prefix_fn)(value).chars().chain(self.alphabet.chars()) {
            if self.legend.contains_key(&c) {
                continue;
            }

            self.legend.insert(c, value.clone());
            self.seen_values.insert(value.clone(), c);
            return Ok(c);
        }
        Err(())
    }
}

#[cfg(test)]
mod test {
    use euclid::Point2D;
    use super::Prefab;

    #[test]
    fn test_from_text() {
        let a = Prefab::from_text_map("
###
#..
##.
#..
");
        let b = Prefab::from_text_hexmap("
    # # #
   # . .
  # # .
 # . .
");

        assert_eq!(a, b);

        assert_eq!(Some(&'#'), a.get(Point2D::new(0, 0)));
        assert_eq!(Some(&'.'), a.get(Point2D::new(1, 1)));
        assert_eq!(Some(&'#'), a.get(Point2D::new(1, 2)));
    }

    /// Remove whitespace differences from text map strings.
    fn normalize(dirty: &str) -> String {
        // XXX: This should also normalize indetation by removing the longest whitespace prefix
        // shared by every line from each line.

        let mut ret = String::new();
        // Remove trailing whitespace and empty lines.
        let dirty = dirty.trim_right();
        // Remove heading empty lines in iterator construction.
        for line in dirty.lines().skip_while(|line| line.trim() == "") {
            ret.push_str(line.trim_right());
            ret.push('\n');
        }
        ret
    }

    #[test]
    fn test_print() {
        let hex_text = "
      # #
   # . .
  # # . .
 # . .
@ @ @ @";

        let dense_text = "
 ##
#..
##..
#..
@@@@";
        let map = Prefab::from_text_hexmap(&hex_text);

        assert_eq!(normalize(&format!("{}", map.hexmap_display())),
                   normalize(hex_text));
        assert_eq!(normalize(&format!("{}", map)), normalize(dense_text));
    }

    #[test]
    fn test_left_align() {
        let big_hex = "
                                                           * *
                                                        * * * *
                                                     * * * * * *
                                                  * * * * * * * *
                                               * * * * * * * * * *
                                            * * * * * * * * * * * *
                                         * * * * * * * * * * * * * *
                                      * * * * * * * * * * * * * * * *
                                   * * * * * * * * * * * * * * * * * *
                                * * * * * * * * * * * * * * * * * * * *
                             * * * * * * * * * * * * * * * * * * * * * *
                          * * * * * * * * * * * * * * * * * * * * * * * *
                       * * * * * * * * * * * * * * ^ * * * * * * * * * * *
                    * * * * * * * * * * * * * * * * * * * * * * * * * * * *
                 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
              * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
           * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
        * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * , , % # # , , , * * * * * * * * * * * * * *
  * * * * * * * * * * * * * * * * * * * , , , , , , , , * * * * * * * * * * * * * *
   * * * * * * * * * * * * * * * * * * , , , * * , , , * * * * * * * * * * * * * *
    * * * * * * * * * * * * * * * * * , , , , , , , , * * * * * * * * * * * * *
     * * * * * * * * * * * * * * * * , , , , , , , , * * * * * * * * * * * *
      * * * * * * * * * * * * * * * , , , , , , , , * * * * * * * * * * *
       * * * * * * * * * * * * * * , , , , , , , , * * * * * * * * * *
        * * * * * * * * * * * * * , , , , , , , , * * * * * * * * *
         * * * * * * * * * * * * * * * * * * * * * * * * * * * *
          * * * * * * * * * * * * * * * * * * * * * * * * * *
           * * * * * * * * * * * * * * * * * * * * * * * *
            * * * * * * * * * * * * * * * * * * * * * *
             * * * * * * * * * * * * * * * * * * * *
              * * * * * * * * * * * * * * * * * *
               * * * * * * * * * * * * * * * *
                * * * * * * * * * * * * * *
                 * * * * * * * * * * * *
                  * * * * * * * * * *
                   * * * * * * * *
                    * * * * * *
                     * * * *
                      * *";
        let map = Prefab::from_text_hexmap(&big_hex);

        let map2 = Prefab::from_text_hexmap(&format!("{}", map.hexmap_display()));
        assert_eq!(map, map2);

        assert_eq!(normalize(&format!("{}", map.hexmap_display())),
                   normalize(big_hex));

    }
}
<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

mod inst {
    use option::{None, Option, Some};

    #[allow(non_camel_case_types)]
    pub type IMPL_T<A> = Option<A>;

    #[inline(always)]
    pub pure fn EACH<A>(self: &IMPL_T<A>, f: fn(v: &A) -> bool) {
        match *self {
            None => (),
            Some(ref a) => { f(a); }
        }
    }

    #[inline(always)]
    pub pure fn SIZE_HINT<A>(self: &IMPL_T<A>) -> Option<uint> {
        match *self {
            None => Some(0),
            Some(_) => Some(1)
        }
    }
}
<commit_msg>rm obsolete iter-trait/option.rs file<commit_after><|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Sampling from random distributions

// Some implementations use the Ziggurat method
// https://en.wikipedia.org/wiki/Ziggurat_algorithm
//
// The version used here is ZIGNOR [Doornik 2005, "An Improved
// Ziggurat Method to Generate Normal Random Samples"] which is slower
// (about double, it generates an extra random number) than the
// canonical version [Marsaglia & Tsang 2000, "The Ziggurat Method for
// Generating Random Variables"], but more robust. If one wanted, one
// could implement VIZIGNOR the ZIGNOR paper for more speed.

use f64;
use prelude::*;
use rand::{Rng,Rand};

mod ziggurat_tables;

// inlining should mean there is no performance penalty for this
#[inline(always)]
fn ziggurat<R:Rng>(rng: &mut R,
                   center_u: bool,
                   X: ziggurat_tables::ZigTable,
                   F: ziggurat_tables::ZigTable,
                   F_DIFF: ziggurat_tables::ZigTable,
                   pdf: &'static fn(f64) -> f64, // probability density function
                   zero_case: &'static fn(&mut R, f64) -> f64) -> f64 {
    loop {
        let u = if center_u {2.0 * rng.gen() - 1.0} else {rng.gen()};
        let i: uint = rng.gen::<uint>() & 0xff;
        let x = u * X[i];

        let test_x = if center_u {f64::abs(x)} else {x};

        // algebraically equivalent to |u| < X[i+1]/X[i] (or u < X[i+1]/X[i])
        if test_x < X[i + 1] {
            return x;
        }
        if i == 0 {
            return zero_case(rng, u);
        }
        // algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1
        if F[i+1] + F_DIFF[i+1] * rng.gen() < pdf(x) {
            return x;
        }
    }
}

/// A wrapper around an `f64` to generate N(0, 1) random numbers (a.k.a.  a
/// standard normal, or Gaussian). Multiplying the generated values by the
/// desired standard deviation `sigma` then adding the desired mean `mu` will
/// give N(mu, sigma^2) distributed random numbers.
///
/// Note that this has to be unwrapped before use as an `f64` (using either
/// `*` or `cast::transmute` is safe).
///
/// # Example
///
/// ~~~
/// use core::rand::distributions::StandardNormal;
///
/// fn main() {
///     let normal = 2.0 + (*rand::random::<StandardNormal>()) * 3.0;
///     println(fmt!("%f is from a N(2, 9) distribution", normal))
/// }
/// ~~~
pub struct StandardNormal(f64);

impl Rand for StandardNormal {
    fn rand<R:Rng>(rng: &mut R) -> StandardNormal {
        #[inline(always)]
        fn pdf(x: f64) -> f64 {
            f64::exp((-x*x/2.0) as f64) as f64
        }
        #[inline(always)]
        fn zero_case<R:Rng>(rng: &mut R, u: f64) -> f64 {
            // compute a random number in the tail by hand

            // strange initial conditions, because the loop is not
            // do-while, so the condition should be true on the first
            // run, they get overwritten anyway (0 < 1, so these are
            // good).
            let mut x = 1.0, y = 0.0;

            // XXX infinities?
            while -2.0*y < x * x {
                x = f64::ln(rng.gen()) / ziggurat_tables::ZIG_NORM_R;
                y = f64::ln(rng.gen());
            }
            if u < 0.0 {x-ziggurat_tables::ZIG_NORM_R} else {ziggurat_tables::ZIG_NORM_R-x}
        }

        StandardNormal(ziggurat(
            rng,
            true, // this is symmetric
            &ziggurat_tables::ZIG_NORM_X,
            &ziggurat_tables::ZIG_NORM_F, &ziggurat_tables::ZIG_NORM_F_DIFF,
            pdf, zero_case))
    }
}

/// A wrapper around an `f64` to generate Exp(1) random numbers. Dividing by
/// the desired rate `lambda` will give Exp(lambda) distributed random
/// numbers.
///
/// Note that this has to be unwrapped before use as an `f64` (using either
/// `*` or `cast::transmute` is safe).
///
/// # Example
///
/// ~~~
/// use core::rand::distributions::Exp1;
///
/// fn main() {
///     let exp2 = (*rand::random::<Exp1>()) * 0.5;
///     println(fmt!("%f is from a Exp(2) distribution", exp2));
/// }
/// ~~~
pub struct Exp1(f64);

// This could be done via `-f64::ln(rng.gen::<f64>())` but that is slower.
impl Rand for Exp1 {
    #[inline]
    fn rand<R:Rng>(rng: &mut R) -> Exp1 {
        #[inline(always)]
        fn pdf(x: f64) -> f64 {
            f64::exp(-x)
        }
        #[inline(always)]
        fn zero_case<R:Rng>(rng: &mut R, _u: f64) -> f64 {
            ziggurat_tables::ZIG_EXP_R - f64::ln(rng.gen())
        }

        Exp1(ziggurat(rng, false,
                      &ziggurat_tables::ZIG_EXP_X,
                      &ziggurat_tables::ZIG_EXP_F, &ziggurat_tables::ZIG_EXP_F_DIFF,
                      pdf, zero_case))
    }
}
<commit_msg>Remove unnecessary 'use' forms<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Sampling from random distributions

// Some implementations use the Ziggurat method
// https://en.wikipedia.org/wiki/Ziggurat_algorithm
//
// The version used here is ZIGNOR [Doornik 2005, "An Improved
// Ziggurat Method to Generate Normal Random Samples"] which is slower
// (about double, it generates an extra random number) than the
// canonical version [Marsaglia & Tsang 2000, "The Ziggurat Method for
// Generating Random Variables"], but more robust. If one wanted, one
// could implement VIZIGNOR the ZIGNOR paper for more speed.

use f64;
use rand::{Rng,Rand};

mod ziggurat_tables;

// inlining should mean there is no performance penalty for this
#[inline(always)]
fn ziggurat<R:Rng>(rng: &mut R,
                   center_u: bool,
                   X: ziggurat_tables::ZigTable,
                   F: ziggurat_tables::ZigTable,
                   F_DIFF: ziggurat_tables::ZigTable,
                   pdf: &'static fn(f64) -> f64, // probability density function
                   zero_case: &'static fn(&mut R, f64) -> f64) -> f64 {
    loop {
        let u = if center_u {2.0 * rng.gen() - 1.0} else {rng.gen()};
        let i: uint = rng.gen::<uint>() & 0xff;
        let x = u * X[i];

        let test_x = if center_u {f64::abs(x)} else {x};

        // algebraically equivalent to |u| < X[i+1]/X[i] (or u < X[i+1]/X[i])
        if test_x < X[i + 1] {
            return x;
        }
        if i == 0 {
            return zero_case(rng, u);
        }
        // algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1
        if F[i+1] + F_DIFF[i+1] * rng.gen() < pdf(x) {
            return x;
        }
    }
}

/// A wrapper around an `f64` to generate N(0, 1) random numbers (a.k.a.  a
/// standard normal, or Gaussian). Multiplying the generated values by the
/// desired standard deviation `sigma` then adding the desired mean `mu` will
/// give N(mu, sigma^2) distributed random numbers.
///
/// Note that this has to be unwrapped before use as an `f64` (using either
/// `*` or `cast::transmute` is safe).
///
/// # Example
///
/// ~~~
/// use core::rand::distributions::StandardNormal;
///
/// fn main() {
///     let normal = 2.0 + (*rand::random::<StandardNormal>()) * 3.0;
///     println(fmt!("%f is from a N(2, 9) distribution", normal))
/// }
/// ~~~
pub struct StandardNormal(f64);

impl Rand for StandardNormal {
    fn rand<R:Rng>(rng: &mut R) -> StandardNormal {
        #[inline(always)]
        fn pdf(x: f64) -> f64 {
            f64::exp((-x*x/2.0) as f64) as f64
        }
        #[inline(always)]
        fn zero_case<R:Rng>(rng: &mut R, u: f64) -> f64 {
            // compute a random number in the tail by hand

            // strange initial conditions, because the loop is not
            // do-while, so the condition should be true on the first
            // run, they get overwritten anyway (0 < 1, so these are
            // good).
            let mut x = 1.0, y = 0.0;

            // XXX infinities?
            while -2.0*y < x * x {
                x = f64::ln(rng.gen()) / ziggurat_tables::ZIG_NORM_R;
                y = f64::ln(rng.gen());
            }
            if u < 0.0 {x-ziggurat_tables::ZIG_NORM_R} else {ziggurat_tables::ZIG_NORM_R-x}
        }

        StandardNormal(ziggurat(
            rng,
            true, // this is symmetric
            &ziggurat_tables::ZIG_NORM_X,
            &ziggurat_tables::ZIG_NORM_F, &ziggurat_tables::ZIG_NORM_F_DIFF,
            pdf, zero_case))
    }
}

/// A wrapper around an `f64` to generate Exp(1) random numbers. Dividing by
/// the desired rate `lambda` will give Exp(lambda) distributed random
/// numbers.
///
/// Note that this has to be unwrapped before use as an `f64` (using either
/// `*` or `cast::transmute` is safe).
///
/// # Example
///
/// ~~~
/// use core::rand::distributions::Exp1;
///
/// fn main() {
///     let exp2 = (*rand::random::<Exp1>()) * 0.5;
///     println(fmt!("%f is from a Exp(2) distribution", exp2));
/// }
/// ~~~
pub struct Exp1(f64);

// This could be done via `-f64::ln(rng.gen::<f64>())` but that is slower.
impl Rand for Exp1 {
    #[inline]
    fn rand<R:Rng>(rng: &mut R) -> Exp1 {
        #[inline(always)]
        fn pdf(x: f64) -> f64 {
            f64::exp(-x)
        }
        #[inline(always)]
        fn zero_case<R:Rng>(rng: &mut R, _u: f64) -> f64 {
            ziggurat_tables::ZIG_EXP_R - f64::ln(rng.gen())
        }

        Exp1(ziggurat(rng, false,
                      &ziggurat_tables::ZIG_EXP_X,
                      &ziggurat_tables::ZIG_EXP_F, &ziggurat_tables::ZIG_EXP_F_DIFF,
                      pdf, zero_case))
    }
}
<|endoftext|>


<commit_before>use std::cell::Cell;

use cgmath::Vector2;
use smithay::{
    backend::{
        allocator::dmabuf::Dmabuf,
        renderer::{Frame, ImportDma, ImportShm, Renderer, Texture, Transform},
        SwapBuffersError,
    },
    reexports::wayland_server::protocol::wl_buffer,
    utils::{Buffer, Physical, Rectangle, Size},
    wayland::compositor::SurfaceData,
};

pub struct DummyRenderer {}

impl DummyRenderer {
    pub fn new() -> DummyRenderer {
        DummyRenderer {}
    }
}

impl Renderer for DummyRenderer {
    type Error = SwapBuffersError;
    type TextureId = DummyTexture;
    type Frame = DummyFrame;

    fn render<F, R>(
        &mut self,
        _size: Size<i32, Physical>,
        _transform: Transform,
        rendering: F,
    ) -> Result<R, Self::Error>
    where
        F: FnOnce(&mut Self, &mut Self::Frame) -> R,
    {
        let mut frame = DummyFrame {};
        Ok(rendering(self, &mut frame))
    }
}

impl ImportShm for DummyRenderer {
    fn import_shm_buffer(
        &mut self,
        buffer: &wl_buffer::WlBuffer,
        surface: Option<&SurfaceData>,
        _damage: &[Rectangle<i32, Buffer>],
    ) -> Result<<Self as Renderer>::TextureId, <Self as Renderer>::Error> {
        use smithay::wayland::shm::with_buffer_contents;
        let ret = with_buffer_contents(&buffer, |slice, data| {
            let offset = data.offset as u32;
            let width = data.width as u32;
            let height = data.height as u32;
            let stride = data.stride as u32;

            let mut x = 0;
            for h in 0..height {
                for w in 0..width {
                    x |= slice[(offset + w + h * stride) as usize];
                }
            }

            if let Some(data) = surface {
                data.data_map.insert_if_missing(|| Cell::new(0u8));
                data.data_map.get::<Cell<u8>>().unwrap().set(x);
            }

            (width, height)
        });

        match ret {
            Ok((width, height)) => Ok(DummyTexture { width, height }),
            Err(e) => Err(SwapBuffersError::TemporaryFailure(Box::new(e))),
        }
    }
}

impl ImportDma for DummyRenderer {
    fn import_dmabuf(
        &mut self,
        _dmabuf: &Dmabuf,
    ) -> Result<<Self as Renderer>::TextureId, <Self as Renderer>::Error> {
        unimplemented!()
    }
}

pub struct DummyFrame {}

impl Frame for DummyFrame {
    type Error = SwapBuffersError;
    type TextureId = DummyTexture;

    fn clear(&mut self, _color: [f32; 4]) -> Result<(), Self::Error> {
        Ok(())
    }

    fn render_texture(
        &mut self,
        _texture: &Self::TextureId,
        _matrix: cgmath::Matrix3<f32>,
        _tex_coords: [Vector2<f32>; 4],
        _alpha: f32,
    ) -> Result<(), Self::Error> {
        Ok(())
    }
}

pub struct DummyTexture {
    width: u32,
    height: u32,
}

impl Texture for DummyTexture {
    fn width(&self) -> u32 {
        self.width
    }

    fn height(&self) -> u32 {
        self.height
    }
}
<commit_msg>wlcs_anvil: Adjust dummy renderer for changes<commit_after>use std::cell::Cell;

use smithay::{
    backend::{
        allocator::dmabuf::Dmabuf,
        renderer::{Frame, ImportDma, ImportShm, Renderer, Texture, TextureFilter, Transform},
        SwapBuffersError,
    },
    reexports::wayland_server::protocol::wl_buffer,
    utils::{Buffer, Physical, Rectangle, Size},
    wayland::compositor::SurfaceData,
};

pub struct DummyRenderer {}

impl DummyRenderer {
    pub fn new() -> DummyRenderer {
        DummyRenderer {}
    }
}

impl Renderer for DummyRenderer {
    type Error = SwapBuffersError;
    type TextureId = DummyTexture;
    type Frame = DummyFrame;

    fn render<F, R>(
        &mut self,
        _size: Size<i32, Physical>,
        _dst_transform: Transform,
        rendering: F,
    ) -> Result<R, Self::Error>
    where
        F: FnOnce(&mut Self, &mut Self::Frame) -> R,
    {
        let mut frame = DummyFrame {};
        Ok(rendering(self, &mut frame))
    }

    fn upscale_filter(&mut self, _filter: TextureFilter) -> Result<(), Self::Error> {
        Ok(())
    }

    fn downscale_filter(&mut self, _filter: TextureFilter) -> Result<(), Self::Error> {
        Ok(())
    }
}

impl ImportShm for DummyRenderer {
    fn import_shm_buffer(
        &mut self,
        buffer: &wl_buffer::WlBuffer,
        surface: Option<&SurfaceData>,
        _damage: &[Rectangle<i32, Buffer>],
    ) -> Result<<Self as Renderer>::TextureId, <Self as Renderer>::Error> {
        use smithay::wayland::shm::with_buffer_contents;
        let ret = with_buffer_contents(&buffer, |slice, data| {
            let offset = data.offset as u32;
            let width = data.width as u32;
            let height = data.height as u32;
            let stride = data.stride as u32;

            let mut x = 0;
            for h in 0..height {
                for w in 0..width {
                    x |= slice[(offset + w + h * stride) as usize];
                }
            }

            if let Some(data) = surface {
                data.data_map.insert_if_missing(|| Cell::new(0u8));
                data.data_map.get::<Cell<u8>>().unwrap().set(x);
            }

            (width, height)
        });

        match ret {
            Ok((width, height)) => Ok(DummyTexture { width, height }),
            Err(e) => Err(SwapBuffersError::TemporaryFailure(Box::new(e))),
        }
    }
}

impl ImportDma for DummyRenderer {
    fn import_dmabuf(
        &mut self,
        _dmabuf: &Dmabuf,
    ) -> Result<<Self as Renderer>::TextureId, <Self as Renderer>::Error> {
        unimplemented!()
    }
}

pub struct DummyFrame {}

impl Frame for DummyFrame {
    type Error = SwapBuffersError;
    type TextureId = DummyTexture;

    fn clear(&mut self, _color: [f32; 4]) -> Result<(), Self::Error> {
        Ok(())
    }

    fn render_texture_from_to(
        &mut self,
        _texture: &Self::TextureId,
        _src: Rectangle<i32, Buffer>,
        _dst: Rectangle<f64, Physical>,
        _src_transform: Transform,
        _alpha: f32,
    ) -> Result<(), Self::Error> {
        Ok(())
    }
}

pub struct DummyTexture {
    width: u32,
    height: u32,
}

impl Texture for DummyTexture {
    fn width(&self) -> u32 {
        self.width
    }

    fn height(&self) -> u32 {
        self.height
    }
}
<|endoftext|>


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

//! CSS handling for the computed value of
//! [grids](https://drafts.csswg.org/css-grid/)

use cssparser::{Parser, Token, BasicParseError};
use parser::{Parse, ParserContext};
use std::ascii::AsciiExt;
use std::mem;
use style_traits::{HasViewportPercentage, ParseError, StyleParseError};
use values::{CSSFloat, CustomIdent};
use values::computed::{self, Context, ToComputedValue};
use values::generics::grid::{GridTemplateComponent, RepeatCount, TrackBreadth, TrackKeyword, TrackRepeat};
use values::generics::grid::{LineNameList, TrackSize, TrackList, TrackListType};
use values::specified::LengthOrPercentage;

/// Parse a single flexible length.
pub fn parse_flex<'i, 't>(input: &mut Parser<'i, 't>) -> Result<CSSFloat, ParseError<'i>> {
    match input.next()? {
        Token::Dimension { value, ref unit, .. } if unit.eq_ignore_ascii_case("fr") && value.is_sign_positive()
            => Ok(value),
        t => Err(BasicParseError::UnexpectedToken(t).into()),
    }
}

impl Parse for TrackBreadth<LengthOrPercentage> {
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
            return Ok(TrackBreadth::Breadth(lop))
        }

        if let Ok(f) = input.try(parse_flex) {
            return Ok(TrackBreadth::Flex(f))
        }

        TrackKeyword::parse(input).map(TrackBreadth::Keyword)
    }
}

impl HasViewportPercentage for TrackBreadth<LengthOrPercentage> {
    #[inline]
    fn has_viewport_percentage(&self) -> bool {
        if let TrackBreadth::Breadth(ref lop) = *self {
            lop.has_viewport_percentage()
        } else {
            false
        }
    }
}

impl Parse for TrackSize<LengthOrPercentage> {
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        if let Ok(b) = input.try(|i| TrackBreadth::parse(context, i)) {
            return Ok(TrackSize::Breadth(b))
        }

        if input.try(|i| i.expect_function_matching("minmax")).is_ok() {
            return input.parse_nested_block(|input| {
                let inflexible_breadth =
                    match input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
                        Ok(lop) => TrackBreadth::Breadth(lop),
                        Err(..) => {
                            let keyword = TrackKeyword::parse(input)?;
                            TrackBreadth::Keyword(keyword)
                        }
                    };

                input.expect_comma()?;
                Ok(TrackSize::Minmax(inflexible_breadth, TrackBreadth::parse(context, input)?))
            });
        }

        input.expect_function_matching("fit-content")?;
        let lop = input.parse_nested_block(|i| LengthOrPercentage::parse_non_negative(context, i))?;
        Ok(TrackSize::FitContent(lop))
    }
}

/// Parse the grid line names into a vector of owned strings.
///
/// https://drafts.csswg.org/css-grid/#typedef-line-names
pub fn parse_line_names<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Box<[CustomIdent]>, ParseError<'i>> {
    input.expect_square_bracket_block()?;
    input.parse_nested_block(|input| {
        let mut values = vec![];
        while let Ok(ident) = input.try(|i| i.expect_ident()) {
            let ident = CustomIdent::from_ident(ident, &["span"])?;
            values.push(ident);
        }

        Ok(values.into_boxed_slice())
    })
}

/// The type of `repeat` function (only used in parsing).
///
/// https://drafts.csswg.org/css-grid/#typedef-track-repeat
#[derive(Clone, Copy, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
enum RepeatType {
    /// [`<auto-repeat>`](https://drafts.csswg.org/css-grid/#typedef-auto-repeat)
    Auto,
    /// [`<track-repeat>`](https://drafts.csswg.org/css-grid/#typedef-track-repeat)
    Normal,
    /// [`<fixed-repeat>`](https://drafts.csswg.org/css-grid/#typedef-fixed-repeat)
    Fixed,
}

impl TrackRepeat<LengthOrPercentage> {
    fn parse_with_repeat_type<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
                                      -> Result<(TrackRepeat<LengthOrPercentage>, RepeatType), ParseError<'i>> {
        input.try(|i| i.expect_function_matching("repeat").map_err(|e| e.into())).and_then(|_| {
            input.parse_nested_block(|input| {
                let count = RepeatCount::parse(context, input)?;
                input.expect_comma()?;

                let is_auto = count == RepeatCount::AutoFit || count == RepeatCount::AutoFill;
                let mut repeat_type = if is_auto {
                    RepeatType::Auto
                } else {    // <fixed-size> is a subset of <track_size>, so it should work for both
                    RepeatType::Fixed
                };

                let mut names = vec![];
                let mut values = vec![];
                let mut current_names;

                loop {
                    current_names = input.try(parse_line_names).unwrap_or(vec![].into_boxed_slice());
                    if let Ok(track_size) = input.try(|i| TrackSize::parse(context, i)) {
                        if !track_size.is_fixed() {
                            if is_auto {
                                // should be <fixed-size> for <auto-repeat>
                                return Err(StyleParseError::UnspecifiedError.into())
                            }

                            if repeat_type == RepeatType::Fixed {
                                repeat_type = RepeatType::Normal       // <track-size> for sure
                            }
                        }

                        values.push(track_size);
                        names.push(current_names);
                        if is_auto {
                            // FIXME: In the older version of the spec
                            // (https://www.w3.org/TR/2015/WD-css-grid-1-20150917/#typedef-auto-repeat),
                            // if the repeat type is `<auto-repeat>` we shouldn't try to parse more than
                            // one `TrackSize`. But in current version of the spec, this is deprecated
                            // but we are adding this for gecko parity. We should remove this when
                            // gecko implements new spec.
                            names.push(input.try(parse_line_names).unwrap_or(vec![].into_boxed_slice()));
                            break
                        }
                    } else {
                        if values.is_empty() {
                            // expecting at least one <track-size>
                            return Err(StyleParseError::UnspecifiedError.into())
                        }

                        names.push(current_names);      // final `<line-names>`
                        break       // no more <track-size>, breaking
                    }
                }

                let repeat = TrackRepeat {
                    count: count,
                    track_sizes: values,
                    line_names: names.into_boxed_slice(),
                };

                Ok((repeat, repeat_type))
            })
        })
    }
}

impl HasViewportPercentage for TrackRepeat<LengthOrPercentage> {
    #[inline]
    fn has_viewport_percentage(&self) -> bool {
        self.track_sizes.iter().any(|ref v| v.has_viewport_percentage())
    }
}

impl Parse for TrackList<LengthOrPercentage> {
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        // Merge the line names while parsing values. The resulting values will
        // all be bunch of `<track-size>` and one <auto-repeat>.
        //
        // For example,
        // `[a b] 100px [c d] repeat(1, 30px [g]) [h]` will be merged as `[a b] 100px [c d] 30px [g h]`
        //  whereas, `[a b] repeat(2, [c] 50px [d]) [e f] repeat(auto-fill, [g] 12px) 10px [h]` will be merged as
        // `[a b c] 50px [d c] 50px [d e f] repeat(auto-fill, [g] 12px) 10px [h]`, with the `<auto-repeat>` value
        // set in the `auto_repeat` field, and the `idx` in TrackListType::Auto pointing to the values after
        // `<auto-repeat>` (in this case, `10px [h]`).
        let mut current_names = vec![];
        let mut names = vec![];
        let mut values = vec![];

        let mut list_type = TrackListType::Explicit;    // assume it's the simplest case
        // holds <auto-repeat> value. It can only be only one in a TrackList.
        let mut auto_repeat = None;
        // assume that everything is <fixed-size>. This flag is useful when we encounter <auto-repeat>
        let mut atleast_one_not_fixed = false;

        loop {
            current_names.extend_from_slice(&mut input.try(parse_line_names).unwrap_or(vec![].into_boxed_slice()));
            if let Ok(track_size) = input.try(|i| TrackSize::parse(context, i)) {
                if !track_size.is_fixed() {
                    atleast_one_not_fixed = true;
                    if auto_repeat.is_some() {
                        // <auto-track-list> only accepts <fixed-size> and <fixed-repeat>
                        return Err(StyleParseError::UnspecifiedError.into())
                    }
                }

                let vec = mem::replace(&mut current_names, vec![]);
                names.push(vec.into_boxed_slice());
                values.push(track_size);
            } else if let Ok((repeat, type_)) = input.try(|i| TrackRepeat::parse_with_repeat_type(context, i)) {
                if list_type == TrackListType::Explicit {
                    list_type = TrackListType::Normal;      // <explicit-track-list> doesn't contain repeat()
                }

                match type_ {
                    RepeatType::Normal => {
                        atleast_one_not_fixed = true;
                        if auto_repeat.is_some() { // only <fixed-repeat>
                            return Err(StyleParseError::UnspecifiedError.into())
                        }
                    },
                    RepeatType::Auto => {
                        if auto_repeat.is_some() || atleast_one_not_fixed {
                            // We've either seen <auto-repeat> earlier, or there's at least one non-fixed value
                            return Err(StyleParseError::UnspecifiedError.into())
                        }

                        list_type = TrackListType::Auto(values.len() as u16);
                        auto_repeat = Some(repeat);
                        let vec = mem::replace(&mut current_names, vec![]);
                        names.push(vec.into_boxed_slice());
                        continue
                    },
                    RepeatType::Fixed => (),
                }

                // If the repeat count is numeric, we axpand and merge the values.
                let mut repeat = repeat.expand();
                let mut repeat_names_iter = repeat.line_names.iter();
                for (size, repeat_names) in repeat.track_sizes.drain(..).zip(&mut repeat_names_iter) {
                    current_names.extend_from_slice(&repeat_names);
                    let vec = mem::replace(&mut current_names, vec![]);
                    names.push(vec.into_boxed_slice());
                    values.push(size);
                }

                if let Some(names) = repeat_names_iter.next() {
                    current_names.extend_from_slice(&names);
                }
            } else {
                if values.is_empty() && auto_repeat.is_none() {
                    return Err(StyleParseError::UnspecifiedError.into())
                }

                names.push(current_names.into_boxed_slice());
                break
            }
        }

        Ok(TrackList {
            list_type: list_type,
            values: values,
            line_names: names.into_boxed_slice(),
            auto_repeat: auto_repeat,
        })
    }
}

impl HasViewportPercentage for TrackList<LengthOrPercentage> {
    #[inline]
    fn has_viewport_percentage(&self) -> bool {
        self.values.iter().any(|ref v| v.has_viewport_percentage())
    }
}

impl ToComputedValue for TrackList<LengthOrPercentage> {
    type ComputedValue = TrackList<computed::LengthOrPercentage>;

    #[inline]
    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
        let mut values = Vec::with_capacity(self.values.len() + 1);
        for value in self.values.iter().map(|val| val.to_computed_value(context)) {
            values.push(value);
        }

        TrackList {
            list_type: self.list_type.to_computed_value(context),
            values: values,
            line_names: self.line_names.clone(),
            auto_repeat: self.auto_repeat.clone().map(|repeat| repeat.to_computed_value(context)),
        }
    }

    #[inline]
    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
        let mut values = Vec::with_capacity(computed.values.len() + 1);
        for value in computed.values.iter().map(ToComputedValue::from_computed_value) {
            values.push(value);
        }

        TrackList {
            list_type: computed.list_type,
            values: values,
            line_names: computed.line_names.clone(),
            auto_repeat: computed.auto_repeat.clone().map(|ref repeat| TrackRepeat::from_computed_value(repeat)),
        }
    }
}

impl Parse for GridTemplateComponent<LengthOrPercentage> {
    // FIXME: Derive Parse (probably with None_)
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        if input.try(|i| i.expect_ident_matching("none")).is_ok() {
            return Ok(GridTemplateComponent::None)
        }

        Self::parse_without_none(context, input)
    }
}

impl GridTemplateComponent<LengthOrPercentage> {
    /// Parses a `GridTemplateComponent<LengthOrPercentage>` except `none` keyword.
    pub fn parse_without_none<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
                                      -> Result<Self, ParseError<'i>> {
        if let Ok(t) = input.try(|i| TrackList::parse(context, i)) {
            return Ok(GridTemplateComponent::TrackList(t))
        }

        LineNameList::parse(context, input).map(GridTemplateComponent::Subgrid)
    }
}

impl HasViewportPercentage for GridTemplateComponent<LengthOrPercentage> {
    #[inline]
    fn has_viewport_percentage(&self) -> bool {
        match *self {
            GridTemplateComponent::TrackList(ref l) => l.has_viewport_percentage(),
            _ => false,
        }
    }
}

impl ToComputedValue for GridTemplateComponent<LengthOrPercentage> {
    type ComputedValue = GridTemplateComponent<computed::LengthOrPercentage>;

    #[inline]
    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
        match *self {
            GridTemplateComponent::None => GridTemplateComponent::None,
            GridTemplateComponent::TrackList(ref l) => GridTemplateComponent::TrackList(l.to_computed_value(context)),
            GridTemplateComponent::Subgrid(ref n) => GridTemplateComponent::Subgrid(n.to_computed_value(context)),
        }
    }

    #[inline]
    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
        match *computed {
            GridTemplateComponent::None => GridTemplateComponent::None,
            GridTemplateComponent::TrackList(ref l) =>
                GridTemplateComponent::TrackList(ToComputedValue::from_computed_value(l)),
            GridTemplateComponent::Subgrid(ref n) =>
                GridTemplateComponent::Subgrid(ToComputedValue::from_computed_value(n)),
        }
    }
}
<commit_msg>Add a bug link as comment for repeat function<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! CSS handling for the computed value of
//! [grids](https://drafts.csswg.org/css-grid/)

use cssparser::{Parser, Token, BasicParseError};
use parser::{Parse, ParserContext};
use std::ascii::AsciiExt;
use std::mem;
use style_traits::{HasViewportPercentage, ParseError, StyleParseError};
use values::{CSSFloat, CustomIdent};
use values::computed::{self, Context, ToComputedValue};
use values::generics::grid::{GridTemplateComponent, RepeatCount, TrackBreadth, TrackKeyword, TrackRepeat};
use values::generics::grid::{LineNameList, TrackSize, TrackList, TrackListType};
use values::specified::LengthOrPercentage;

/// Parse a single flexible length.
pub fn parse_flex<'i, 't>(input: &mut Parser<'i, 't>) -> Result<CSSFloat, ParseError<'i>> {
    match input.next()? {
        Token::Dimension { value, ref unit, .. } if unit.eq_ignore_ascii_case("fr") && value.is_sign_positive()
            => Ok(value),
        t => Err(BasicParseError::UnexpectedToken(t).into()),
    }
}

impl Parse for TrackBreadth<LengthOrPercentage> {
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
            return Ok(TrackBreadth::Breadth(lop))
        }

        if let Ok(f) = input.try(parse_flex) {
            return Ok(TrackBreadth::Flex(f))
        }

        TrackKeyword::parse(input).map(TrackBreadth::Keyword)
    }
}

impl HasViewportPercentage for TrackBreadth<LengthOrPercentage> {
    #[inline]
    fn has_viewport_percentage(&self) -> bool {
        if let TrackBreadth::Breadth(ref lop) = *self {
            lop.has_viewport_percentage()
        } else {
            false
        }
    }
}

impl Parse for TrackSize<LengthOrPercentage> {
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        if let Ok(b) = input.try(|i| TrackBreadth::parse(context, i)) {
            return Ok(TrackSize::Breadth(b))
        }

        if input.try(|i| i.expect_function_matching("minmax")).is_ok() {
            return input.parse_nested_block(|input| {
                let inflexible_breadth =
                    match input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
                        Ok(lop) => TrackBreadth::Breadth(lop),
                        Err(..) => {
                            let keyword = TrackKeyword::parse(input)?;
                            TrackBreadth::Keyword(keyword)
                        }
                    };

                input.expect_comma()?;
                Ok(TrackSize::Minmax(inflexible_breadth, TrackBreadth::parse(context, input)?))
            });
        }

        input.expect_function_matching("fit-content")?;
        let lop = input.parse_nested_block(|i| LengthOrPercentage::parse_non_negative(context, i))?;
        Ok(TrackSize::FitContent(lop))
    }
}

/// Parse the grid line names into a vector of owned strings.
///
/// https://drafts.csswg.org/css-grid/#typedef-line-names
pub fn parse_line_names<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Box<[CustomIdent]>, ParseError<'i>> {
    input.expect_square_bracket_block()?;
    input.parse_nested_block(|input| {
        let mut values = vec![];
        while let Ok(ident) = input.try(|i| i.expect_ident()) {
            let ident = CustomIdent::from_ident(ident, &["span"])?;
            values.push(ident);
        }

        Ok(values.into_boxed_slice())
    })
}

/// The type of `repeat` function (only used in parsing).
///
/// https://drafts.csswg.org/css-grid/#typedef-track-repeat
#[derive(Clone, Copy, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
enum RepeatType {
    /// [`<auto-repeat>`](https://drafts.csswg.org/css-grid/#typedef-auto-repeat)
    Auto,
    /// [`<track-repeat>`](https://drafts.csswg.org/css-grid/#typedef-track-repeat)
    Normal,
    /// [`<fixed-repeat>`](https://drafts.csswg.org/css-grid/#typedef-fixed-repeat)
    Fixed,
}

impl TrackRepeat<LengthOrPercentage> {
    fn parse_with_repeat_type<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
                                      -> Result<(TrackRepeat<LengthOrPercentage>, RepeatType), ParseError<'i>> {
        input.try(|i| i.expect_function_matching("repeat").map_err(|e| e.into())).and_then(|_| {
            input.parse_nested_block(|input| {
                let count = RepeatCount::parse(context, input)?;
                input.expect_comma()?;

                let is_auto = count == RepeatCount::AutoFit || count == RepeatCount::AutoFill;
                let mut repeat_type = if is_auto {
                    RepeatType::Auto
                } else {    // <fixed-size> is a subset of <track_size>, so it should work for both
                    RepeatType::Fixed
                };

                let mut names = vec![];
                let mut values = vec![];
                let mut current_names;

                loop {
                    current_names = input.try(parse_line_names).unwrap_or(vec![].into_boxed_slice());
                    if let Ok(track_size) = input.try(|i| TrackSize::parse(context, i)) {
                        if !track_size.is_fixed() {
                            if is_auto {
                                // should be <fixed-size> for <auto-repeat>
                                return Err(StyleParseError::UnspecifiedError.into())
                            }

                            if repeat_type == RepeatType::Fixed {
                                repeat_type = RepeatType::Normal       // <track-size> for sure
                            }
                        }

                        values.push(track_size);
                        names.push(current_names);
                        if is_auto {
                            // FIXME: In the older version of the spec
                            // (https://www.w3.org/TR/2015/WD-css-grid-1-20150917/#typedef-auto-repeat),
                            // if the repeat type is `<auto-repeat>` we shouldn't try to parse more than
                            // one `TrackSize`. But in current version of the spec, this is deprecated
                            // but we are adding this for gecko parity. We should remove this when
                            // gecko implements new spec.
                            names.push(input.try(parse_line_names).unwrap_or(vec![].into_boxed_slice()));
                            break
                        }
                    } else {
                        if values.is_empty() {
                            // expecting at least one <track-size>
                            return Err(StyleParseError::UnspecifiedError.into())
                        }

                        names.push(current_names);      // final `<line-names>`
                        break       // no more <track-size>, breaking
                    }
                }

                let repeat = TrackRepeat {
                    count: count,
                    track_sizes: values,
                    line_names: names.into_boxed_slice(),
                };

                Ok((repeat, repeat_type))
            })
        })
    }
}

impl HasViewportPercentage for TrackRepeat<LengthOrPercentage> {
    #[inline]
    fn has_viewport_percentage(&self) -> bool {
        self.track_sizes.iter().any(|ref v| v.has_viewport_percentage())
    }
}

impl Parse for TrackList<LengthOrPercentage> {
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        // Merge the line names while parsing values. The resulting values will
        // all be bunch of `<track-size>` and one <auto-repeat>.
        // FIXME: We need to decide which way is better for repeat function in
        // https://bugzilla.mozilla.org/show_bug.cgi?id=1382369.
        //
        // For example,
        // `[a b] 100px [c d] repeat(1, 30px [g]) [h]` will be merged as `[a b] 100px [c d] 30px [g h]`
        //  whereas, `[a b] repeat(2, [c] 50px [d]) [e f] repeat(auto-fill, [g] 12px) 10px [h]` will be merged as
        // `[a b c] 50px [d c] 50px [d e f] repeat(auto-fill, [g] 12px) 10px [h]`, with the `<auto-repeat>` value
        // set in the `auto_repeat` field, and the `idx` in TrackListType::Auto pointing to the values after
        // `<auto-repeat>` (in this case, `10px [h]`).
        let mut current_names = vec![];
        let mut names = vec![];
        let mut values = vec![];

        let mut list_type = TrackListType::Explicit;    // assume it's the simplest case
        // holds <auto-repeat> value. It can only be only one in a TrackList.
        let mut auto_repeat = None;
        // assume that everything is <fixed-size>. This flag is useful when we encounter <auto-repeat>
        let mut atleast_one_not_fixed = false;

        loop {
            current_names.extend_from_slice(&mut input.try(parse_line_names).unwrap_or(vec![].into_boxed_slice()));
            if let Ok(track_size) = input.try(|i| TrackSize::parse(context, i)) {
                if !track_size.is_fixed() {
                    atleast_one_not_fixed = true;
                    if auto_repeat.is_some() {
                        // <auto-track-list> only accepts <fixed-size> and <fixed-repeat>
                        return Err(StyleParseError::UnspecifiedError.into())
                    }
                }

                let vec = mem::replace(&mut current_names, vec![]);
                names.push(vec.into_boxed_slice());
                values.push(track_size);
            } else if let Ok((repeat, type_)) = input.try(|i| TrackRepeat::parse_with_repeat_type(context, i)) {
                if list_type == TrackListType::Explicit {
                    list_type = TrackListType::Normal;      // <explicit-track-list> doesn't contain repeat()
                }

                match type_ {
                    RepeatType::Normal => {
                        atleast_one_not_fixed = true;
                        if auto_repeat.is_some() { // only <fixed-repeat>
                            return Err(StyleParseError::UnspecifiedError.into())
                        }
                    },
                    RepeatType::Auto => {
                        if auto_repeat.is_some() || atleast_one_not_fixed {
                            // We've either seen <auto-repeat> earlier, or there's at least one non-fixed value
                            return Err(StyleParseError::UnspecifiedError.into())
                        }

                        list_type = TrackListType::Auto(values.len() as u16);
                        auto_repeat = Some(repeat);
                        let vec = mem::replace(&mut current_names, vec![]);
                        names.push(vec.into_boxed_slice());
                        continue
                    },
                    RepeatType::Fixed => (),
                }

                // If the repeat count is numeric, we axpand and merge the values.
                let mut repeat = repeat.expand();
                let mut repeat_names_iter = repeat.line_names.iter();
                for (size, repeat_names) in repeat.track_sizes.drain(..).zip(&mut repeat_names_iter) {
                    current_names.extend_from_slice(&repeat_names);
                    let vec = mem::replace(&mut current_names, vec![]);
                    names.push(vec.into_boxed_slice());
                    values.push(size);
                }

                if let Some(names) = repeat_names_iter.next() {
                    current_names.extend_from_slice(&names);
                }
            } else {
                if values.is_empty() && auto_repeat.is_none() {
                    return Err(StyleParseError::UnspecifiedError.into())
                }

                names.push(current_names.into_boxed_slice());
                break
            }
        }

        Ok(TrackList {
            list_type: list_type,
            values: values,
            line_names: names.into_boxed_slice(),
            auto_repeat: auto_repeat,
        })
    }
}

impl HasViewportPercentage for TrackList<LengthOrPercentage> {
    #[inline]
    fn has_viewport_percentage(&self) -> bool {
        self.values.iter().any(|ref v| v.has_viewport_percentage())
    }
}

impl ToComputedValue for TrackList<LengthOrPercentage> {
    type ComputedValue = TrackList<computed::LengthOrPercentage>;

    #[inline]
    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
        let mut values = Vec::with_capacity(self.values.len() + 1);
        for value in self.values.iter().map(|val| val.to_computed_value(context)) {
            values.push(value);
        }

        TrackList {
            list_type: self.list_type.to_computed_value(context),
            values: values,
            line_names: self.line_names.clone(),
            auto_repeat: self.auto_repeat.clone().map(|repeat| repeat.to_computed_value(context)),
        }
    }

    #[inline]
    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
        let mut values = Vec::with_capacity(computed.values.len() + 1);
        for value in computed.values.iter().map(ToComputedValue::from_computed_value) {
            values.push(value);
        }

        TrackList {
            list_type: computed.list_type,
            values: values,
            line_names: computed.line_names.clone(),
            auto_repeat: computed.auto_repeat.clone().map(|ref repeat| TrackRepeat::from_computed_value(repeat)),
        }
    }
}

impl Parse for GridTemplateComponent<LengthOrPercentage> {
    // FIXME: Derive Parse (probably with None_)
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        if input.try(|i| i.expect_ident_matching("none")).is_ok() {
            return Ok(GridTemplateComponent::None)
        }

        Self::parse_without_none(context, input)
    }
}

impl GridTemplateComponent<LengthOrPercentage> {
    /// Parses a `GridTemplateComponent<LengthOrPercentage>` except `none` keyword.
    pub fn parse_without_none<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
                                      -> Result<Self, ParseError<'i>> {
        if let Ok(t) = input.try(|i| TrackList::parse(context, i)) {
            return Ok(GridTemplateComponent::TrackList(t))
        }

        LineNameList::parse(context, input).map(GridTemplateComponent::Subgrid)
    }
}

impl HasViewportPercentage for GridTemplateComponent<LengthOrPercentage> {
    #[inline]
    fn has_viewport_percentage(&self) -> bool {
        match *self {
            GridTemplateComponent::TrackList(ref l) => l.has_viewport_percentage(),
            _ => false,
        }
    }
}

impl ToComputedValue for GridTemplateComponent<LengthOrPercentage> {
    type ComputedValue = GridTemplateComponent<computed::LengthOrPercentage>;

    #[inline]
    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
        match *self {
            GridTemplateComponent::None => GridTemplateComponent::None,
            GridTemplateComponent::TrackList(ref l) => GridTemplateComponent::TrackList(l.to_computed_value(context)),
            GridTemplateComponent::Subgrid(ref n) => GridTemplateComponent::Subgrid(n.to_computed_value(context)),
        }
    }

    #[inline]
    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
        match *computed {
            GridTemplateComponent::None => GridTemplateComponent::None,
            GridTemplateComponent::TrackList(ref l) =>
                GridTemplateComponent::TrackList(ToComputedValue::from_computed_value(l)),
            GridTemplateComponent::Subgrid(ref n) =>
                GridTemplateComponent::Subgrid(ToComputedValue::from_computed_value(n)),
        }
    }
}
<|endoftext|>