<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: 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));

    }
}
<commit_msg>Add flag for legend running out of alphabet<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> {
    /// The generated legend map.
    pub legend: BTreeMap<char, T>,
    /// Set to true if an add operation failed to assign a symbol.
    pub out_of_alphabet: bool,
    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(),
            out_of_alphabet: false,
            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);
        }
        self.out_of_alphabet = true;
        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>// check-pass
// compile-flags: --emit=mir
// Force mir to be emitted, to ensure that const
// propagation doesn't ICE on a function
// with an 'impossible' body. See issue #67696
// Inconsistent bounds with trait implementations

#![feature(trivial_bounds)]
#![allow(unused)]

trait A {
    fn foo(&self) -> Self where Self: Copy;
}

impl A for str {
    fn foo(&self) -> Self where Self: Copy { *"" }
}

impl A for i32 {
    fn foo(&self) -> Self { 3 }
}

fn main() {}
<commit_msg>Add "--emit=link"<commit_after>// check-pass
// compile-flags: --emit=mir,link
// Force mir to be emitted, to ensure that const
// propagation doesn't ICE on a function
// with an 'impossible' body. See issue #67696
// Inconsistent bounds with trait implementations

#![feature(trivial_bounds)]
#![allow(unused)]

trait A {
    fn foo(&self) -> Self where Self: Copy;
}

impl A for str {
    fn foo(&self) -> Self where Self: Copy { *"" }
}

impl A for i32 {
    fn foo(&self) -> Self { 3 }
}

fn main() {}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Device memory allocation and memory pools.
//!
//! By default, memory allocation is automatically handled by the vulkano library when you create
//! a buffer or an image. But if you want more control, you have the possibility to customise the
//! memory allocation strategy.
//!
//! # Memory types and heaps
//!
//! A physical device is composed of one or more **memory heaps**. A memory heap is a pool of
//! memory that can be allocated.
//!
//! ```
//! // Enumerating memory heaps.
//! # let physical_device: vulkano::device::physical::PhysicalDevice = return;
//! for heap in physical_device.memory_heaps() {
//!     println!("Heap #{:?} has a capacity of {:?} bytes", heap.id(), heap.size());
//! }
//! ```
//!
//! However you can't allocate directly from a memory heap. A memory heap is shared amongst one or
//! multiple **memory types**, which you can allocate memory from. Each memory type has different
//! characteristics.
//!
//! A memory type may or may not be visible to the host. In other words, it may or may not be
//! directly writable by the CPU. A memory type may or may not be device-local. A device-local
//! memory type has a much quicker access time from the GPU than a non-device-local type. Note
//! that non-device-local memory types are still accessible by the device, they are just slower.
//!
//! ```
//! // Enumerating memory types.
//! # let physical_device: vulkano::device::physical::PhysicalDevice = return;
//! for ty in physical_device.memory_types() {
//!     println!("Memory type belongs to heap #{:?}", ty.heap().id());
//!     println!("Host-accessible: {:?}", ty.is_host_visible());
//!     println!("Device-local: {:?}", ty.is_device_local());
//! }
//! ```
//!
//! Memory types are order from "best" to "worse". In other words, the implementation prefers that
//! you use the memory types that are earlier in the list. This means that selecting a memory type
//! should always be done by enumerating them and taking the first one that matches our criteria.
//!
//! ## In practice
//!
//! In practice, desktop machines usually have two memory heaps: one that represents the RAM of
//! the CPU, and one that represents the RAM of the GPU. The CPU's RAM is host-accessible but not
//! device-local, while the GPU's RAM is not host-accessible but is device-local.
//!
//! Mobile machines usually have a single memory heap that is "equally local" to both the CPU and
//! the GPU. It is both host-accessible and device-local.
//!
//! # Allocating memory and memory pools
//!
//! Allocating memory can be done by calling `DeviceMemory::allocate()`.
//!
//! Here is an example:
//!
//! ```
//! use vulkano::memory::{DeviceMemory, MemoryAllocateInfo};
//!
//! # let device: std::sync::Arc<vulkano::device::Device> = return;
//! // Taking the first memory type for the sake of this example.
//! let memory_type = device.physical_device().memory_types().next().unwrap();
//!
//! let memory = DeviceMemory::allocate(
//!     device.clone(),
//!     MemoryAllocateInfo {
//!         allocation_size: 1024,
//!         memory_type_index: memory_type.id(),
//!         ..Default::default()
//!     },
//! ).expect("Failed to allocate memory");
//!
//! // The memory is automatically freed when `memory` is destroyed.
//! ```
//!
//! However allocating and freeing memory is very slow (up to several hundred milliseconds
//! sometimes). Instead you are strongly encouraged to use a memory pool. A memory pool is not
//! a Vulkan concept but a vulkano concept.
//!
//! A memory pool is any object that implements the `MemoryPool` trait. You can implement that
//! trait on your own structure and then use it when you create buffers and images so that they
//! get memory from that pool. By default if you don't specify any pool when creating a buffer or
//! an image, an instance of `StdMemoryPool` that is shared by the `Device` object is used.

pub use self::{
    device_memory::{
        DeviceMemory, DeviceMemoryAllocationError, DeviceMemoryExportError,
        ExternalMemoryHandleType, ExternalMemoryHandleTypes, MappedDeviceMemory,
        MemoryAllocateInfo, MemoryImportInfo,
    },
    pool::MemoryPool,
};
use crate::{buffer::sys::UnsafeBuffer, image::sys::UnsafeImage, DeviceSize};

mod device_memory;
pub mod pool;

/// Represents requirements expressed by the Vulkan implementation when it comes to binding memory
/// to a resource.
#[derive(Debug, Copy, Clone)]
pub struct MemoryRequirements {
    /// Number of bytes of memory required.
    pub size: DeviceSize,

    /// Alignment of the requirement buffer. The base memory address must be a multiple
    /// of this value.
    pub alignment: DeviceSize,

    /// Indicates which memory types can be used. Each bit that is set to 1 means that the memory
    /// type whose index is the same as the position of the bit can be used.
    pub memory_type_bits: u32,

    /// Whether implementation prefers to use dedicated allocations (in other words, allocate
    /// a whole block of memory dedicated to this resource alone). This will be `false` if the
    /// [`khr_get_memory_requirements2`](crate::device::DeviceExtensions::khr_get_memory_requirements2)
    /// extension is not enabled on the device.
    ///
    /// > **Note**: As its name says, using a dedicated allocation is an optimization and not a
    /// > requirement.
    pub prefer_dedicated: bool,
}

impl From<ash::vk::MemoryRequirements> for MemoryRequirements {
    #[inline]
    fn from(val: ash::vk::MemoryRequirements) -> Self {
        MemoryRequirements {
            size: val.size,
            alignment: val.alignment,
            memory_type_bits: val.memory_type_bits,
            prefer_dedicated: false,
        }
    }
}

/// Indicates a specific resource to allocate memory for.
///
/// Using dedicated allocations can yield better performance, but requires the
/// [`khr_dedicated_allocation`](crate::device::DeviceExtensions::khr_dedicated_allocation)
/// extension to be enabled on the device.
///
/// If a dedicated allocation is performed, it must not be bound to any resource other than the
/// one that was passed with the enumeration.
#[derive(Debug, Copy, Clone)]
pub enum DedicatedAllocation<'a> {
    /// Allocation dedicated to a buffer.
    Buffer(&'a UnsafeBuffer),
    /// Allocation dedicated to an image.
    Image(&'a UnsafeImage),
}

/// The properties for exporting or importing external memory, when a buffer or image is created
/// with a specific configuration.
#[derive(Clone, Debug, Default)]
#[non_exhaustive]
pub struct ExternalMemoryProperties {
    /// Whether a dedicated memory allocation is required for the queried external handle type.
    pub dedicated_only: bool,

    /// Whether memory can be exported to an external source with the queried
    /// external handle type.
    pub exportable: bool,

    /// Whether memory can be imported from an external source with the queried
    /// external handle type.
    pub importable: bool,

    /// Which external handle types can be re-exported after the queried external handle type has
    /// been imported.
    pub export_from_imported_handle_types: ExternalMemoryHandleTypes,

    /// Which external handle types can be enabled along with the queried external handle type
    /// when creating the buffer or image.
    pub compatible_handle_types: ExternalMemoryHandleTypes,
}

impl From<ash::vk::ExternalMemoryProperties> for ExternalMemoryProperties {
    #[inline]
    fn from(val: ash::vk::ExternalMemoryProperties) -> Self {
        Self {
            dedicated_only: val
                .external_memory_features
                .intersects(ash::vk::ExternalMemoryFeatureFlags::DEDICATED_ONLY),
            exportable: val
                .external_memory_features
                .intersects(ash::vk::ExternalMemoryFeatureFlags::EXPORTABLE),
            importable: val
                .external_memory_features
                .intersects(ash::vk::ExternalMemoryFeatureFlags::IMPORTABLE),
            export_from_imported_handle_types: val.export_from_imported_handle_types.into(),
            compatible_handle_types: val.compatible_handle_types.into(),
        }
    }
}
<commit_msg>Export enum MemoryMapError (#1861)<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Device memory allocation and memory pools.
//!
//! By default, memory allocation is automatically handled by the vulkano library when you create
//! a buffer or an image. But if you want more control, you have the possibility to customise the
//! memory allocation strategy.
//!
//! # Memory types and heaps
//!
//! A physical device is composed of one or more **memory heaps**. A memory heap is a pool of
//! memory that can be allocated.
//!
//! ```
//! // Enumerating memory heaps.
//! # let physical_device: vulkano::device::physical::PhysicalDevice = return;
//! for heap in physical_device.memory_heaps() {
//!     println!("Heap #{:?} has a capacity of {:?} bytes", heap.id(), heap.size());
//! }
//! ```
//!
//! However you can't allocate directly from a memory heap. A memory heap is shared amongst one or
//! multiple **memory types**, which you can allocate memory from. Each memory type has different
//! characteristics.
//!
//! A memory type may or may not be visible to the host. In other words, it may or may not be
//! directly writable by the CPU. A memory type may or may not be device-local. A device-local
//! memory type has a much quicker access time from the GPU than a non-device-local type. Note
//! that non-device-local memory types are still accessible by the device, they are just slower.
//!
//! ```
//! // Enumerating memory types.
//! # let physical_device: vulkano::device::physical::PhysicalDevice = return;
//! for ty in physical_device.memory_types() {
//!     println!("Memory type belongs to heap #{:?}", ty.heap().id());
//!     println!("Host-accessible: {:?}", ty.is_host_visible());
//!     println!("Device-local: {:?}", ty.is_device_local());
//! }
//! ```
//!
//! Memory types are order from "best" to "worse". In other words, the implementation prefers that
//! you use the memory types that are earlier in the list. This means that selecting a memory type
//! should always be done by enumerating them and taking the first one that matches our criteria.
//!
//! ## In practice
//!
//! In practice, desktop machines usually have two memory heaps: one that represents the RAM of
//! the CPU, and one that represents the RAM of the GPU. The CPU's RAM is host-accessible but not
//! device-local, while the GPU's RAM is not host-accessible but is device-local.
//!
//! Mobile machines usually have a single memory heap that is "equally local" to both the CPU and
//! the GPU. It is both host-accessible and device-local.
//!
//! # Allocating memory and memory pools
//!
//! Allocating memory can be done by calling `DeviceMemory::allocate()`.
//!
//! Here is an example:
//!
//! ```
//! use vulkano::memory::{DeviceMemory, MemoryAllocateInfo};
//!
//! # let device: std::sync::Arc<vulkano::device::Device> = return;
//! // Taking the first memory type for the sake of this example.
//! let memory_type = device.physical_device().memory_types().next().unwrap();
//!
//! let memory = DeviceMemory::allocate(
//!     device.clone(),
//!     MemoryAllocateInfo {
//!         allocation_size: 1024,
//!         memory_type_index: memory_type.id(),
//!         ..Default::default()
//!     },
//! ).expect("Failed to allocate memory");
//!
//! // The memory is automatically freed when `memory` is destroyed.
//! ```
//!
//! However allocating and freeing memory is very slow (up to several hundred milliseconds
//! sometimes). Instead you are strongly encouraged to use a memory pool. A memory pool is not
//! a Vulkan concept but a vulkano concept.
//!
//! A memory pool is any object that implements the `MemoryPool` trait. You can implement that
//! trait on your own structure and then use it when you create buffers and images so that they
//! get memory from that pool. By default if you don't specify any pool when creating a buffer or
//! an image, an instance of `StdMemoryPool` that is shared by the `Device` object is used.

pub use self::{
    device_memory::{
        DeviceMemory, DeviceMemoryAllocationError, DeviceMemoryExportError,
        ExternalMemoryHandleType, ExternalMemoryHandleTypes, MappedDeviceMemory,
        MemoryAllocateInfo, MemoryImportInfo, MemoryMapError,
    },
    pool::MemoryPool,
};
use crate::{buffer::sys::UnsafeBuffer, image::sys::UnsafeImage, DeviceSize};

mod device_memory;
pub mod pool;

/// Represents requirements expressed by the Vulkan implementation when it comes to binding memory
/// to a resource.
#[derive(Debug, Copy, Clone)]
pub struct MemoryRequirements {
    /// Number of bytes of memory required.
    pub size: DeviceSize,

    /// Alignment of the requirement buffer. The base memory address must be a multiple
    /// of this value.
    pub alignment: DeviceSize,

    /// Indicates which memory types can be used. Each bit that is set to 1 means that the memory
    /// type whose index is the same as the position of the bit can be used.
    pub memory_type_bits: u32,

    /// Whether implementation prefers to use dedicated allocations (in other words, allocate
    /// a whole block of memory dedicated to this resource alone). This will be `false` if the
    /// [`khr_get_memory_requirements2`](crate::device::DeviceExtensions::khr_get_memory_requirements2)
    /// extension is not enabled on the device.
    ///
    /// > **Note**: As its name says, using a dedicated allocation is an optimization and not a
    /// > requirement.
    pub prefer_dedicated: bool,
}

impl From<ash::vk::MemoryRequirements> for MemoryRequirements {
    #[inline]
    fn from(val: ash::vk::MemoryRequirements) -> Self {
        MemoryRequirements {
            size: val.size,
            alignment: val.alignment,
            memory_type_bits: val.memory_type_bits,
            prefer_dedicated: false,
        }
    }
}

/// Indicates a specific resource to allocate memory for.
///
/// Using dedicated allocations can yield better performance, but requires the
/// [`khr_dedicated_allocation`](crate::device::DeviceExtensions::khr_dedicated_allocation)
/// extension to be enabled on the device.
///
/// If a dedicated allocation is performed, it must not be bound to any resource other than the
/// one that was passed with the enumeration.
#[derive(Debug, Copy, Clone)]
pub enum DedicatedAllocation<'a> {
    /// Allocation dedicated to a buffer.
    Buffer(&'a UnsafeBuffer),
    /// Allocation dedicated to an image.
    Image(&'a UnsafeImage),
}

/// The properties for exporting or importing external memory, when a buffer or image is created
/// with a specific configuration.
#[derive(Clone, Debug, Default)]
#[non_exhaustive]
pub struct ExternalMemoryProperties {
    /// Whether a dedicated memory allocation is required for the queried external handle type.
    pub dedicated_only: bool,

    /// Whether memory can be exported to an external source with the queried
    /// external handle type.
    pub exportable: bool,

    /// Whether memory can be imported from an external source with the queried
    /// external handle type.
    pub importable: bool,

    /// Which external handle types can be re-exported after the queried external handle type has
    /// been imported.
    pub export_from_imported_handle_types: ExternalMemoryHandleTypes,

    /// Which external handle types can be enabled along with the queried external handle type
    /// when creating the buffer or image.
    pub compatible_handle_types: ExternalMemoryHandleTypes,
}

impl From<ash::vk::ExternalMemoryProperties> for ExternalMemoryProperties {
    #[inline]
    fn from(val: ash::vk::ExternalMemoryProperties) -> Self {
        Self {
            dedicated_only: val
                .external_memory_features
                .intersects(ash::vk::ExternalMemoryFeatureFlags::DEDICATED_ONLY),
            exportable: val
                .external_memory_features
                .intersects(ash::vk::ExternalMemoryFeatureFlags::EXPORTABLE),
            importable: val
                .external_memory_features
                .intersects(ash::vk::ExternalMemoryFeatureFlags::IMPORTABLE),
            export_from_imported_handle_types: val.export_from_imported_handle_types.into(),
            compatible_handle_types: val.compatible_handle_types.into(),
        }
    }
}
<|endoftext|>


<commit_before>use futures_01::{
    task as task01, Async as Async01, AsyncSink as AsyncSink01,
    Future as Future01, Poll as Poll01, Sink as Sink01,
    StartSend as StartSend01, Stream as Stream01,
};
use futures_core::{
    task as task03, TryFuture as TryFuture03, TryStream as TryStream03,
};
use futures_sink::Sink as Sink03;
use std::{marker::Unpin, pin::Pin, ptr::NonNull, sync::Arc};

/// Converts a futures 0.3 [`TryFuture`](futures_core::future::TryFuture),
/// [`TryStream`](futures_core::stream::TryStream) or
/// [`Sink`](futures_sink::Sink) into a futures 0.1
/// [`Future`](futures::future::Future),
/// [`Stream`](futures::stream::Stream) or
/// [`Sink`](futures::sink::Sink).
#[derive(Debug)]
#[must_use = "futures do nothing unless polled"]
pub struct Compat<T> {
    pub(crate) inner: T,
}

impl<T> Compat<T> {
    /// Returns the inner item.
    pub fn into_inner(self) -> T {
        self.inner
    }

    /// Creates a new [`Compat`].
    pub(crate) fn new(inner: T) -> Compat<T> {
        Compat { inner }
    }
}

fn poll_03_to_01<T, E>(x: task03::Poll<Result<T, E>>)
    -> Result<Async01<T>, E>
{
    match x {
        task03::Poll::Ready(Ok(t)) => Ok(Async01::Ready(t)),
        task03::Poll::Pending => Ok(Async01::NotReady),
        task03::Poll::Ready(Err(e)) => Err(e),
    }
}

impl<Fut> Future01 for Compat<Fut>
where
    Fut: TryFuture03 + Unpin,
{
    type Item = Fut::Ok;
    type Error = Fut::Error;

    fn poll(&mut self) -> Poll01<Self::Item, Self::Error> {
        with_context(self, |inner, lw| poll_03_to_01(inner.try_poll(lw)))
    }
}

impl<St> Stream01 for Compat<St>
where
    St: TryStream03 + Unpin,
{
    type Item = St::Ok;
    type Error = St::Error;

    fn poll(&mut self) -> Poll01<Option<Self::Item>, Self::Error> {
        with_context(self, |inner, lw| match inner.try_poll_next(lw) {
            task03::Poll::Ready(None) => Ok(Async01::Ready(None)),
            task03::Poll::Ready(Some(Ok(t))) => Ok(Async01::Ready(Some(t))),
            task03::Poll::Pending => Ok(Async01::NotReady),
            task03::Poll::Ready(Some(Err(e))) => Err(e),
        })
    }
}

impl<T> Sink01 for Compat<T>
where
    T: Sink03 + Unpin,
{
    type SinkItem = T::SinkItem;
    type SinkError = T::SinkError;

    fn start_send(
        &mut self,
        item: Self::SinkItem,
    ) -> StartSend01<Self::SinkItem, Self::SinkError> {
        with_context(self, |mut inner, lw| {
            match inner.as_mut().poll_ready(lw) {
                task03::Poll::Ready(Ok(())) => {
                    inner.start_send(item).map(|()| AsyncSink01::Ready)
                }
                task03::Poll::Pending => Ok(AsyncSink01::NotReady(item)),
                task03::Poll::Ready(Err(e)) => Err(e),
            }
        })
    }

    fn poll_complete(&mut self) -> Poll01<(), Self::SinkError> {
        with_context(self, |inner, lw| poll_03_to_01(inner.poll_flush(lw)))
    }

    fn close(&mut self) -> Poll01<(), Self::SinkError> {
        with_context(self, |inner, lw| poll_03_to_01(inner.poll_close(lw)))
    }
}

fn current_ref_as_waker() -> task03::LocalWaker {
    unsafe {
        task03::LocalWaker::new(NonNull::<CurrentRef>::dangling())
    }
}

struct CurrentRef;

struct CurrentOwned(task01::Task);

unsafe impl task03::UnsafeWake for CurrentRef {
    #[inline]
    unsafe fn clone_raw(&self) -> task03::Waker {
        task03::Waker::from(Arc::new(CurrentOwned(task01::current())))
    }

    #[inline]
    unsafe fn drop_raw(&self) {} // Does nothing

    #[inline]
    unsafe fn wake(&self) {
        task01::current().notify();
    }
}

impl task03::Wake for CurrentOwned {
    fn wake(arc_self: &Arc<Self>) {
        arc_self.0.notify();
    }
}

fn with_context<T, R, F>(compat: &mut Compat<T>, f: F) -> R
where
    T: Unpin,
    F: FnOnce(Pin<&mut T>, &task03::LocalWaker) -> R,
{
    let lw = current_ref_as_waker();
    f(Pin::new(&mut compat.inner), &lw)
}

#[cfg(feature = "io-compat")]
mod io {
    use super::*;
    use futures_io::{AsyncRead as AsyncRead03, AsyncWrite as AsyncWrite03};
    use tokio_io::{AsyncRead as AsyncRead01, AsyncWrite as AsyncWrite01};

    fn poll_03_to_io<T>(x: task03::Poll<Result<T, std::io::Error>>)
        -> Result<T, std::io::Error>
    {
        match x {
            task03::Poll::Ready(Ok(t)) => Ok(t),
            task03::Poll::Pending => Err(std::io::ErrorKind::WouldBlock.into()),
            task03::Poll::Ready(Err(e)) => Err(e),
        }
    }

    impl<R: AsyncRead03> std::io::Read for Compat<R> {
        fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
            let lw = current_ref_as_waker();
            poll_03_to_io(self.inner.poll_read(&lw, buf))
        }
    }

    impl<R: AsyncRead03> AsyncRead01 for Compat<R> {
        unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
            let initializer = self.inner.initializer();
            let does_init = initializer.should_initialize();
            if does_init {
                initializer.initialize(buf);
            }
            does_init
        }
    }

    impl<W: AsyncWrite03> std::io::Write for Compat<W> {
        fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
            let lw = current_ref_as_waker();
            poll_03_to_io(self.inner.poll_write(&lw, buf))
        }

        fn flush(&mut self) -> std::io::Result<()> {
            let lw = current_ref_as_waker();
            poll_03_to_io(self.inner.poll_flush(&lw))
        }
    }

    impl<W: AsyncWrite03> AsyncWrite01 for Compat<W> {
        fn shutdown(&mut self) -> std::io::Result<Async01<()>> {
            let lw = current_ref_as_waker();
            poll_03_to_01(self.inner.poll_close(&lw))
        }
    }
}
<commit_msg>Fix a stack overflow in the compat layers<commit_after>use futures_01::{
    task as task01, Async as Async01, AsyncSink as AsyncSink01,
    Future as Future01, Poll as Poll01, Sink as Sink01,
    StartSend as StartSend01, Stream as Stream01,
};
use futures_core::{
    task as task03, TryFuture as TryFuture03, TryStream as TryStream03,
};
use futures_sink::Sink as Sink03;
use std::{marker::Unpin, pin::Pin, ptr::NonNull, sync::Arc};

/// Converts a futures 0.3 [`TryFuture`](futures_core::future::TryFuture),
/// [`TryStream`](futures_core::stream::TryStream) or
/// [`Sink`](futures_sink::Sink) into a futures 0.1
/// [`Future`](futures::future::Future),
/// [`Stream`](futures::stream::Stream) or
/// [`Sink`](futures::sink::Sink).
#[derive(Debug)]
#[must_use = "futures do nothing unless polled"]
pub struct Compat<T> {
    pub(crate) inner: T,
}

impl<T> Compat<T> {
    /// Returns the inner item.
    pub fn into_inner(self) -> T {
        self.inner
    }

    /// Creates a new [`Compat`].
    pub(crate) fn new(inner: T) -> Compat<T> {
        Compat { inner }
    }
}

fn poll_03_to_01<T, E>(x: task03::Poll<Result<T, E>>)
    -> Result<Async01<T>, E>
{
    match x {
        task03::Poll::Ready(Ok(t)) => Ok(Async01::Ready(t)),
        task03::Poll::Pending => Ok(Async01::NotReady),
        task03::Poll::Ready(Err(e)) => Err(e),
    }
}

impl<Fut> Future01 for Compat<Fut>
where
    Fut: TryFuture03 + Unpin,
{
    type Item = Fut::Ok;
    type Error = Fut::Error;

    fn poll(&mut self) -> Poll01<Self::Item, Self::Error> {
        with_context(self, |inner, lw| poll_03_to_01(inner.try_poll(lw)))
    }
}

impl<St> Stream01 for Compat<St>
where
    St: TryStream03 + Unpin,
{
    type Item = St::Ok;
    type Error = St::Error;

    fn poll(&mut self) -> Poll01<Option<Self::Item>, Self::Error> {
        with_context(self, |inner, lw| match inner.try_poll_next(lw) {
            task03::Poll::Ready(None) => Ok(Async01::Ready(None)),
            task03::Poll::Ready(Some(Ok(t))) => Ok(Async01::Ready(Some(t))),
            task03::Poll::Pending => Ok(Async01::NotReady),
            task03::Poll::Ready(Some(Err(e))) => Err(e),
        })
    }
}

impl<T> Sink01 for Compat<T>
where
    T: Sink03 + Unpin,
{
    type SinkItem = T::SinkItem;
    type SinkError = T::SinkError;

    fn start_send(
        &mut self,
        item: Self::SinkItem,
    ) -> StartSend01<Self::SinkItem, Self::SinkError> {
        with_context(self, |mut inner, lw| {
            match inner.as_mut().poll_ready(lw) {
                task03::Poll::Ready(Ok(())) => {
                    inner.start_send(item).map(|()| AsyncSink01::Ready)
                }
                task03::Poll::Pending => Ok(AsyncSink01::NotReady(item)),
                task03::Poll::Ready(Err(e)) => Err(e),
            }
        })
    }

    fn poll_complete(&mut self) -> Poll01<(), Self::SinkError> {
        with_context(self, |inner, lw| poll_03_to_01(inner.poll_flush(lw)))
    }

    fn close(&mut self) -> Poll01<(), Self::SinkError> {
        with_context(self, |inner, lw| poll_03_to_01(inner.poll_close(lw)))
    }
}

struct Current(task01::Task);

impl Current {
    fn new() -> Current {
        Current(task01::current())
    }

    fn as_waker(&self) -> task03::LocalWaker {
        unsafe {
            task03::LocalWaker::new(NonNull::new_unchecked(self as *const Current as *mut Current))
        }
    }
}

unsafe impl task03::UnsafeWake for Current {
    #[inline]
    unsafe fn clone_raw(&self) -> task03::Waker {
        task03::Waker::from(Arc::new(Current(self.0.clone())))
    }

    #[inline]
    unsafe fn drop_raw(&self) {} // Does nothing

    #[inline]
    unsafe fn wake(&self) {
        self.0.notify();
    }
}

impl task03::Wake for Current {
    fn wake(arc_self: &Arc<Self>) {
        arc_self.0.notify();
    }
}

fn with_context<T, R, F>(compat: &mut Compat<T>, f: F) -> R
where
    T: Unpin,
    F: FnOnce(Pin<&mut T>, &task03::LocalWaker) -> R,
{
    let current = Current::new();
    let lw = current.as_waker();
    f(Pin::new(&mut compat.inner), &lw)
}

#[cfg(feature = "io-compat")]
mod io {
    use super::*;
    use futures_io::{AsyncRead as AsyncRead03, AsyncWrite as AsyncWrite03};
    use tokio_io::{AsyncRead as AsyncRead01, AsyncWrite as AsyncWrite01};

    fn poll_03_to_io<T>(x: task03::Poll<Result<T, std::io::Error>>)
        -> Result<T, std::io::Error>
    {
        match x {
            task03::Poll::Ready(Ok(t)) => Ok(t),
            task03::Poll::Pending => Err(std::io::ErrorKind::WouldBlock.into()),
            task03::Poll::Ready(Err(e)) => Err(e),
        }
    }

    impl<R: AsyncRead03> std::io::Read for Compat<R> {
        fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
            let current = Current::new();
            let lw = current.as_waker();
            poll_03_to_io(self.inner.poll_read(&lw, buf))
        }
    }

    impl<R: AsyncRead03> AsyncRead01 for Compat<R> {
        unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
            let initializer = self.inner.initializer();
            let does_init = initializer.should_initialize();
            if does_init {
                initializer.initialize(buf);
            }
            does_init
        }
    }

    impl<W: AsyncWrite03> std::io::Write for Compat<W> {
        fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
            let current = Current::new();
            let lw = current.as_waker();
            poll_03_to_io(self.inner.poll_write(&lw, buf))
        }

        fn flush(&mut self) -> std::io::Result<()> {
            let current = Current::new();
            let lw = current.as_waker();
            poll_03_to_io(self.inner.poll_flush(&lw))
        }
    }

    impl<W: AsyncWrite03> AsyncWrite01 for Compat<W> {
        fn shutdown(&mut self) -> std::io::Result<Async01<()>> {
            let current = Current::new();
            let lw = current.as_waker();
            poll_03_to_01(self.inner.poll_close(&lw))
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    keys::{ConsensusKeyPair, NetworkKeyPairs},
    seed_peers::SeedPeersConfigHelpers,
    trusted_peers::{ConfigHelpers, ConsensusPrivateKey, NetworkPrivateKeys},
    utils::get_available_port,
};
use failure::prelude::*;
use libra_tools::tempdir::TempPath;
use libra_types::{
    transaction::{SignedTransaction, Transaction},
    PeerId,
};
use prost::Message;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use std::{
    convert::TryFrom,
    fs::File,
    io::{Read, Write},
    path::{Path, PathBuf},
    str::FromStr,
    string::ToString,
};
use toml;

mod admission_control_config;
pub use admission_control_config::*;
mod consensus_config;
pub use consensus_config::*;
mod debug_interface_config;
pub use debug_interface_config::*;
mod execution_config;
pub use execution_config::*;
mod logger_config;
pub use logger_config::*;
mod metrics_config;
pub use metrics_config::*;
mod mempool_config;
pub use mempool_config::*;
mod network_config;
pub use network_config::*;
mod state_sync_config;
pub use state_sync_config::*;
mod storage_config;
pub use storage_config::*;
mod safety_rules_config;
pub use safety_rules_config::*;
mod vm_config;
pub use vm_config::*;

#[cfg(test)]
#[path = "unit_tests/config_test.rs"]
mod config_test;

// path is relative to this file location
static CONFIG_TEMPLATE: &[u8] = include_bytes!("../data/configs/node.config.toml");

/// Config pulls in configuration information from the config file.
/// This is used to set up the nodes and configure various parameters.
/// The config file is broken up into sections for each module
/// so that only that module can be passed around
#[cfg_attr(any(test, feature = "fuzzing"), derive(Clone))]
#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct NodeConfig {
    //TODO Add configuration for multiple chain's in a future diff
    #[serde(default)]
    pub base: BaseConfig,
    #[serde(default)]
    pub metrics: MetricsConfig,
    #[serde(default)]
    pub execution: ExecutionConfig,
    #[serde(default)]
    pub admission_control: AdmissionControlConfig,
    #[serde(default)]
    pub debug_interface: DebugInterfaceConfig,

    #[serde(default)]
    pub storage: StorageConfig,
    #[serde(default)]
    pub networks: Vec<NetworkConfig>,
    #[serde(default)]
    pub consensus: ConsensusConfig,
    #[serde(default)]
    pub mempool: MempoolConfig,
    #[serde(default)]
    pub state_sync: StateSyncConfig,
    #[serde(default)]
    pub logger: LoggerConfig,
    #[serde(default)]
    pub vm_config: VMConfig,
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(default)]
pub struct BaseConfig {
    pub data_dir_path: PathBuf,
    #[serde(skip)]
    temp_data_dir: Option<TempPath>,
}

impl Default for BaseConfig {
    fn default() -> BaseConfig {
        BaseConfig {
            data_dir_path: PathBuf::from("."),
            temp_data_dir: None,
        }
    }
}

impl BaseConfig {
    /// Constructs a new BaseConfig with an empty temp directory
    pub fn new(data_dir_path: PathBuf) -> Self {
        BaseConfig {
            data_dir_path,
            temp_data_dir: None,
        }
    }
}

#[cfg(any(test, feature = "fuzzing"))]
impl Clone for BaseConfig {
    fn clone(&self) -> Self {
        Self {
            data_dir_path: self.data_dir_path.clone(),
            temp_data_dir: None,
        }
    }
}

impl NodeConfig {
    /// Reads the config file and returns the configuration object in addition to doing some
    /// post-processing of the config
    /// Paths used in the config are either absolute or relative to the config location
    pub fn load<P: AsRef<Path>>(path: P) -> Result<Self> {
        let mut config = Self::load_config(&path);
        let mut validator_count = 0;
        for network in &mut config.networks {
            // We use provided peer id for validator role. Otherwise peer id is generated using
            // network identity key.
            if network.role == RoleType::Validator {
                assert_eq!(
                    validator_count, 0,
                    "At most 1 network config should be for a validator"
                );
                network.load(path.as_ref())?;
                validator_count += 1;
            } else {
                network.load(path.as_ref())?;
            }
        }
        config.consensus.load(path.as_ref())?;
        Ok(config)
    }

    /// Returns true if the node config is for a validator. Otherwise returns false.
    pub fn is_validator(&self) -> bool {
        self.networks
            .iter()
            .any(|network| RoleType::Validator == network.role)
    }

    /// Returns true if the node config is for a validator. Otherwise returns false.
    pub fn get_role(&self) -> RoleType {
        if self.is_validator() {
            RoleType::Validator
        } else {
            RoleType::FullNode
        }
    }

    /// Returns the validator network config for this node.
    pub fn get_validator_network_config(&self) -> Option<&NetworkConfig> {
        self.networks
            .iter()
            .filter(|network| RoleType::Validator == network.role)
            .last()
    }

    pub fn get_genesis_transaction_file(&self) -> PathBuf {
        let path = &self.execution.genesis_file_location;
        if path.is_relative() {
            self.base.data_dir_path.join(path)
        } else {
            path.clone()
        }
    }

    pub fn get_genesis_transaction(&self) -> Result<Transaction> {
        let file_path = self.get_genesis_transaction_file();
        let mut file: File = File::open(&file_path).unwrap_or_else(|err| {
            panic!(
                "Failed to open file: {:?}; error: {:?}",
                file_path.clone(),
                err
            );
        });
        let mut buffer = vec![];
        file.read_to_end(&mut buffer)?;
        // TODO: update to use `Transaction::WriteSet` variant when ready.
        Ok(Transaction::UserTransaction(SignedTransaction::try_from(
            libra_types::proto::types::SignedTransaction::decode(&buffer)?,
        )?))
    }

    pub fn get_storage_dir(&self) -> PathBuf {
        let path = self.storage.dir.clone();
        if path.is_relative() {
            self.base.data_dir_path.join(path)
        } else {
            path
        }
    }

    pub fn get_metrics_dir(&self) -> Option<PathBuf> {
        let path = self.metrics.dir.as_path();
        if path.as_os_str().is_empty() {
            None
        } else if path.is_relative() {
            Some(self.base.data_dir_path.join(path))
        } else {
            Some(path.to_owned())
        }
    }

    /// Returns true if network_config is for an upstream network
    pub fn is_upstream_network(&self, network_config: &NetworkConfig) -> bool {
        self.state_sync
            .upstream_peers
            .upstream_peers
            .iter()
            .any(|peer_id| network_config.network_peers.peers.contains_key(peer_id))
    }

    pub fn get_upstream_peer_ids(&self) -> Vec<PeerId> {
        self.state_sync
            .upstream_peers
            .upstream_peers
            .iter()
            .map(|peer_id_str| {
                (PeerId::from_str(peer_id_str).unwrap_or_else(|_| {
                    unreachable!("Failed to parse peer_id from string: {}", peer_id_str)
                }))
            })
            .collect()
    }
}

pub struct NodeConfigHelpers {}

impl NodeConfigHelpers {
    /// Returns a simple test config for single node. It does not have correct network_peers_file,
    /// consensus_peers_file, network_keypairs_file, consensus_keypair_file, and seed_peers_file
    /// set. It is expected that the callee will provide these.
    pub fn get_single_node_test_config(random_ports: bool) -> NodeConfig {
        let config_string = String::from_utf8_lossy(CONFIG_TEMPLATE);
        let mut config =
            NodeConfig::parse(&config_string).expect("Error parsing single node test config");
        // Create temporary directory for persisting configs.
        let dir = TempPath::new();
        dir.create_as_dir().expect("error creating tempdir");
        config.base.data_dir_path = dir.path().to_owned();
        config.base.temp_data_dir = Some(dir);
        if random_ports {
            NodeConfigHelpers::randomize_config_ports(&mut config);
        }
        let (mut private_keys, test_consensus_peers, test_network_peers) =
            ConfigHelpers::gen_validator_nodes(1, None);
        let peer_id = *private_keys.keys().nth(0).unwrap();
        let (
            ConsensusPrivateKey {
                consensus_private_key,
            },
            NetworkPrivateKeys {
                network_signing_private_key,
                network_identity_private_key,
            },
        ) = private_keys.remove_entry(&peer_id).unwrap().1;
        config.consensus.consensus_keypair = ConsensusKeyPair::load(Some(consensus_private_key));
        config.consensus.consensus_peers = test_consensus_peers;
        // Setup node's peer id.
        let mut network = config.networks.get_mut(0).unwrap();
        network.peer_id = peer_id.to_string();
        network.network_keypairs =
            NetworkKeyPairs::load(network_signing_private_key, network_identity_private_key);
        let seed_peers_config = SeedPeersConfigHelpers::get_test_config(&test_network_peers, None);
        network.listen_address = seed_peers_config
            .seed_peers
            .get(&peer_id.to_string())
            .unwrap()
            .get(0)
            .unwrap()
            .clone();
        network.advertised_address = network.listen_address.clone();
        network.seed_peers = seed_peers_config;
        network.network_peers = test_network_peers;
        config
    }

    pub fn randomize_config_ports(config: &mut NodeConfig) {
        config.admission_control.admission_control_service_port = get_available_port();
        config.debug_interface.admission_control_node_debug_port = get_available_port();
        config.debug_interface.metrics_server_port = get_available_port();
        config.debug_interface.public_metrics_server_port = get_available_port();
        config.debug_interface.storage_node_debug_port = get_available_port();
        config.execution.port = get_available_port();
        config.mempool.mempool_service_port = get_available_port();
        config.storage.port = get_available_port();
    }
}

pub trait PersistableConfig: Serialize + DeserializeOwned {
    // TODO: Return Result<Self> instead of panic.
    fn load_config<P: AsRef<Path>>(path: P) -> Self {
        let path = path.as_ref();
        let mut file =
            File::open(path).unwrap_or_else(|_| panic!("Cannot open config file {:?}", path));
        let mut contents = String::new();
        file.read_to_string(&mut contents)
            .unwrap_or_else(|_| panic!("Error reading config file {:?}", path));
        Self::parse(&contents).expect("Unable to parse config")
    }

    fn save_config<P: AsRef<Path>>(&self, output_file: P) {
        let contents = toml::to_vec(&self).expect("Error serializing");
        let mut file = File::create(output_file).expect("Error opening file");
        file.write_all(&contents).expect("Error writing file");
    }

    fn parse(serialized: &str) -> Result<Self> {
        Ok(toml::from_str(&serialized)?)
    }
}

impl<T: ?Sized> PersistableConfig for T where T: Serialize + DeserializeOwned {}
<commit_msg>[config] reorder configs by alphabetical name<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    keys::{ConsensusKeyPair, NetworkKeyPairs},
    seed_peers::SeedPeersConfigHelpers,
    trusted_peers::{ConfigHelpers, ConsensusPrivateKey, NetworkPrivateKeys},
    utils::get_available_port,
};
use failure::prelude::*;
use libra_tools::tempdir::TempPath;
use libra_types::{
    transaction::{SignedTransaction, Transaction},
    PeerId,
};
use prost::Message;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use std::{
    convert::TryFrom,
    fs::File,
    io::{Read, Write},
    path::{Path, PathBuf},
    str::FromStr,
    string::ToString,
};
use toml;

mod admission_control_config;
pub use admission_control_config::*;
mod consensus_config;
pub use consensus_config::*;
mod debug_interface_config;
pub use debug_interface_config::*;
mod execution_config;
pub use execution_config::*;
mod logger_config;
pub use logger_config::*;
mod metrics_config;
pub use metrics_config::*;
mod mempool_config;
pub use mempool_config::*;
mod network_config;
pub use network_config::*;
mod state_sync_config;
pub use state_sync_config::*;
mod storage_config;
pub use storage_config::*;
mod safety_rules_config;
pub use safety_rules_config::*;
mod vm_config;
pub use vm_config::*;

#[cfg(test)]
#[path = "unit_tests/config_test.rs"]
mod config_test;

// path is relative to this file location
static CONFIG_TEMPLATE: &[u8] = include_bytes!("../data/configs/node.config.toml");

/// Config pulls in configuration information from the config file.
/// This is used to set up the nodes and configure various parameters.
/// The config file is broken up into sections for each module
/// so that only that module can be passed around
#[cfg_attr(any(test, feature = "fuzzing"), derive(Clone))]
#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct NodeConfig {
    #[serde(default)]
    pub admission_control: AdmissionControlConfig,
    #[serde(default)]
    pub base: BaseConfig,
    #[serde(default)]
    pub consensus: ConsensusConfig,
    #[serde(default)]
    pub debug_interface: DebugInterfaceConfig,
    #[serde(default)]
    pub execution: ExecutionConfig,
    #[serde(default)]
    pub logger: LoggerConfig,
    #[serde(default)]
    pub metrics: MetricsConfig,
    #[serde(default)]
    pub mempool: MempoolConfig,
    #[serde(default)]
    pub networks: Vec<NetworkConfig>,
    #[serde(default)]
    pub state_sync: StateSyncConfig,
    #[serde(default)]
    pub storage: StorageConfig,
    #[serde(default)]
    pub vm_config: VMConfig,
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(default)]
pub struct BaseConfig {
    pub data_dir_path: PathBuf,
    #[serde(skip)]
    temp_data_dir: Option<TempPath>,
}

impl Default for BaseConfig {
    fn default() -> BaseConfig {
        BaseConfig {
            data_dir_path: PathBuf::from("."),
            temp_data_dir: None,
        }
    }
}

impl BaseConfig {
    /// Constructs a new BaseConfig with an empty temp directory
    pub fn new(data_dir_path: PathBuf) -> Self {
        BaseConfig {
            data_dir_path,
            temp_data_dir: None,
        }
    }
}

#[cfg(any(test, feature = "fuzzing"))]
impl Clone for BaseConfig {
    fn clone(&self) -> Self {
        Self {
            data_dir_path: self.data_dir_path.clone(),
            temp_data_dir: None,
        }
    }
}

impl NodeConfig {
    /// Reads the config file and returns the configuration object in addition to doing some
    /// post-processing of the config
    /// Paths used in the config are either absolute or relative to the config location
    pub fn load<P: AsRef<Path>>(path: P) -> Result<Self> {
        let mut config = Self::load_config(&path);
        let mut validator_count = 0;
        for network in &mut config.networks {
            // We use provided peer id for validator role. Otherwise peer id is generated using
            // network identity key.
            if network.role == RoleType::Validator {
                assert_eq!(
                    validator_count, 0,
                    "At most 1 network config should be for a validator"
                );
                network.load(path.as_ref())?;
                validator_count += 1;
            } else {
                network.load(path.as_ref())?;
            }
        }
        config.consensus.load(path.as_ref())?;
        Ok(config)
    }

    /// Returns true if the node config is for a validator. Otherwise returns false.
    pub fn is_validator(&self) -> bool {
        self.networks
            .iter()
            .any(|network| RoleType::Validator == network.role)
    }

    /// Returns true if the node config is for a validator. Otherwise returns false.
    pub fn get_role(&self) -> RoleType {
        if self.is_validator() {
            RoleType::Validator
        } else {
            RoleType::FullNode
        }
    }

    /// Returns the validator network config for this node.
    pub fn get_validator_network_config(&self) -> Option<&NetworkConfig> {
        self.networks
            .iter()
            .filter(|network| RoleType::Validator == network.role)
            .last()
    }

    pub fn get_genesis_transaction_file(&self) -> PathBuf {
        let path = &self.execution.genesis_file_location;
        if path.is_relative() {
            self.base.data_dir_path.join(path)
        } else {
            path.clone()
        }
    }

    pub fn get_genesis_transaction(&self) -> Result<Transaction> {
        let file_path = self.get_genesis_transaction_file();
        let mut file: File = File::open(&file_path).unwrap_or_else(|err| {
            panic!(
                "Failed to open file: {:?}; error: {:?}",
                file_path.clone(),
                err
            );
        });
        let mut buffer = vec![];
        file.read_to_end(&mut buffer)?;
        // TODO: update to use `Transaction::WriteSet` variant when ready.
        Ok(Transaction::UserTransaction(SignedTransaction::try_from(
            libra_types::proto::types::SignedTransaction::decode(&buffer)?,
        )?))
    }

    pub fn get_storage_dir(&self) -> PathBuf {
        let path = self.storage.dir.clone();
        if path.is_relative() {
            self.base.data_dir_path.join(path)
        } else {
            path
        }
    }

    pub fn get_metrics_dir(&self) -> Option<PathBuf> {
        let path = self.metrics.dir.as_path();
        if path.as_os_str().is_empty() {
            None
        } else if path.is_relative() {
            Some(self.base.data_dir_path.join(path))
        } else {
            Some(path.to_owned())
        }
    }

    /// Returns true if network_config is for an upstream network
    pub fn is_upstream_network(&self, network_config: &NetworkConfig) -> bool {
        self.state_sync
            .upstream_peers
            .upstream_peers
            .iter()
            .any(|peer_id| network_config.network_peers.peers.contains_key(peer_id))
    }

    pub fn get_upstream_peer_ids(&self) -> Vec<PeerId> {
        self.state_sync
            .upstream_peers
            .upstream_peers
            .iter()
            .map(|peer_id_str| {
                (PeerId::from_str(peer_id_str).unwrap_or_else(|_| {
                    unreachable!("Failed to parse peer_id from string: {}", peer_id_str)
                }))
            })
            .collect()
    }
}

pub struct NodeConfigHelpers {}

impl NodeConfigHelpers {
    /// Returns a simple test config for single node. It does not have correct network_peers_file,
    /// consensus_peers_file, network_keypairs_file, consensus_keypair_file, and seed_peers_file
    /// set. It is expected that the callee will provide these.
    pub fn get_single_node_test_config(random_ports: bool) -> NodeConfig {
        let config_string = String::from_utf8_lossy(CONFIG_TEMPLATE);
        let mut config =
            NodeConfig::parse(&config_string).expect("Error parsing single node test config");
        // Create temporary directory for persisting configs.
        let dir = TempPath::new();
        dir.create_as_dir().expect("error creating tempdir");
        config.base.data_dir_path = dir.path().to_owned();
        config.base.temp_data_dir = Some(dir);
        if random_ports {
            NodeConfigHelpers::randomize_config_ports(&mut config);
        }
        let (mut private_keys, test_consensus_peers, test_network_peers) =
            ConfigHelpers::gen_validator_nodes(1, None);
        let peer_id = *private_keys.keys().nth(0).unwrap();
        let (
            ConsensusPrivateKey {
                consensus_private_key,
            },
            NetworkPrivateKeys {
                network_signing_private_key,
                network_identity_private_key,
            },
        ) = private_keys.remove_entry(&peer_id).unwrap().1;
        config.consensus.consensus_keypair = ConsensusKeyPair::load(Some(consensus_private_key));
        config.consensus.consensus_peers = test_consensus_peers;
        // Setup node's peer id.
        let mut network = config.networks.get_mut(0).unwrap();
        network.peer_id = peer_id.to_string();
        network.network_keypairs =
            NetworkKeyPairs::load(network_signing_private_key, network_identity_private_key);
        let seed_peers_config = SeedPeersConfigHelpers::get_test_config(&test_network_peers, None);
        network.listen_address = seed_peers_config
            .seed_peers
            .get(&peer_id.to_string())
            .unwrap()
            .get(0)
            .unwrap()
            .clone();
        network.advertised_address = network.listen_address.clone();
        network.seed_peers = seed_peers_config;
        network.network_peers = test_network_peers;
        config
    }

    pub fn randomize_config_ports(config: &mut NodeConfig) {
        config.admission_control.admission_control_service_port = get_available_port();
        config.debug_interface.admission_control_node_debug_port = get_available_port();
        config.debug_interface.metrics_server_port = get_available_port();
        config.debug_interface.public_metrics_server_port = get_available_port();
        config.debug_interface.storage_node_debug_port = get_available_port();
        config.execution.port = get_available_port();
        config.mempool.mempool_service_port = get_available_port();
        config.storage.port = get_available_port();
    }
}

pub trait PersistableConfig: Serialize + DeserializeOwned {
    // TODO: Return Result<Self> instead of panic.
    fn load_config<P: AsRef<Path>>(path: P) -> Self {
        let path = path.as_ref();
        let mut file =
            File::open(path).unwrap_or_else(|_| panic!("Cannot open config file {:?}", path));
        let mut contents = String::new();
        file.read_to_string(&mut contents)
            .unwrap_or_else(|_| panic!("Error reading config file {:?}", path));
        Self::parse(&contents).expect("Unable to parse config")
    }

    fn save_config<P: AsRef<Path>>(&self, output_file: P) {
        let contents = toml::to_vec(&self).expect("Error serializing");
        let mut file = File::create(output_file).expect("Error opening file");
        file.write_all(&contents).expect("Error writing file");
    }

    fn parse(serialized: &str) -> Result<Self> {
        Ok(toml::from_str(&serialized)?)
    }
}

impl<T: ?Sized> PersistableConfig for T where T: Serialize + DeserializeOwned {}
<|endoftext|>