<commit_before>use super::config::{Config, Capture};
use std::collections::BTreeMap;
use std::io::{BufRead, Write};

#[derive(Debug, Clone, Copy)]
pub enum OutputFormat {
    LittleEndian,
    BigEndian,
    HexList,
}

struct Replacement {
    // Line for purposes of printing errors.
    line: usize,
    // Left shift amount
    shift: i32,
    // Segment to add the value to.
    add_segment: usize,
    // The index in the add_segment to add the value.
    index: usize,
    // The tag to retrieve the position to add.
    tag: String,
    // The segment for which we are retrieving the position from the tag.
    pos_segment: usize,
    // The offset we add after retrieving the value from the tag.
    pos_offset: isize,
}

pub struct Parser<'a> {
    config: &'a Config,
    segments: Vec<Vec<u64>>,
    tags: BTreeMap<String, Vec<usize>>,
    plus_tags: Vec<(usize, Vec<usize>)>,
    minus_tags: Vec<(usize, Vec<usize>)>,
    replacements: Vec<Replacement>,
}

fn shift_left_or_right(a: u64, shift: i32) -> u64 {
    if shift < 0 {
        a >> (-shift)
    } else {
        a << shift
    }
}

impl<'a> Parser<'a> {
    pub fn new(config: &'a Config) -> Self {
        Parser {
            config: config,
            segments: {
                let mut v = Vec::new();
                for _ in 0..config.segment_widths.len() {
                    v.push(Vec::new());
                }
                v
            },
            tags: BTreeMap::new(),
            plus_tags: Vec::new(),
            minus_tags: Vec::new(),
            replacements: Vec::new(),
        }
    }

    pub fn link(&mut self) {
        // Iterate through every replacement.
        'outer: for r in &self.replacements {
            if r.tag.chars().all(|c| c == '+') {
                for e in &self.plus_tags {
                    // Ensure they have the same amount of pluses and that the relevant segment is at least as high.
                    if e.0 == r.tag.len() && e.1[r.add_segment] >= r.index {
                        self.segments[r.add_segment][r.index] +=
                            shift_left_or_right((e.1[r.pos_segment] as isize + r.pos_offset) as u64, r.shift);

                        break 'outer;
                    }
                }
                panic!("Error: Forward + tag used on line {} was never defined.",
                       r.line);
            } else if r.tag.chars().all(|c| c == '-') {
                for e in self.minus_tags.iter().rev() {
                    // Ensure they have the same amount of minuses and that the relevant segment is at least as low.
                    if e.0 == r.tag.len() && e.1[r.add_segment] < r.index {
                        self.segments[r.add_segment][r.index] +=
                            shift_left_or_right((e.1[r.pos_segment] as isize + r.pos_offset) as u64, r.shift);

                        break 'outer;
                    }
                }
                panic!("Error: Forward + tag used on line {} was never defined.",
                       r.line);
            } else {
                // Get the tag offset vector corresponding to the replacement.
                let tag = self.tags.get(&r.tag).unwrap_or_else(|| {
                    panic!("Error: Tag \"{}\" used on line {} never defined.",
                           r.tag,
                           r.line);
                });
                self.segments[r.add_segment][r.index] +=
                    shift_left_or_right((tag[r.pos_segment] as isize + r.pos_offset) as u64,
                                        r.shift);
            }
        }
    }

    pub fn parse<B>(&mut self, bufread: B)
        where B: BufRead
    {
        for (index, line) in bufread.lines().enumerate() {
            let line = line.unwrap_or_else(|e| panic!("Error: Failed to read from buffer: {}", e));

            // Remove everything after the first #, which denotes a comment.
            let line = line.splitn(2, '#').next().unwrap();

            if self.config.split_whitespace {
                for word in line.split_whitespace() {
                    self.parse_segment(word, index + 1);
                }
            } else {
                self.parse_segment(line, index + 1);
            }
        }
    }

    pub fn output<W>(&self, format: OutputFormat, segment: usize, w: &mut W)
        where W: Write
    {
        use byteorder::{ByteOrder, LittleEndian, BigEndian};
        match format {
            OutputFormat::LittleEndian => {
                // Allocate enough bytes to store a u64
                let mut bytes = [0; 8];
                let width = self.config.segment_widths[segment];
                for val in &self.segments[segment] {
                    LittleEndian::write_u64(&mut bytes, *val);
                    w.write_all(&bytes[0..width]).unwrap_or_else(|e| {
                        panic!("Error: Writing to output file for segment {} failed: {}",
                               segment,
                               e);
                    });
                }
            }
            OutputFormat::BigEndian => {
                // Allocate enough bytes to store a u64
                let mut bytes = [0; 8];
                let width = self.config.segment_widths[segment];
                for val in &self.segments[segment] {
                    BigEndian::write_u64(&mut bytes, *val);
                    w.write_all(&bytes[0..width]).unwrap_or_else(|e| {
                        panic!("Error: Writing to output file for segment {} failed: {}",
                               segment,
                               e);
                    });
                }
            }
            OutputFormat::HexList => {
                use std::iter::FromIterator;
                // Allocate enough bytes to store a u64
                let mut bytes = [0u8; 8];
                let width = self.config.segment_widths[segment];
                for val in &self.segments[segment] {
                    BigEndian::write_u64(&mut bytes, *val);
                    w.write_all((String::from_iter(bytes[(8 - width)..8]
                                .iter()
                                .map(|&b| format!("{:02X}", b))) +
                                    "\n")
                            .as_bytes())
                        .unwrap_or_else(|e| {
                            panic!("Error: Writing to output file for segment {} failed: {}",
                                   segment,
                                   e);
                        });
                }
            }
        }
    }

    pub fn parse_segment(&mut self, segment: &str, line: usize) {
        if segment.is_empty() {
            return;
        }
        if self.attempt_tag_create(segment) {
            return;
        }
        if self.attempt_rules(segment, line) {
            return;
        }
        panic!("Error: Unrecognized symbol \"{}\" on line {}.",
               segment,
               line);
    }

    fn attempt_tag_create(&mut self, segment: &str) -> bool {
        if let Some(caps) = self.config.tag_create.regex.as_ref().unwrap().captures(segment) {
            let s = caps.at(1).unwrap();
            if s.chars().all(|c| c == '+') {
                self.plus_tags.push((s.len(),
                                     self.segments
                    .iter()
                    .map(|v| v.len())
                    .collect()));
            } else if s.chars().all(|c| c == '-') {
                self.minus_tags.push((s.len(),
                                      self.segments
                    .iter()
                    .map(|v| v.len())
                    .collect()));
            } else {
                self.tags.insert(s.to_string(),
                                 self.segments
                                     .iter()
                                     .map(|v| v.len())
                                     .collect());
            }
            true
        } else {
            false
        }
    }

    fn attempt_rules(&mut self, segment: &str, line: usize) -> bool {
        let config = &self.config;
        for rule in &config.rules {
            if let Some(caps) = rule.regex.as_ref().unwrap().captures(segment) {
                let mut segvals = rule.segment_values.clone();
                for self_reference in &rule.self_references {
                    segvals[self_reference.add_segment][self_reference.add_index] +=
                        if self_reference.shift < 0 {
                            (self.segments[self_reference.from_segment].len() as u64) >>
                            ((-self_reference.shift) as u32)
                        } else {
                            (self.segments[self_reference.from_segment].len() as u64) <<
                            (self_reference.shift as u32)
                        };
                }
                for (index, capture) in rule.captures.iter().enumerate() {
                    use std::mem::transmute;
                    let cap_string = caps.at(index + 1).unwrap();
                    match *capture {
                        Capture::Tag { ref feedbacks } => {
                            for feedback in feedbacks {
                                self.replacements.push(Replacement {
                                    line: line,
                                    shift: feedback.shift,
                                    add_segment: feedback.add_segment,
                                    index: self.segments[feedback.add_segment].len() +
                                           feedback.add_index,
                                    tag: String::from(cap_string),
                                    pos_segment: feedback.from_segment,
                                    pos_offset: if feedback.relative {
                                        feedback.offset -
                                        self.segments[feedback.from_segment].len() as isize
                                    } else {
                                        feedback.offset
                                    },
                                });
                            }
                        }
                        Capture::Str { add_segment } => {
                            for c in cap_string.chars() {
                                self.segments[add_segment].push(c as u64);
                            }
                        }
                        Capture::Num { ref feedbacks, ref base } => {
                            let pval = i64::from_str_radix(cap_string, *base).unwrap_or_else(|e| {
                                panic!("Error: Failed to parse captured string \"{}\" from \
                                        \"{}\": {}",
                                       cap_string,
                                       segment,
                                       e);
                            });
                            let val: u64 = unsafe { transmute(pval) };

                            for feedback in feedbacks {
                                let mut shiftval = shift_left_or_right(val, feedback.shift);
                                if feedback.negate {
                                    shiftval = !shiftval + 1;
                                }
                                if feedback.fill {
                                    let baseval = segvals[feedback.segment][feedback.index];
                                    let fill_amount = shiftval as isize + feedback.fill_offset;
                                    if fill_amount.is_negative() {
                                        panic!("Error: Got a negative fill amount!");
                                    } else if feedback.align {
                                        while self.segments[feedback.segment].len() <
                                              fill_amount as usize {
                                            self.segments[feedback.segment].push(baseval);
                                        }
                                    } else {
                                        for _ in 0..fill_amount {
                                            self.segments[feedback.segment].push(baseval);
                                        }
                                    }
                                    segvals[feedback.segment].pop();
                                } else {
                                    segvals[feedback.segment][feedback.index] += shiftval;
                                }
                            }
                        }
                    }
                }
                for (segvec, segment) in segvals.iter_mut().zip(self.segments.iter_mut()) {
                    segment.append(segvec);
                }
                return true;
            }
        }
        false
    }
}
<commit_msg>error on duplicate tags<commit_after>use super::config::{Config, Capture};
use std::collections::HashMap;
use std::io::{BufRead, Write};

#[derive(Debug, Clone, Copy)]
pub enum OutputFormat {
    LittleEndian,
    BigEndian,
    HexList,
}

struct Replacement {
    // Line for purposes of printing errors.
    line: usize,
    // Left shift amount
    shift: i32,
    // Segment to add the value to.
    add_segment: usize,
    // The index in the add_segment to add the value.
    index: usize,
    // The tag to retrieve the position to add.
    tag: String,
    // The segment for which we are retrieving the position from the tag.
    pos_segment: usize,
    // The offset we add after retrieving the value from the tag.
    pos_offset: isize,
}

pub struct Parser<'a> {
    config: &'a Config,
    segments: Vec<Vec<u64>>,
    tags: HashMap<String, Vec<usize>>,
    plus_tags: Vec<(usize, Vec<usize>)>,
    minus_tags: Vec<(usize, Vec<usize>)>,
    replacements: Vec<Replacement>,
}

fn shift_left_or_right(a: u64, shift: i32) -> u64 {
    if shift < 0 {
        a >> (-shift)
    } else {
        a << shift
    }
}

impl<'a> Parser<'a> {
    pub fn new(config: &'a Config) -> Self {
        Parser {
            config: config,
            segments: {
                let mut v = Vec::new();
                for _ in 0..config.segment_widths.len() {
                    v.push(Vec::new());
                }
                v
            },
            tags: HashMap::new(),
            plus_tags: Vec::new(),
            minus_tags: Vec::new(),
            replacements: Vec::new(),
        }
    }

    pub fn link(&mut self) {
        // Iterate through every replacement.
        'outer: for r in &self.replacements {
            if r.tag.chars().all(|c| c == '+') {
                for e in &self.plus_tags {
                    // Ensure they have the same amount of pluses and that the relevant segment is at least as high.
                    if e.0 == r.tag.len() && e.1[r.add_segment] >= r.index {
                        self.segments[r.add_segment][r.index] +=
                            shift_left_or_right((e.1[r.pos_segment] as isize + r.pos_offset) as u64, r.shift);

                        break 'outer;
                    }
                }
                panic!("Error: Forward + tag used on line {} was never defined.",
                       r.line);
            } else if r.tag.chars().all(|c| c == '-') {
                for e in self.minus_tags.iter().rev() {
                    // Ensure they have the same amount of minuses and that the relevant segment is at least as low.
                    if e.0 == r.tag.len() && e.1[r.add_segment] < r.index {
                        self.segments[r.add_segment][r.index] +=
                            shift_left_or_right((e.1[r.pos_segment] as isize + r.pos_offset) as u64, r.shift);

                        break 'outer;
                    }
                }
                panic!("Error: Forward + tag used on line {} was never defined.",
                       r.line);
            } else {
                // Get the tag offset vector corresponding to the replacement.
                let tag = self.tags.get(&r.tag).unwrap_or_else(|| {
                    panic!("Error: Tag \"{}\" used on line {} never defined.",
                           r.tag,
                           r.line);
                });
                self.segments[r.add_segment][r.index] +=
                    shift_left_or_right((tag[r.pos_segment] as isize + r.pos_offset) as u64,
                                        r.shift);
            }
        }
    }

    pub fn parse<B>(&mut self, bufread: B)
        where B: BufRead
    {
        for (index, line) in bufread.lines().enumerate() {
            let line = line.unwrap_or_else(|e| panic!("Error: Failed to read from buffer: {}", e));

            // Remove everything after the first #, which denotes a comment.
            let line = line.splitn(2, '#').next().unwrap();

            if self.config.split_whitespace {
                for word in line.split_whitespace() {
                    self.parse_segment(word, index + 1);
                }
            } else {
                self.parse_segment(line, index + 1);
            }
        }
    }

    pub fn output<W>(&self, format: OutputFormat, segment: usize, w: &mut W)
        where W: Write
    {
        use byteorder::{ByteOrder, LittleEndian, BigEndian};
        match format {
            OutputFormat::LittleEndian => {
                // Allocate enough bytes to store a u64
                let mut bytes = [0; 8];
                let width = self.config.segment_widths[segment];
                for val in &self.segments[segment] {
                    LittleEndian::write_u64(&mut bytes, *val);
                    w.write_all(&bytes[0..width]).unwrap_or_else(|e| {
                        panic!("Error: Writing to output file for segment {} failed: {}",
                               segment,
                               e);
                    });
                }
            }
            OutputFormat::BigEndian => {
                // Allocate enough bytes to store a u64
                let mut bytes = [0; 8];
                let width = self.config.segment_widths[segment];
                for val in &self.segments[segment] {
                    BigEndian::write_u64(&mut bytes, *val);
                    w.write_all(&bytes[0..width]).unwrap_or_else(|e| {
                        panic!("Error: Writing to output file for segment {} failed: {}",
                               segment,
                               e);
                    });
                }
            }
            OutputFormat::HexList => {
                use std::iter::FromIterator;
                // Allocate enough bytes to store a u64
                let mut bytes = [0u8; 8];
                let width = self.config.segment_widths[segment];
                for val in &self.segments[segment] {
                    BigEndian::write_u64(&mut bytes, *val);
                    w.write_all((String::from_iter(bytes[(8 - width)..8]
                                .iter()
                                .map(|&b| format!("{:02X}", b))) +
                                    "\n")
                            .as_bytes())
                        .unwrap_or_else(|e| {
                            panic!("Error: Writing to output file for segment {} failed: {}",
                                   segment,
                                   e);
                        });
                }
            }
        }
    }

    pub fn parse_segment(&mut self, segment: &str, line: usize) {
        if segment.is_empty() {
            return;
        }
        if self.attempt_tag_create(segment, line) {
            return;
        }
        if self.attempt_rules(segment, line) {
            return;
        }
        panic!("Error: Unrecognized symbol \"{}\" on line {}.",
               segment,
               line);
    }

    fn attempt_tag_create(&mut self, segment: &str, line: usize) -> bool {
        if let Some(caps) = self.config.tag_create.regex.as_ref().unwrap().captures(segment) {
            let s = caps.at(1).unwrap();
            if s.chars().all(|c| c == '+') {
                self.plus_tags.push((s.len(),
                                     self.segments
                    .iter()
                    .map(|v| v.len())
                    .collect()));
            } else if s.chars().all(|c| c == '-') {
                self.minus_tags.push((s.len(),
                                      self.segments
                    .iter()
                    .map(|v| v.len())
                    .collect()));
            } else {
                use std::collections::hash_map::Entry;
                match self.tags.entry(s.to_string()) {
                    Entry::Occupied(_) => {
                        panic!("Attempted to create duplicate tag \"{}\" on line {}",
                               s,
                               line)
                    }
                    Entry::Vacant(v) => {
                        v.insert(self.segments
                            .iter()
                            .map(|v| v.len())
                            .collect());
                    }
                }
            }
            true
        } else {
            false
        }
    }

    fn attempt_rules(&mut self, segment: &str, line: usize) -> bool {
        let config = &self.config;
        for rule in &config.rules {
            if let Some(caps) = rule.regex.as_ref().unwrap().captures(segment) {
                let mut segvals = rule.segment_values.clone();
                for self_reference in &rule.self_references {
                    segvals[self_reference.add_segment][self_reference.add_index] +=
                        if self_reference.shift < 0 {
                            (self.segments[self_reference.from_segment].len() as u64) >>
                            ((-self_reference.shift) as u32)
                        } else {
                            (self.segments[self_reference.from_segment].len() as u64) <<
                            (self_reference.shift as u32)
                        };
                }
                for (index, capture) in rule.captures.iter().enumerate() {
                    use std::mem::transmute;
                    let cap_string = caps.at(index + 1).unwrap();
                    match *capture {
                        Capture::Tag { ref feedbacks } => {
                            for feedback in feedbacks {
                                self.replacements.push(Replacement {
                                    line: line,
                                    shift: feedback.shift,
                                    add_segment: feedback.add_segment,
                                    index: self.segments[feedback.add_segment].len() +
                                           feedback.add_index,
                                    tag: String::from(cap_string),
                                    pos_segment: feedback.from_segment,
                                    pos_offset: if feedback.relative {
                                        feedback.offset -
                                        self.segments[feedback.from_segment].len() as isize
                                    } else {
                                        feedback.offset
                                    },
                                });
                            }
                        }
                        Capture::Str { add_segment } => {
                            for c in cap_string.chars() {
                                self.segments[add_segment].push(c as u64);
                            }
                        }
                        Capture::Num { ref feedbacks, ref base } => {
                            let pval = i64::from_str_radix(cap_string, *base).unwrap_or_else(|e| {
                                panic!("Error: Failed to parse captured string \"{}\" from \
                                        \"{}\": {}",
                                       cap_string,
                                       segment,
                                       e);
                            });
                            let val: u64 = unsafe { transmute(pval) };

                            for feedback in feedbacks {
                                let mut shiftval = shift_left_or_right(val, feedback.shift);
                                if feedback.negate {
                                    shiftval = !shiftval + 1;
                                }
                                if feedback.fill {
                                    let baseval = segvals[feedback.segment][feedback.index];
                                    let fill_amount = shiftval as isize + feedback.fill_offset;
                                    if fill_amount.is_negative() {
                                        panic!("Error: Got a negative fill amount!");
                                    } else if feedback.align {
                                        while self.segments[feedback.segment].len() <
                                              fill_amount as usize {
                                            self.segments[feedback.segment].push(baseval);
                                        }
                                    } else {
                                        for _ in 0..fill_amount {
                                            self.segments[feedback.segment].push(baseval);
                                        }
                                    }
                                    segvals[feedback.segment].pop();
                                } else {
                                    segvals[feedback.segment][feedback.index] += shiftval;
                                }
                            }
                        }
                    }
                }
                for (segvec, segment) in segvals.iter_mut().zip(self.segments.iter_mut()) {
                    segment.append(segvec);
                }
                return true;
            }
        }
        false
    }
}
<|endoftext|>


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

use model::Model;
use entity::Entity;
use resource::ResourceManager;
use transform::Transform;

pub type Id = u32;

/// The scene type.
///
/// This type gathers all the required objects a scene needs to correctly handle and render all
/// visual effects.
pub struct Scene<'a> {
  /// Resource manager; used to handle scarce resources.
  res_manager: ResourceManager,
  /// List of all models used in the scene.
  models: Vec<Model<'a>>,
  /// Model cache used to resolve Id based on instance name.
  model_cache: HashMap<String, Id>,
}

impl<'a> Scene<'a> {
  pub fn new<P>(root: P) -> Self where P: AsRef<Path>{
    Scene {
      res_manager: ResourceManager::new(root),
      models: Vec::new(),
      model_cache: HashMap::new(),
    }
  }

  pub fn get_id<T>(&mut self, inst_name: &str) -> Option<Id> where T: GetId {
    T::get_id(self, inst_name)
  }

  pub fn resource_manager(&mut self) -> &mut ResourceManager {
    &mut self.res_manager
  }
}

pub trait GetId {
  fn get_id<'a>(scene: &mut Scene<'a>, inst_name: &str) -> Option<Id>;
}

impl<'b> GetId for Model<'b> {
  fn get_id<'a>(scene: &mut Scene<'a>, inst_name: &str) -> Option<Id> {
    match scene.model_cache.get(inst_name).cloned() {
      id@Some(..) => id,
      None => {
        // cache miss; load then
        let path_str = format!("data/models/{}.obj", inst_name);
        let path = Path::new(&path_str);

        if path.exists() {
          match Model::load(&mut scene.res_manager, path) {
            Ok(model) => {
              let model_id = scene.models.len() as u32;

              // add the model to the list of loaded models
              scene.models.push(model);
              // add the model to the cache
              scene.model_cache.insert(inst_name.to_owned(), model_id);

              Some(model_id)
            },
            Err(e) => {
              err!("unable to load model '{}': '{:?}'", inst_name, e);
              None
            }
          }
        } else { // TODO: add a manifest override to look in somewhere else
          err!("model '{}' cannot be found", inst_name);
          None
        }
      }
    }
  }
}
<commit_msg>inst_name -> name.<commit_after>use std::collections::HashMap;
use std::path::Path;

use model::Model;
use entity::Entity;
use resource::ResourceManager;
use transform::Transform;

pub type Id = u32;

/// The scene type.
///
/// This type gathers all the required objects a scene needs to correctly handle and render all
/// visual effects.
pub struct Scene<'a> {
  /// Resource manager; used to handle scarce resources.
  res_manager: ResourceManager,
  /// List of all models used in the scene.
  models: Vec<Model<'a>>,
  /// Model cache used to resolve Id based on instance name.
  model_cache: HashMap<String, Id>,
}

impl<'a> Scene<'a> {
  pub fn new<P>(root: P) -> Self where P: AsRef<Path>{
    Scene {
      res_manager: ResourceManager::new(root),
      models: Vec::new(),
      model_cache: HashMap::new(),
    }
  }

  pub fn get_id<T>(&mut self, name: &str) -> Option<Id> where T: GetId {
    T::get_id(self, name)
  }

  pub fn get_model(&mut self, id

  pub fn resource_manager(&mut self) -> &mut ResourceManager {
    &mut self.res_manager
  }
}

pub trait GetId {
  fn get_id<'a>(scene: &mut Scene<'a>, name: &str) -> Option<Id>;
}

impl<'b> GetId for Model<'b> {
  fn get_id<'a>(scene: &mut Scene<'a>, name: &str) -> Option<Id> {
    match scene.model_cache.get(name).cloned() {
      id@Some(..) => id,
      None => {
        // cache miss; load then
        let path_str = format!("data/models/{}.obj", name);
        let path = Path::new(&path_str);

        if path.exists() {
          match Model::load(&mut scene.res_manager, path) {
            Ok(model) => {
              let model_id = scene.models.len() as u32;

              // add the model to the list of loaded models
              scene.models.push(model);
              // add the model to the cache
              scene.model_cache.insert(name.to_owned(), model_id);

              Some(model_id)
            },
            Err(e) => {
              err!("unable to load model '{}': '{:?}'", name, e);
              None
            }
          }
        } else { // TODO: add a manifest override to look in somewhere else
          err!("model '{}' cannot be found", name);
          None
        }
      }
    }
  }
}
<|endoftext|>


<commit_before>//! Data structures that can be shared between the server and the client.
//!
//! All these structures should be serializable, so that they can be
//! transferred from the server to the client over the network.
use std::convert::Into;
use std::fmt;
use std::collections::HashMap;

/// A unit identifier.
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Copy, Clone, Hash)]
pub struct UnitId(pub u32);

impl Into<UnitId> for u32 {
    fn into(self) -> UnitId {
        UnitId(self)
    }
}

impl fmt::Display for UnitId {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.0.fmt(f)
    }
}

/// A client/player identifier.
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Copy, Clone)]
pub struct ClientId(pub u32);

impl Into<ClientId> for u32 {
    fn into(self) -> ClientId {
        ClientId(self)
    }
}

impl fmt::Display for ClientId {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.0.fmt(f)
    }
}

pub const UNIT_SIZE: f64 = 50.0;

/// The state of a single unit
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct Unit {
    /// The unit identifier
    pub id: UnitId,

    /// X/Y position in the world in m
    pub position: [f64; 2],

    /// Angle of the unit in radiant
    pub angle: f64,

    /// Direction and speed of the movement. The angle of the movement may be different then the
    /// angle of the unit. The unit is m per milli second.
    pub speed_vector: [f64; 2],

    /// Health of the unit
    pub health: u64,
}

impl Unit {
    pub fn new<T: Into<UnitId>>(id: T, position: [f64; 2]) -> Unit {
        println!("Create unit at {:?}", position);
        Unit {
            id: id.into(),
            position: position,
            angle: 0.0f64,
            speed_vector: [0.0f64, 0.0f64],
            health: 100_0000,
        }
    }

    pub fn update(&mut self, dt_ms: f64) {
        self.position[0] += self.speed_vector[0] * dt_ms;
        self.position[1] += self.speed_vector[1] * dt_ms;
    }
}

/// A player has an ID and consists of 0..N `Unit`s
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct Player {
    pub id: ClientId,
    pub units: Vec<Unit>,
}

impl Player {
    pub fn new<T: Into<ClientId>>(id: T) -> Player {
        Player {
            id: id.into(),
            units: vec![],
        }
    }
}

/// Data related to the current game.
///
/// This needs to be transferred to the client every time the game state
/// changes.
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct GameState {
    /// List of players
    pub players: Vec<Player>,
}

impl GameState {
    pub fn new() -> GameState {
        GameState{ players: vec![] }
    }

    pub fn update_targets(&mut self, unit_targets: &HashMap<UnitId, [f64; 2]>) {
        for player in self.players.iter_mut() {
            for unit in player.units.iter_mut() {
                if let Some(target) = unit_targets.get(&unit.id) {
                    let speed = 0.0001;
                    unit.speed_vector = [(target[0]-unit.position[0])*speed, (target[1]-unit.position[1])*speed];
                } else {
                    unit.speed_vector = [0.0,0.0];
                }
            }
        }
    }

    pub fn update(&mut self, dt: f64) {
        for player in self.players.iter_mut() {
            for unit in player.units.iter_mut() {
                unit.update(dt);
            }
        }
    }
}

/// Data related to the entire world, like width and height.
///
/// This needs to be transferred to the client only once, on connecting.
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct WorldState {
    /// Width of the world in m
    pub x: f64,
    /// Height of the world in m
    pub y: f64,
}

impl WorldState {
    pub fn new(x: f64, y: f64) -> WorldState {
        WorldState {
            x: x,
            y: y,
        }
    }
}
<commit_msg>state: Add Bullet<commit_after>//! Data structures that can be shared between the server and the client.
//!
//! All these structures should be serializable, so that they can be
//! transferred from the server to the client over the network.
use std::convert::Into;
use std::fmt;
use std::collections::HashMap;

/// A unit identifier.
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Copy, Clone, Hash)]
pub struct UnitId(pub u32);

impl Into<UnitId> for u32 {
    fn into(self) -> UnitId {
        UnitId(self)
    }
}

impl fmt::Display for UnitId {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.0.fmt(f)
    }
}

/// A client/player identifier.
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Copy, Clone)]
pub struct ClientId(pub u32);

impl Into<ClientId> for u32 {
    fn into(self) -> ClientId {
        ClientId(self)
    }
}

impl fmt::Display for ClientId {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.0.fmt(f)
    }
}

pub const UNIT_SIZE: f64 = 50.0;

/// The state of a single unit
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct Unit {
    /// The unit identifier
    pub id: UnitId,

    /// X/Y position in the world in m
    pub position: [f64; 2],

    /// Angle of the unit in radiant
    pub angle: f64,

    /// Direction and speed of the movement. The angle of the movement may be different then the
    /// angle of the unit. The unit is m per milli second.
    pub speed_vector: [f64; 2],

    /// Health of the unit
    pub health: u64,
}

impl Unit {
    pub fn new<T: Into<UnitId>>(id: T, position: [f64; 2]) -> Unit {
        println!("Create unit at {:?}", position);
        Unit {
            id: id.into(),
            position: position,
            angle: 0.0f64,
            speed_vector: [0.0f64, 0.0f64],
            health: 100_0000,
        }
    }

    pub fn update(&mut self, dt_ms: f64) {
        self.position[0] += self.speed_vector[0] * dt_ms;
        self.position[1] += self.speed_vector[1] * dt_ms;
    }

    pub fn shoot(&self, size: f64, speed: f64) -> Bullet {
        let position = [
            self.position[0] + self.angle.cos() * size,
            self.position[1] + self.angle.sin() * size,
        ];
        let speed = [
            self.angle.cos() * speed,
            self.angle.sin() * speed,
        ];
        Bullet::new(position, speed)
    }
}

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct Bullet {
    pub position: [f64; 2],
    pub speed_vector: [f64; 2],
}

impl Bullet {
    pub fn new(position: [f64; 2], speed: [f64; 2]) -> Bullet {
        Bullet {
            position: position,
            speed_vector: speed,
        }
    }

    pub fn update(&mut self, dt_ms: f64) {
        self.position[0] += self.speed_vector[0] * dt_ms;
        self.position[1] += self.speed_vector[1] * dt_ms;
    }
}

/// A player has an ID and consists of 0..N `Unit`s
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct Player {
    pub id: ClientId,
    pub units: Vec<Unit>,
    pub bullets: Vec<Bullet>,
}

impl Player {
    pub fn new<T: Into<ClientId>>(id: T) -> Player {
        Player {
            id: id.into(),
            units: vec![],
            bullets: vec![],
        }
    }
}

/// Data related to the current game.
///
/// This needs to be transferred to the client every time the game state
/// changes.
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct GameState {
    /// List of players
    pub players: Vec<Player>,
}

impl GameState {
    pub fn new() -> GameState {
        GameState{ players: vec![] }
    }

    pub fn update_targets(&mut self, unit_targets: &HashMap<UnitId, [f64; 2]>) {
        for player in self.players.iter_mut() {
            for unit in player.units.iter_mut() {
                if let Some(target) = unit_targets.get(&unit.id) {
                    let speed = 0.0001;
                    unit.speed_vector = [(target[0]-unit.position[0])*speed, (target[1]-unit.position[1])*speed];
                } else {
                    unit.speed_vector = [0.0,0.0];
                }
            }
        }
    }

    pub fn update(&mut self, dt: f64) {
        for player in self.players.iter_mut() {
            for unit in player.units.iter_mut() {
                unit.update(dt);
            }
            for bullet in player.bullets.iter_mut() {
                bullet.update(dt);
            }
        }
    }
}

/// Data related to the entire world, like width and height.
///
/// This needs to be transferred to the client only once, on connecting.
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct WorldState {
    /// Width of the world in m
    pub x: f64,
    /// Height of the world in m
    pub y: f64,
}

impl WorldState {
    pub fn new(x: f64, y: f64) -> WorldState {
        WorldState {
            x: x,
            y: y,
        }
    }
}
<|endoftext|>


<commit_before>use std::cmp::max;
use std::sync::Arc;
use std::time::Duration;

use rotor::{Notifier, Time};

use datasets::{self, Dataset};
use peers::PeersState;
use query::RemoteQuery;

#[derive(Debug)]
pub struct State {
    pub min_retry: Duration,
    pub peers_interval: Option<Duration>,
    pub remote_query_task: Option<(Duration, Arc<Box<[u8]>>)>,
    pub peers: Option<Arc<PeersState>>,
    pub remote_query: Option<Arc<RemoteQuery>>,
    peers_attempt: Option<Time>,
    remote_query_attempt: Option<Time>,
    scheduler_notifier: Notifier,
    listeners: Vec<Notifier>,
}

pub trait PrivateState {
    fn new(notifier: Notifier) -> State;
    fn add_listener(&mut self, listener: Notifier);
    fn wakeup_listeners(&self);
    fn next_request(&mut self, now: Time) -> Result<Box<Dataset>, Time>;
    fn changed(&self);
}

impl PrivateState for State {
    fn new(notifier: Notifier) -> State {
        State {
            min_retry: Duration::from_millis(50),
            peers_interval: None,
            peers_attempt: None,
            peers: None,
            remote_query_task: None,
            remote_query_attempt: None,
            remote_query: None,
            scheduler_notifier: notifier,
            listeners: Vec::new(),
        }
    }
    fn add_listener(&mut self, listener: Notifier) {
        self.listeners.push(listener);
    }
    fn wakeup_listeners(&self) {
        for i in &self.listeners {
            i.wakeup().expect("wakeup cantal listener");
        }
    }
    fn next_request(&mut self, now: Time) -> Result<Box<Dataset>, Time> {
        // TODO(tailhook) select minimal time rather than prioritizing
        // the peers over the query
        if let Some(ivl) = self.peers_interval {
            let mut next;
            if let Some(last) = self.peers.as_ref().map(|x| x.received) {
                next = last + ivl;
            } else {
                next = now;
            }
            if let Some(attempt) = self.peers_attempt {
                next = max(attempt + self.min_retry, next);
            }
            if next <= now {
                self.peers_attempt = Some(now);
                Ok(Box::new(datasets::Peers))
            } else {
                Err(next)
            }
        } else if let Some((ivl, ref data)) = self.remote_query_task {
            let mut next;
            if let Some(last) = self.remote_query.as_ref().map(|x| x.received) {
                next = last + ivl;
            } else {
                next = now;
            }
            if let Some(attempt) = self.remote_query_attempt {
                next = max(attempt + self.min_retry, next);
            }
            if next <= now {
                self.remote_query_attempt = Some(now);
                Ok(Box::new(datasets::RemoteQuery(data.clone())))
            } else {
                Err(next)
            }
        } else {
            // TODO(tailhook) this breaks abstractions a little bit
            Err(now + Duration::new(120, 0))
        }
    }
    fn changed(&self) {
        self.scheduler_notifier.wakeup().expect("wakeup state machine")
    }
}
<commit_msg>Fix bug in scheduling peers and query simultaneously<commit_after>use std::cmp::{max, min};
use std::sync::Arc;
use std::time::Duration;

use rotor::{Notifier, Time};

use datasets::{self, Dataset};
use peers::PeersState;
use query::RemoteQuery;

#[derive(Debug)]
pub struct State {
    pub min_retry: Duration,
    pub peers_interval: Option<Duration>,
    pub remote_query_task: Option<(Duration, Arc<Box<[u8]>>)>,
    pub peers: Option<Arc<PeersState>>,
    pub remote_query: Option<Arc<RemoteQuery>>,
    peers_attempt: Option<Time>,
    remote_query_attempt: Option<Time>,
    scheduler_notifier: Notifier,
    listeners: Vec<Notifier>,
}

pub trait PrivateState {
    fn new(notifier: Notifier) -> State;
    fn add_listener(&mut self, listener: Notifier);
    fn wakeup_listeners(&self);
    fn next_request(&mut self, now: Time) -> Result<Box<Dataset>, Time>;
    fn changed(&self);
}

impl PrivateState for State {
    fn new(notifier: Notifier) -> State {
        State {
            min_retry: Duration::from_millis(50),
            peers_interval: None,
            peers_attempt: None,
            peers: None,
            remote_query_task: None,
            remote_query_attempt: None,
            remote_query: None,
            scheduler_notifier: notifier,
            listeners: Vec::new(),
        }
    }
    fn add_listener(&mut self, listener: Notifier) {
        self.listeners.push(listener);
    }
    fn wakeup_listeners(&self) {
        for i in &self.listeners {
            i.wakeup().expect("wakeup cantal listener");
        }
    }
    fn next_request(&mut self, now: Time) -> Result<Box<Dataset>, Time> {
        // TODO(tailhook) select minimal time rather than prioritizing
        // the peers over the query
        let mut sleep = now + Duration::new(120, 0);
        if let Some(ivl) = self.peers_interval {
            let mut next;
            if let Some(last) = self.peers.as_ref().map(|x| x.received) {
                next = last + ivl;
            } else {
                next = now;
            }
            if let Some(attempt) = self.peers_attempt {
                next = max(attempt + self.min_retry, next);
            }
            if next <= now {
                self.peers_attempt = Some(now);
                return Ok(Box::new(datasets::Peers));
            } else {
                sleep = min(next, sleep);
            }
        }
        if let Some((ivl, ref data)) = self.remote_query_task {
            let mut next;
            if let Some(last) = self.remote_query.as_ref().map(|x| x.received) {
                next = last + ivl;
            } else {
                next = now;
            }
            if let Some(attempt) = self.remote_query_attempt {
                next = max(attempt + self.min_retry, next);
            }
            if next <= now {
                self.remote_query_attempt = Some(now);
                return Ok(Box::new(datasets::RemoteQuery(data.clone())));
            } else {
                sleep = min(next, sleep);
            }
        }
        return Err(sleep)
    }
    fn changed(&self) {
        self.scheduler_notifier.wakeup().expect("wakeup state machine")
    }
}
<|endoftext|>


<commit_before>#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Color {
    Reset,
    Black,
    Red,
    Green,
    Yellow,
    Blue,
    Magenta,
    Cyan,
    Gray,
    DarkGray,
    LightRed,
    LightGreen,
    LightYellow,
    LightBlue,
    LightMagenta,
    LightCyan,
    White,
    Rgb(u8, u8, u8),
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Modifier {
    Blink,
    Bold,
    CrossedOut,
    Faint,
    Framed,
    Invert,
    Italic,
    NoBlink,
    NoBold,
    NoCrossedOut,
    NoFaint,
    NoInvert,
    NoItalic,
    NoUnderline,
    Reset,
    Underline,
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Style {
    pub fg: Color,
    pub bg: Color,
    pub modifier: Modifier,
}

impl Default for Style {
    fn default() -> Style {
        Style {
            fg: Color::Reset,
            bg: Color::Reset,
            modifier: Modifier::Reset,
        }
    }
}

impl Style {
    pub fn reset(&mut self) {
        self.fg = Color::Reset;
        self.bg = Color::Reset;
        self.modifier = Modifier::Reset;
    }

    pub fn fg(mut self, color: Color) -> Style {
        self.fg = color;
        self
    }
    pub fn bg(mut self, color: Color) -> Style {
        self.bg = color;
        self
    }
    pub fn modifier(mut self, modifier: Modifier) -> Style {
        self.modifier = modifier;
        self
    }
}
<commit_msg>[style] add enum for text alignment<commit_after>#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Color {
    Reset,
    Black,
    Red,
    Green,
    Yellow,
    Blue,
    Magenta,
    Cyan,
    Gray,
    DarkGray,
    LightRed,
    LightGreen,
    LightYellow,
    LightBlue,
    LightMagenta,
    LightCyan,
    White,
    Rgb(u8, u8, u8),
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Modifier {
    Blink,
    Bold,
    CrossedOut,
    Faint,
    Framed,
    Invert,
    Italic,
    NoBlink,
    NoBold,
    NoCrossedOut,
    NoFaint,
    NoInvert,
    NoItalic,
    NoUnderline,
    Reset,
    Underline,
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Alignment {
    Left,
    Center,
    Right,
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Style {
    pub fg: Color,
    pub bg: Color,
    pub modifier: Modifier,
}

impl Default for Style {
    fn default() -> Style {
        Style {
            fg: Color::Reset,
            bg: Color::Reset,
            modifier: Modifier::Reset,
        }
    }
}

impl Style {
    pub fn reset(&mut self) {
        self.fg = Color::Reset;
        self.bg = Color::Reset;
        self.modifier = Modifier::Reset;
    }

    pub fn fg(mut self, color: Color) -> Style {
        self.fg = color;
        self
    }
    pub fn bg(mut self, color: Color) -> Style {
        self.bg = color;
        self
    }
    pub fn modifier(mut self, modifier: Modifier) -> Style {
        self.modifier = modifier;
        self
    }
}
<|endoftext|>


<commit_before>use super::Array;
use std::fmt::Debug;
use std::ops::Add;

fn test_empty<T: Array<i32>>(mut arr: T)
{
    assert_eq!(arr.len(), 0);
    assert_eq!(arr.is_empty(), true);
    assert_eq!(arr.first(), None);
    assert_eq!(arr.first_mut(), None);
    assert_eq!(arr.last(), None);
    assert_eq!(arr.last_mut(), None);
    assert_eq!(arr.get(1), None);
    assert_eq!(arr.get_mut(1), None);
}

fn test_arr<T: Array<V>, V: PartialEq + Debug>(mut arr: T, len: usize, mut first: V, mut last: V, mut second: V)
{
    assert_eq!(arr.len(), len);
    assert_eq!(arr.is_empty(), false);
    assert_eq!(arr.first(), Some(&first));
    assert_eq!(arr.first_mut(), Some(&mut first));
    assert_eq!(arr.last(), Some(&last));
    assert_eq!(arr.last_mut(), Some(&mut last));
    assert_eq!(arr.get(1), Some(&second));
    assert_eq!(arr.get(42), None);
    assert_eq!(arr.get_mut(1), Some(&mut second));
    assert_eq!(arr.get_mut(42), None);
}

#[test]
fn methods()
{
    let arr: [i32; 0] = [];
    test_empty(arr);
    assert_eq!(arr.map(|a| a * 2), []);
    assert_eq!(arr.fold(0, |a, n| a + n), 0);

    let arr = [1, 2, 3, 4];
    test_arr(arr, 4, 1, 4, 2);
    assert_eq!(arr.map(|a| a * 2), [2, 4, 6, 8]);
    assert_eq!(arr.fold(0, |a, n| a + n), 10);
}

fn sum<T, V>(arr: T, val: V) -> T
    where T: Array<V>, V: Add<Output=V> + Copy
{
    arr.map(|n| n + val)
}

#[test]
fn generics()
{
    assert_eq!(sum([], 1), []);
    assert_eq!(sum([1], 10), [11]);
    assert_eq!(sum([1, 2], 20), [21, 22]);
    assert_eq!(sum([1, 2, 3], 30), [31, 32, 33]);
    assert_eq!(sum([1, 2, 3, 4], 40), [41, 42, 43, 44]);
}

#[test]
fn slice()
{
    assert_eq!([1, 2, 3].as_slice(), &[1, 2, 3]);
    assert_eq!([4, 5, 6].as_mut_slice(), &mut [4, 5, 6]);

    let mut arr = [1, -5, 8, 42, 33];
    arr.as_mut_slice().sort();
    assert_eq!(arr, [-5, 1, 8, 33, 42]);
}
<commit_msg>added more tests<commit_after>use super::Array;
use std::fmt::Debug;
use std::ops::Add;

fn test_empty<T: Array<i32>>(mut arr: T)
{
    assert_eq!(arr.len(), 0);
    assert_eq!(arr.is_empty(), true);
    assert_eq!(arr.first(), None);
    assert_eq!(arr.first_mut(), None);
    assert_eq!(arr.last(), None);
    assert_eq!(arr.last_mut(), None);
    assert_eq!(arr.get(1), None);
    assert_eq!(arr.get_mut(1), None);
}

#[test]
fn methods_empty()
{
    let arr: [i32; 0] = [];
    test_empty(arr);
    assert_eq!(arr.map(|a| a * 2), []);
    assert_eq!(arr.fold(0, |a, n| a + n), 0);
}

fn test_arr<T: Array<V>, V: PartialEq + Debug>(mut arr: T, len: usize, mut first: V, mut last: V, mut second: V)
{
    assert_eq!(arr.len(), len);
    assert_eq!(arr.is_empty(), false);
    assert_eq!(arr.first(), Some(&first));
    assert_eq!(arr.first_mut(), Some(&mut first));
    assert_eq!(arr.last(), Some(&last));
    assert_eq!(arr.last_mut(), Some(&mut last));
    assert_eq!(arr.get(1), Some(&second));
    assert_eq!(arr.get(42), None);
    assert_eq!(arr.get_mut(1), Some(&mut second));
    assert_eq!(arr.get_mut(42), None);
}

#[test]
fn methods()
{
    let arr = [1, 2, 3, 4];
    test_arr(arr, 4, 1, 4, 2);
    assert_eq!(arr.map(|a| a * 2), [2, 4, 6, 8]);
    assert_eq!(arr.fold(0, |a, n| a + n), 10);

    let arr = ['c', 'd', 'e', 'f', 'g', 'a', 'b'];
    test_arr(arr, 7, 'c', 'b', 'd');
    assert_eq!(arr.map(|a| a.to_uppercase().next().unwrap()), ['C', 'D', 'E', 'F', 'G', 'A', 'B']);
    assert_eq!(arr.fold(String::new(), |mut a, c| { a.push(c); a }), "cdefgab");
}

fn sum<T, V>(arr: T, val: V) -> T
    where T: Array<V>, V: Add<Output=V> + Copy
{
    arr.map(|n| n + val)
}

fn avg<T: Array<f32>>(arr: T) -> f32
{
    let n = arr.len() as f32;
    arr.fold(0.0, |a, n| a + n) / n
}

#[test]
fn generics()
{
    assert_eq!(sum([], 1), []);
    assert_eq!(sum([1], 10), [11]);
    assert_eq!(sum([1, 2], 20), [21, 22]);
    assert_eq!(sum([1, 2, 3], 30), [31, 32, 33]);
    assert_eq!(sum([1, 2, 3, 4], 40), [41, 42, 43, 44]);

    assert_eq!(avg([3.5, 4.1, 7.0, 1.5]), 4.025);
    assert_eq!(avg([1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, 512.0]), 102.3);
}

#[test]
fn slice()
{
    assert_eq!([1, 2, 3].as_slice(), &[1, 2, 3]);
    assert_eq!([4, 5, 6].as_mut_slice(), &mut [4, 5, 6]);

    let mut arr = [1, -5, 8, 42, 33];
    arr.as_mut_slice().sort();
    assert_eq!(arr, [-5, 1, 8, 33, 42]);

    let mut v = Vec::new();
    v.extend_from_slice(arr.as_slice());
    assert_eq!(arr, &v[..]);
}
<|endoftext|>


<commit_before>use crate::{decode_config, encode::encoded_size, encode_config_buf, CharacterSet, Config};

use std::str;

use rand::{
    distributions::{Distribution, Uniform},
    seq::SliceRandom,
    FromEntropy, Rng,
};

#[test]
fn roundtrip_random_config_short() {
    // exercise the slower encode/decode routines that operate on shorter buffers more vigorously
    roundtrip_random_config(Uniform::new(0, 50), 10_000);
}

#[test]
fn roundtrip_random_config_long() {
    roundtrip_random_config(Uniform::new(0, 1000), 10_000);
}

pub fn assert_encode_sanity(encoded: &str, config: Config, input_len: usize) {
    let input_rem = input_len % 3;
    let expected_padding_len = if input_rem > 0 {
        if config.pad {
            3 - input_rem
        } else {
            0
        }
    } else {
        0
    };

    let expected_encoded_len = encoded_size(input_len, config).unwrap();

    assert_eq!(expected_encoded_len, encoded.len());

    let padding_len = encoded.chars().filter(|&c| c == '=').count();

    assert_eq!(expected_padding_len, padding_len);

    let _ = str::from_utf8(encoded.as_bytes()).expect("Base64 should be valid utf8");
}

fn roundtrip_random_config(input_len_range: Uniform<usize>, iterations: u32) {
    let mut input_buf: Vec<u8> = Vec::new();
    let mut encoded_buf = String::new();
    let mut rng = rand::rngs::SmallRng::from_entropy();

    for _ in 0..iterations {
        input_buf.clear();
        encoded_buf.clear();

        let input_len = input_len_range.sample(&mut rng);

        let config = random_config(&mut rng);

        for _ in 0..input_len {
            input_buf.push(rng.gen());
        }

        encode_config_buf(&input_buf, config, &mut encoded_buf);

        assert_encode_sanity(&encoded_buf, config, input_len);

        assert_eq!(input_buf, decode_config(&encoded_buf, config).unwrap());
    }
}

pub fn random_config<R: Rng>(rng: &mut R) -> Config {
    const CHARSETS: &[CharacterSet] = &[
        CharacterSet::UrlSafe,
        CharacterSet::Standard,
        CharacterSet::Crypt,
        CharacterSet::ImapMutf7
    ];
    let charset = *CHARSETS.choose(rng).unwrap();

    Config::new(charset, rng.gen())
}
<commit_msg>format<commit_after>use crate::{decode_config, encode::encoded_size, encode_config_buf, CharacterSet, Config};

use std::str;

use rand::{
    distributions::{Distribution, Uniform},
    seq::SliceRandom,
    FromEntropy, Rng,
};

#[test]
fn roundtrip_random_config_short() {
    // exercise the slower encode/decode routines that operate on shorter buffers more vigorously
    roundtrip_random_config(Uniform::new(0, 50), 10_000);
}

#[test]
fn roundtrip_random_config_long() {
    roundtrip_random_config(Uniform::new(0, 1000), 10_000);
}

pub fn assert_encode_sanity(encoded: &str, config: Config, input_len: usize) {
    let input_rem = input_len % 3;
    let expected_padding_len = if input_rem > 0 {
        if config.pad {
            3 - input_rem
        } else {
            0
        }
    } else {
        0
    };

    let expected_encoded_len = encoded_size(input_len, config).unwrap();

    assert_eq!(expected_encoded_len, encoded.len());

    let padding_len = encoded.chars().filter(|&c| c == '=').count();

    assert_eq!(expected_padding_len, padding_len);

    let _ = str::from_utf8(encoded.as_bytes()).expect("Base64 should be valid utf8");
}

fn roundtrip_random_config(input_len_range: Uniform<usize>, iterations: u32) {
    let mut input_buf: Vec<u8> = Vec::new();
    let mut encoded_buf = String::new();
    let mut rng = rand::rngs::SmallRng::from_entropy();

    for _ in 0..iterations {
        input_buf.clear();
        encoded_buf.clear();

        let input_len = input_len_range.sample(&mut rng);

        let config = random_config(&mut rng);

        for _ in 0..input_len {
            input_buf.push(rng.gen());
        }

        encode_config_buf(&input_buf, config, &mut encoded_buf);

        assert_encode_sanity(&encoded_buf, config, input_len);

        assert_eq!(input_buf, decode_config(&encoded_buf, config).unwrap());
    }
}

pub fn random_config<R: Rng>(rng: &mut R) -> Config {
    const CHARSETS: &[CharacterSet] = &[
        CharacterSet::UrlSafe,
        CharacterSet::Standard,
        CharacterSet::Crypt,
        CharacterSet::ImapMutf7,
    ];
    let charset = *CHARSETS.choose(rng).unwrap();

    Config::new(charset, rng.gen())
}
<|endoftext|>


<commit_before>// Copyright 2015-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! Runtime type information.

use translate::{FromGlib, FromGlibContainerAsVec, ToGlib, ToGlibPtr, ToGlibContainerFromSlice, from_glib, from_glib_none};
use ffi as glib_ffi;
use gobject_ffi;

use std::fmt;
use std::mem;
use std::ptr;

/// A GLib or GLib-based library type
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Type {
    /// An invalid `Type` used as error return value in some functions
    Invalid,
    /// The fundamental type corresponding to the unit type `()`
    Unit,
    /// The fundamental type corresponding to `i8`
    I8,
    /// The fundamental type corresponding to `u8`
    U8,
    /// The fundamental type corresponding to `bool`
    Bool,
    /// The fundamental type corresponding to `i32`
    I32,
    /// The fundamental type corresponding to `u32`
    U32,
    /// The fundamental type corresponding to C `long`
    ILong,
    /// The fundamental type corresponding to C `unsigned long`
    ULong,
    /// The fundamental type corresponding to `i64`
    I64,
    /// The fundamental type corresponding to `u64`
    U64,
    /// The fundamental type corresponding to `f32`
    F32,
    /// The fundamental type corresponding to `f64`
    F64,
    /// The fundamental type corresponding to `String`
    String,
    /// The fundamental type corresponding to a pointer
    Pointer,
    /// The fundamental type of GVariant
    Variant,
    /// The fundamental type from which all interfaces are derived
    BaseInterface,
    /// The fundamental type from which all enumeration types are derived
    BaseEnum,
    /// The fundamental type from which all flags types are derived
    BaseFlags,
    /// The fundamental type from which all boxed types are derived
    BaseBoxed,
    /// The fundamental type from which all `GParamSpec` types are derived
    BaseParamSpec,
    /// The fundamental type from which all objects are derived
    BaseObject,
    /// A non-fundamental type identified by value of type `usize`
    Other(usize),
}

impl Type {
    pub fn name(&self) -> String {
        unsafe {
            from_glib_none(gobject_ffi::g_type_name(self.to_glib()))
        }
    }

    pub fn is_a(&self, other: &Type) -> bool {
        unsafe {
            from_glib(gobject_ffi::g_type_is_a(self.to_glib(), other.to_glib()))
        }
    }

    pub fn parent(&self) -> Option<Self> {
        unsafe {
            let parent = gobject_ffi::g_type_parent(self.to_glib());
            if parent == gobject_ffi::G_TYPE_INVALID {
                None
            } else {
                Some(from_glib(parent))
            }
        }
    }

    pub fn children(&self) -> Vec<Self> {
        unsafe {
            let mut n_children = 0u32;
            let children = gobject_ffi::g_type_children(self.to_glib(), &mut n_children);

            FromGlibContainerAsVec::from_glib_full_num_as_vec(children, n_children as usize)
        }
    }

    pub fn interfaces(&self) -> Vec<Self> {
        unsafe {
            let mut n_interfaces = 0u32;
            let interfaces = gobject_ffi::g_type_interfaces(self.to_glib(), &mut n_interfaces);

            FromGlibContainerAsVec::from_glib_full_num_as_vec(interfaces, n_interfaces as usize)
        }
    }
    pub fn interface_prerequisites(&self) -> Vec<Self> {
        unsafe {
            let mut n_prereqs = 0u32;
            let prereqs = gobject_ffi::g_type_interface_prerequisites(self.to_glib(), &mut n_prereqs);

            FromGlibContainerAsVec::from_glib_full_num_as_vec(prereqs, n_prereqs as usize)
        }
    }

    pub fn from_name<'a, P: Into<&'a str>>(name: P) -> Option<Self> {
        unsafe {
            let type_ = gobject_ffi::g_type_from_name(name.into().to_glib_none().0);
            if type_ == gobject_ffi::G_TYPE_INVALID {
                None
            } else {
                Some(from_glib(type_))
            }
        }
    }
}

impl fmt::Debug for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(&self.name())
    }
}

impl fmt::Display for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(&self.name())
    }
}

/// Types that are supported by GLib dynamic typing.
pub trait StaticType {
    /// Returns the type identifier of `Self`.
    fn static_type() -> Type;
}

impl<'a, T: ?Sized + StaticType> StaticType for &'a T {
    fn static_type() -> Type {
        T::static_type()
    }
}

macro_rules! builtin {
    ($name:ident, $val:ident) => {
        impl StaticType for $name {
            fn static_type() -> Type {
                Type::$val
            }
        }
    }
}

builtin!(bool, Bool);
builtin!(i8, I8);
builtin!(u8, U8);
builtin!(i32, I32);
builtin!(u32, U32);
builtin!(i64, I64);
builtin!(u64, U64);
builtin!(f32, F32);
builtin!(f64, F64);
builtin!(str, String);
builtin!(String, String);

impl<'a> StaticType for [&'a str] {
    fn static_type() -> Type {
        unsafe {
            from_glib(glib_ffi::g_strv_get_type())
        }
    }
}

impl StaticType for Vec<String> {
    fn static_type() -> Type {
        unsafe {
            from_glib(glib_ffi::g_strv_get_type())
        }
    }
}

pub trait InstanceType {
    fn instance_type(&self) -> Type;
}

#[inline]
pub unsafe fn instance_of<C: StaticType>(ptr: glib_ffi::gconstpointer) -> bool {
    from_glib(
        gobject_ffi::g_type_check_instance_is_a(
            ptr as *mut _, <C as StaticType>::static_type().to_glib()))
}

impl FromGlib<glib_ffi::GType> for Type {
    #[inline]
    fn from_glib(val: glib_ffi::GType) -> Type {
        use self::Type::*;
        match val {
            gobject_ffi::G_TYPE_INVALID => Invalid,
            gobject_ffi::G_TYPE_NONE => Unit,
            gobject_ffi::G_TYPE_INTERFACE => BaseInterface,
            gobject_ffi::G_TYPE_CHAR => I8,
            gobject_ffi::G_TYPE_UCHAR => U8,
            gobject_ffi::G_TYPE_BOOLEAN => Bool,
            gobject_ffi::G_TYPE_INT => I32,
            gobject_ffi::G_TYPE_UINT => U32,
            gobject_ffi::G_TYPE_LONG => ILong,
            gobject_ffi::G_TYPE_ULONG => ULong,
            gobject_ffi::G_TYPE_INT64 => I64,
            gobject_ffi::G_TYPE_UINT64 => U64,
            gobject_ffi::G_TYPE_ENUM => BaseEnum,
            gobject_ffi::G_TYPE_FLAGS => BaseFlags,
            gobject_ffi::G_TYPE_FLOAT => F32,
            gobject_ffi::G_TYPE_DOUBLE => F64,
            gobject_ffi::G_TYPE_STRING => String,
            gobject_ffi::G_TYPE_POINTER => Pointer,
            gobject_ffi::G_TYPE_BOXED => BaseBoxed,
            gobject_ffi::G_TYPE_PARAM => BaseParamSpec,
            gobject_ffi::G_TYPE_OBJECT => BaseObject,
            gobject_ffi::G_TYPE_VARIANT => Variant,
            x => Other(x as usize),
        }
    }
}

impl ToGlib for Type {
    type GlibType = glib_ffi::GType;

    fn to_glib(&self) -> glib_ffi::GType {
        use self::Type::*;
        match *self {
            Invalid => gobject_ffi::G_TYPE_INVALID,
            Unit => gobject_ffi::G_TYPE_NONE,
            BaseInterface => gobject_ffi::G_TYPE_INTERFACE,
            I8 => gobject_ffi::G_TYPE_CHAR,
            U8 => gobject_ffi::G_TYPE_UCHAR,
            Bool => gobject_ffi::G_TYPE_BOOLEAN,
            I32 => gobject_ffi::G_TYPE_INT,
            U32 => gobject_ffi::G_TYPE_UINT,
            ILong => gobject_ffi::G_TYPE_LONG,
            ULong => gobject_ffi::G_TYPE_ULONG,
            I64 => gobject_ffi::G_TYPE_INT64,
            U64 => gobject_ffi::G_TYPE_UINT64,
            BaseEnum => gobject_ffi::G_TYPE_ENUM,
            BaseFlags => gobject_ffi::G_TYPE_FLAGS,
            F32 => gobject_ffi::G_TYPE_FLOAT,
            F64 => gobject_ffi::G_TYPE_DOUBLE,
            String => gobject_ffi::G_TYPE_STRING,
            Pointer => gobject_ffi::G_TYPE_POINTER,
            BaseBoxed => gobject_ffi::G_TYPE_BOXED,
            BaseParamSpec => gobject_ffi::G_TYPE_PARAM,
            BaseObject => gobject_ffi::G_TYPE_OBJECT,
            Variant => gobject_ffi::G_TYPE_VARIANT,
            Other(x) => x as glib_ffi::GType,
        }
    }
}

impl<'a> ToGlibContainerFromSlice<'a, *mut glib_ffi::GType> for Type {
    type Storage = Option<Vec<glib_ffi::GType>>;

    fn to_glib_none_from_slice(t: &'a [Type]) -> (*mut glib_ffi::GType, Self::Storage) {
        let mut vec = t.iter().map(|v| v.to_glib()).collect::<Vec<_>>();

        (vec.as_mut_ptr(), Some(vec))
    }

    fn to_glib_container_from_slice(t: &'a [Type]) -> (*mut glib_ffi::GType, Self::Storage) {
        (Self::to_glib_full_from_slice(t), None)
    }

    fn to_glib_full_from_slice(t: &[Type]) -> *mut glib_ffi::GType {
        if t.len() == 0 {
            return ptr::null_mut();
        }

        unsafe {
            let res = glib_ffi::g_malloc0(mem::size_of::<glib_ffi::GType>() * (t.len() + 1)) as *mut glib_ffi::GType;
            for (i, v) in t.iter().enumerate() {
                *res.offset(i as isize) = v.to_glib();
            }
            res
        }
    }
}

impl FromGlibContainerAsVec<Type, *const glib_ffi::GType> for Type {
    unsafe fn from_glib_none_num_as_vec(ptr: *const glib_ffi::GType, num: usize) -> Vec<Self> {
        if num == 0 || ptr.is_null() {
            return Vec::new();
        }

        let mut res = Vec::with_capacity(num);
        for i in 0..num {
            res.push(from_glib(*ptr.offset(i as isize)));
        }
        res
    }

    unsafe fn from_glib_container_num_as_vec(_: *const glib_ffi::GType, _: usize) -> Vec<Self> {
        // Can't really free a *const
        unimplemented!();
    }

    unsafe fn from_glib_full_num_as_vec(_: *const glib_ffi::GType, _: usize) -> Vec<Self> {
        // Can't really free a *const
        unimplemented!();
    }
}

impl FromGlibContainerAsVec<Type, *mut glib_ffi::GType> for Type {
    unsafe fn from_glib_none_num_as_vec(ptr: *mut glib_ffi::GType, num: usize) -> Vec<Self> {
        FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num)
    }

    unsafe fn from_glib_container_num_as_vec(ptr: *mut glib_ffi::GType, num: usize) -> Vec<Self> {
        let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
        glib_ffi::g_free(ptr as *mut _);
        res
    }

    unsafe fn from_glib_full_num_as_vec(ptr: *mut glib_ffi::GType, num: usize) -> Vec<Self> {
        FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num)
    }
}
<commit_msg>Remove completely unused InstanceType trait<commit_after>// Copyright 2015-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! Runtime type information.

use translate::{FromGlib, FromGlibContainerAsVec, ToGlib, ToGlibPtr, ToGlibContainerFromSlice, from_glib, from_glib_none};
use ffi as glib_ffi;
use gobject_ffi;

use std::fmt;
use std::mem;
use std::ptr;

/// A GLib or GLib-based library type
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Type {
    /// An invalid `Type` used as error return value in some functions
    Invalid,
    /// The fundamental type corresponding to the unit type `()`
    Unit,
    /// The fundamental type corresponding to `i8`
    I8,
    /// The fundamental type corresponding to `u8`
    U8,
    /// The fundamental type corresponding to `bool`
    Bool,
    /// The fundamental type corresponding to `i32`
    I32,
    /// The fundamental type corresponding to `u32`
    U32,
    /// The fundamental type corresponding to C `long`
    ILong,
    /// The fundamental type corresponding to C `unsigned long`
    ULong,
    /// The fundamental type corresponding to `i64`
    I64,
    /// The fundamental type corresponding to `u64`
    U64,
    /// The fundamental type corresponding to `f32`
    F32,
    /// The fundamental type corresponding to `f64`
    F64,
    /// The fundamental type corresponding to `String`
    String,
    /// The fundamental type corresponding to a pointer
    Pointer,
    /// The fundamental type of GVariant
    Variant,
    /// The fundamental type from which all interfaces are derived
    BaseInterface,
    /// The fundamental type from which all enumeration types are derived
    BaseEnum,
    /// The fundamental type from which all flags types are derived
    BaseFlags,
    /// The fundamental type from which all boxed types are derived
    BaseBoxed,
    /// The fundamental type from which all `GParamSpec` types are derived
    BaseParamSpec,
    /// The fundamental type from which all objects are derived
    BaseObject,
    /// A non-fundamental type identified by value of type `usize`
    Other(usize),
}

impl Type {
    pub fn name(&self) -> String {
        unsafe {
            from_glib_none(gobject_ffi::g_type_name(self.to_glib()))
        }
    }

    pub fn is_a(&self, other: &Type) -> bool {
        unsafe {
            from_glib(gobject_ffi::g_type_is_a(self.to_glib(), other.to_glib()))
        }
    }

    pub fn parent(&self) -> Option<Self> {
        unsafe {
            let parent = gobject_ffi::g_type_parent(self.to_glib());
            if parent == gobject_ffi::G_TYPE_INVALID {
                None
            } else {
                Some(from_glib(parent))
            }
        }
    }

    pub fn children(&self) -> Vec<Self> {
        unsafe {
            let mut n_children = 0u32;
            let children = gobject_ffi::g_type_children(self.to_glib(), &mut n_children);

            FromGlibContainerAsVec::from_glib_full_num_as_vec(children, n_children as usize)
        }
    }

    pub fn interfaces(&self) -> Vec<Self> {
        unsafe {
            let mut n_interfaces = 0u32;
            let interfaces = gobject_ffi::g_type_interfaces(self.to_glib(), &mut n_interfaces);

            FromGlibContainerAsVec::from_glib_full_num_as_vec(interfaces, n_interfaces as usize)
        }
    }
    pub fn interface_prerequisites(&self) -> Vec<Self> {
        unsafe {
            let mut n_prereqs = 0u32;
            let prereqs = gobject_ffi::g_type_interface_prerequisites(self.to_glib(), &mut n_prereqs);

            FromGlibContainerAsVec::from_glib_full_num_as_vec(prereqs, n_prereqs as usize)
        }
    }

    pub fn from_name<'a, P: Into<&'a str>>(name: P) -> Option<Self> {
        unsafe {
            let type_ = gobject_ffi::g_type_from_name(name.into().to_glib_none().0);
            if type_ == gobject_ffi::G_TYPE_INVALID {
                None
            } else {
                Some(from_glib(type_))
            }
        }
    }
}

impl fmt::Debug for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(&self.name())
    }
}

impl fmt::Display for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(&self.name())
    }
}

/// Types that are supported by GLib dynamic typing.
pub trait StaticType {
    /// Returns the type identifier of `Self`.
    fn static_type() -> Type;
}

impl<'a, T: ?Sized + StaticType> StaticType for &'a T {
    fn static_type() -> Type {
        T::static_type()
    }
}

macro_rules! builtin {
    ($name:ident, $val:ident) => {
        impl StaticType for $name {
            fn static_type() -> Type {
                Type::$val
            }
        }
    }
}

builtin!(bool, Bool);
builtin!(i8, I8);
builtin!(u8, U8);
builtin!(i32, I32);
builtin!(u32, U32);
builtin!(i64, I64);
builtin!(u64, U64);
builtin!(f32, F32);
builtin!(f64, F64);
builtin!(str, String);
builtin!(String, String);

impl<'a> StaticType for [&'a str] {
    fn static_type() -> Type {
        unsafe {
            from_glib(glib_ffi::g_strv_get_type())
        }
    }
}

impl StaticType for Vec<String> {
    fn static_type() -> Type {
        unsafe {
            from_glib(glib_ffi::g_strv_get_type())
        }
    }
}

#[inline]
pub unsafe fn instance_of<C: StaticType>(ptr: glib_ffi::gconstpointer) -> bool {
    from_glib(
        gobject_ffi::g_type_check_instance_is_a(
            ptr as *mut _, <C as StaticType>::static_type().to_glib()))
}

impl FromGlib<glib_ffi::GType> for Type {
    #[inline]
    fn from_glib(val: glib_ffi::GType) -> Type {
        use self::Type::*;
        match val {
            gobject_ffi::G_TYPE_INVALID => Invalid,
            gobject_ffi::G_TYPE_NONE => Unit,
            gobject_ffi::G_TYPE_INTERFACE => BaseInterface,
            gobject_ffi::G_TYPE_CHAR => I8,
            gobject_ffi::G_TYPE_UCHAR => U8,
            gobject_ffi::G_TYPE_BOOLEAN => Bool,
            gobject_ffi::G_TYPE_INT => I32,
            gobject_ffi::G_TYPE_UINT => U32,
            gobject_ffi::G_TYPE_LONG => ILong,
            gobject_ffi::G_TYPE_ULONG => ULong,
            gobject_ffi::G_TYPE_INT64 => I64,
            gobject_ffi::G_TYPE_UINT64 => U64,
            gobject_ffi::G_TYPE_ENUM => BaseEnum,
            gobject_ffi::G_TYPE_FLAGS => BaseFlags,
            gobject_ffi::G_TYPE_FLOAT => F32,
            gobject_ffi::G_TYPE_DOUBLE => F64,
            gobject_ffi::G_TYPE_STRING => String,
            gobject_ffi::G_TYPE_POINTER => Pointer,
            gobject_ffi::G_TYPE_BOXED => BaseBoxed,
            gobject_ffi::G_TYPE_PARAM => BaseParamSpec,
            gobject_ffi::G_TYPE_OBJECT => BaseObject,
            gobject_ffi::G_TYPE_VARIANT => Variant,
            x => Other(x as usize),
        }
    }
}

impl ToGlib for Type {
    type GlibType = glib_ffi::GType;

    fn to_glib(&self) -> glib_ffi::GType {
        use self::Type::*;
        match *self {
            Invalid => gobject_ffi::G_TYPE_INVALID,
            Unit => gobject_ffi::G_TYPE_NONE,
            BaseInterface => gobject_ffi::G_TYPE_INTERFACE,
            I8 => gobject_ffi::G_TYPE_CHAR,
            U8 => gobject_ffi::G_TYPE_UCHAR,
            Bool => gobject_ffi::G_TYPE_BOOLEAN,
            I32 => gobject_ffi::G_TYPE_INT,
            U32 => gobject_ffi::G_TYPE_UINT,
            ILong => gobject_ffi::G_TYPE_LONG,
            ULong => gobject_ffi::G_TYPE_ULONG,
            I64 => gobject_ffi::G_TYPE_INT64,
            U64 => gobject_ffi::G_TYPE_UINT64,
            BaseEnum => gobject_ffi::G_TYPE_ENUM,
            BaseFlags => gobject_ffi::G_TYPE_FLAGS,
            F32 => gobject_ffi::G_TYPE_FLOAT,
            F64 => gobject_ffi::G_TYPE_DOUBLE,
            String => gobject_ffi::G_TYPE_STRING,
            Pointer => gobject_ffi::G_TYPE_POINTER,
            BaseBoxed => gobject_ffi::G_TYPE_BOXED,
            BaseParamSpec => gobject_ffi::G_TYPE_PARAM,
            BaseObject => gobject_ffi::G_TYPE_OBJECT,
            Variant => gobject_ffi::G_TYPE_VARIANT,
            Other(x) => x as glib_ffi::GType,
        }
    }
}

impl<'a> ToGlibContainerFromSlice<'a, *mut glib_ffi::GType> for Type {
    type Storage = Option<Vec<glib_ffi::GType>>;

    fn to_glib_none_from_slice(t: &'a [Type]) -> (*mut glib_ffi::GType, Self::Storage) {
        let mut vec = t.iter().map(|v| v.to_glib()).collect::<Vec<_>>();

        (vec.as_mut_ptr(), Some(vec))
    }

    fn to_glib_container_from_slice(t: &'a [Type]) -> (*mut glib_ffi::GType, Self::Storage) {
        (Self::to_glib_full_from_slice(t), None)
    }

    fn to_glib_full_from_slice(t: &[Type]) -> *mut glib_ffi::GType {
        if t.len() == 0 {
            return ptr::null_mut();
        }

        unsafe {
            let res = glib_ffi::g_malloc0(mem::size_of::<glib_ffi::GType>() * (t.len() + 1)) as *mut glib_ffi::GType;
            for (i, v) in t.iter().enumerate() {
                *res.offset(i as isize) = v.to_glib();
            }
            res
        }
    }
}

impl FromGlibContainerAsVec<Type, *const glib_ffi::GType> for Type {
    unsafe fn from_glib_none_num_as_vec(ptr: *const glib_ffi::GType, num: usize) -> Vec<Self> {
        if num == 0 || ptr.is_null() {
            return Vec::new();
        }

        let mut res = Vec::with_capacity(num);
        for i in 0..num {
            res.push(from_glib(*ptr.offset(i as isize)));
        }
        res
    }

    unsafe fn from_glib_container_num_as_vec(_: *const glib_ffi::GType, _: usize) -> Vec<Self> {
        // Can't really free a *const
        unimplemented!();
    }

    unsafe fn from_glib_full_num_as_vec(_: *const glib_ffi::GType, _: usize) -> Vec<Self> {
        // Can't really free a *const
        unimplemented!();
    }
}

impl FromGlibContainerAsVec<Type, *mut glib_ffi::GType> for Type {
    unsafe fn from_glib_none_num_as_vec(ptr: *mut glib_ffi::GType, num: usize) -> Vec<Self> {
        FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num)
    }

    unsafe fn from_glib_container_num_as_vec(ptr: *mut glib_ffi::GType, num: usize) -> Vec<Self> {
        let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
        glib_ffi::g_free(ptr as *mut _);
        res
    }

    unsafe fn from_glib_full_num_as_vec(ptr: *mut glib_ffi::GType, num: usize) -> Vec<Self> {
        FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num)
    }
}
<|endoftext|>


<commit_before>use errors;

// see OSC Type Tag String: http://opensoundcontrol.org/spec-1_0
// padding: zero bytes (n*4)

#[derive(Debug)]
pub enum OscType {
    Int(i32),
    Float(f32),
    String(String),
    Blob(Vec<u8>),
    Time(u32, u32),
    // nonstandard argument types
    // ignore them if not implemented
    Long(i64),
    Double(f64),
    Char(u8),
    Color(u32), // byte-order: RGBA
    Midi(OscMidiType),
    True,
    False,
    Nil,
    Inf,
    Array(Vec<OscType>),
}

#[derive(Debug)]
pub struct OscMidiType {
    port: u8,
    status: u8,
    data1: u8, // maybe use an enum for data?
    data2: u8,
}

/// An *osc packet* can contain an *osc message* or a bundle of nested messages
/// which is called *osc bundle*.
#[derive(Debug)]
pub enum OscPacket {
    Message(OscMessage),
    Bundle(OscBundle),
}

#[derive(Debug)]
pub struct OscMessage {
    pub addr: String,
    pub args: Option<Vec<OscType>>,
}

#[derive(Debug)]
pub struct OscBundle {
    pub timetag: OscType,
    pub content: Vec<OscPacket>,
}

pub type OscResult<T> = Result<T, errors::OscError>;
<commit_msg>Rename `OscMidiType` to `OscMidiMessage`<commit_after>use errors;

// see OSC Type Tag String: http://opensoundcontrol.org/spec-1_0
// padding: zero bytes (n*4)

#[derive(Debug)]
pub enum OscType {
    Int(i32),
    Float(f32),
    String(String),
    Blob(Vec<u8>),
    Time(u32, u32),
    // nonstandard argument types
    // ignore them if not implemented
    Long(i64),
    Double(f64),
    Char(u8),
    Color(u32), // byte-order: RGBA
    True,
    False,
    Midi(OscMidiMessage),
    Nil,
    Inf,
    Array(Vec<OscType>),
}

#[derive(Debug)]
pub struct OscMidiMessage {
    pub port: u8,
    pub status: u8,
    pub data1: u8, // maybe use an enum for data?
    pub data2: u8,
}

/// An *osc packet* can contain an *osc message* or a bundle of nested messages
/// which is called *osc bundle*.
#[derive(Debug)]
pub enum OscPacket {
    Message(OscMessage),
    Bundle(OscBundle),
}

#[derive(Debug)]
pub struct OscMessage {
    pub addr: String,
    pub args: Option<Vec<OscType>>,
}

#[derive(Debug)]
pub struct OscBundle {
    pub timetag: OscType,
    pub content: Vec<OscPacket>,
}

pub type OscResult<T> = Result<T, errors::OscError>;
<|endoftext|>


<commit_before>extern crate c_ares_sys;
extern crate libc;

use std::net::{Ipv4Addr, Ipv6Addr};
use std::os::unix::io;

/// Flags that may be passed when initializing a channel.
#[derive(Debug, Clone, Copy)]
pub enum Flag {
    /// Always use TCP queries (the "virtual circuit") instead of UDP queries.
    /// Normally, TCP is only used if a UDP query yields a truncated result.
    USEVC = c_ares_sys::ARES_FLAG_USEVC as isize,

    /// Only query the first server in the list of servers to query.
    PRIMARY = c_ares_sys::ARES_FLAG_PRIMARY as isize,

    /// If a truncated response to a UDP query is received, do not fall back
    /// to TCP; simply continue on with the truncated response.
    IGNTC = c_ares_sys::ARES_FLAG_IGNTC as isize,

    /// Do not set the "recursion desired" bit on outgoing queries, so that
    /// the name server being contacted will not try to fetch the answer from
    /// other servers if it doesn't know the answer locally.
    NORECURSE = c_ares_sys::ARES_FLAG_NORECURSE as isize,

    /// Do not close communications sockets when the number of active queries
    /// drops to zero.
    STAYOPEN = c_ares_sys::ARES_FLAG_STAYOPEN as isize,

    /// Do not use the default search domains; only query hostnames as-is or as
    /// aliases.
    NOSEARCH = c_ares_sys::ARES_FLAG_NOSEARCH as isize,

    /// Do not honor the HOSTALIASES environment variable, which normally
    /// specifies a file of hostname translations.
    NOALIASES = c_ares_sys::ARES_FLAG_NOALIASES as isize,

    /// Do not discard responses with the SERVFAIL, NOTIMP, or REFUSED response
    /// code or responses whose questions don't match the questions in the
    /// request. Primarily useful for writing clients which might be used to
    /// test or debug name servers.
    NOCHECKRESP = c_ares_sys::ARES_FLAG_NOCHECKRESP as isize,
    EDNS = c_ares_sys::ARES_FLAG_EDNS as isize,
}

/// An invalid file descriptor.  Use this to represent 'no action' when calling
/// `process_fd()` on a channel.
pub const INVALID_FD: io::RawFd = c_ares_sys::ARES_SOCKET_BAD as io::RawFd;

/// Error codes that the library might return.  Use `str_error()` to convert an
/// error code into a description.
#[derive(Debug, Clone, Copy)]
pub enum AresError {
    ENODATA = c_ares_sys::ARES_ENODATA as isize,
    EFORMERR = c_ares_sys::ARES_EFORMERR  as isize,
    ESERVFAIL = c_ares_sys::ARES_ESERVFAIL as isize,
    ENOTFOUND = c_ares_sys::ARES_ENOTFOUND as isize,
    ENOTIMP = c_ares_sys::ARES_ENOTIMP as isize,
    EREFUSED = c_ares_sys::ARES_EREFUSED as isize,
    EBADQUERY = c_ares_sys::ARES_EBADQUERY as isize,
    EBADNAME = c_ares_sys::ARES_EBADNAME as isize,
    EBADFAMILY = c_ares_sys::ARES_EBADFAMILY as isize,
    EBADRESP = c_ares_sys::ARES_EBADRESP as isize,
    ECONNREFUSED = c_ares_sys::ARES_ECONNREFUSED as isize,
    ETIMEOUT = c_ares_sys::ARES_ETIMEOUT as isize,
    EOF = c_ares_sys::ARES_EOF as isize,
    EFILE = c_ares_sys::ARES_EFILE as isize,
    ENOMEM = c_ares_sys::ARES_ENOMEM as isize,
    EDESTRUCTION = c_ares_sys::ARES_EDESTRUCTION as isize,
    EBADSTR = c_ares_sys::ARES_EBADSTR as isize,
    EBADFLAGS = c_ares_sys::ARES_EBADFLAGS as isize,
    ENONAME = c_ares_sys::ARES_ENONAME as isize,
    EBADHINTS = c_ares_sys::ARES_EBADHINTS as isize,
    ENOTINITIALIZED = c_ares_sys::ARES_ENOTINITIALIZED as isize,
    ELOADIPHLPAPI = c_ares_sys::ARES_ELOADIPHLPAPI as isize,
    EADDRGETNETWORKPARAMS = c_ares_sys::ARES_EADDRGETNETWORKPARAMS as isize,
    ECANCELLED = c_ares_sys::ARES_ECANCELLED as isize,
    UNKNOWN,
}

/// The result of a successful lookup for an A record.
#[derive(Debug, Clone)]
pub struct AResult {
    /// The IP addresses returned by the lookup.
    pub ip_addrs: Vec<Ipv4Addr>,
}

/// The result of a successful lookup for an AAAA record.
#[derive(Debug, Clone)]
pub struct AAAAResult {
    /// The IP addresses returned by the lookup.
    pub ip_addrs: Vec<Ipv6Addr>,
}

#[repr(C)]
pub struct hostent {
    pub h_name: *mut libc::c_char,
    pub h_aliases: *mut *mut libc::c_char,
    pub h_addrtype: libc::c_int,
    pub h_length: libc::c_int,
    pub h_addr_list: *mut *mut libc::c_char,
}

// See arpa/nameser.h
pub enum QueryType {
    A = 1,
    AAAA = 28,
}

// See arpa/nameser.h
pub enum DnsClass {
   IN = 1,
}
<commit_msg>Document EDNS flag<commit_after>extern crate c_ares_sys;
extern crate libc;

use std::net::{Ipv4Addr, Ipv6Addr};
use std::os::unix::io;

/// Flags that may be passed when initializing a channel.
#[derive(Debug, Clone, Copy)]
pub enum Flag {
    /// Always use TCP queries (the "virtual circuit") instead of UDP queries.
    /// Normally, TCP is only used if a UDP query yields a truncated result.
    USEVC = c_ares_sys::ARES_FLAG_USEVC as isize,

    /// Only query the first server in the list of servers to query.
    PRIMARY = c_ares_sys::ARES_FLAG_PRIMARY as isize,

    /// If a truncated response to a UDP query is received, do not fall back
    /// to TCP; simply continue on with the truncated response.
    IGNTC = c_ares_sys::ARES_FLAG_IGNTC as isize,

    /// Do not set the "recursion desired" bit on outgoing queries, so that
    /// the name server being contacted will not try to fetch the answer from
    /// other servers if it doesn't know the answer locally.
    NORECURSE = c_ares_sys::ARES_FLAG_NORECURSE as isize,

    /// Do not close communications sockets when the number of active queries
    /// drops to zero.
    STAYOPEN = c_ares_sys::ARES_FLAG_STAYOPEN as isize,

    /// Do not use the default search domains; only query hostnames as-is or as
    /// aliases.
    NOSEARCH = c_ares_sys::ARES_FLAG_NOSEARCH as isize,

    /// Do not honor the HOSTALIASES environment variable, which normally
    /// specifies a file of hostname translations.
    NOALIASES = c_ares_sys::ARES_FLAG_NOALIASES as isize,

    /// Do not discard responses with the SERVFAIL, NOTIMP, or REFUSED response
    /// code or responses whose questions don't match the questions in the
    /// request. Primarily useful for writing clients which might be used to
    /// test or debug name servers.
    NOCHECKRESP = c_ares_sys::ARES_FLAG_NOCHECKRESP as isize,

    /// Use Extension Mechanisms for DNS.
    EDNS = c_ares_sys::ARES_FLAG_EDNS as isize,
}

/// An invalid file descriptor.  Use this to represent 'no action' when calling
/// `process_fd()` on a channel.
pub const INVALID_FD: io::RawFd = c_ares_sys::ARES_SOCKET_BAD as io::RawFd;

/// Error codes that the library might return.  Use `str_error()` to convert an
/// error code into a description.
#[derive(Debug, Clone, Copy)]
pub enum AresError {
    ENODATA = c_ares_sys::ARES_ENODATA as isize,
    EFORMERR = c_ares_sys::ARES_EFORMERR  as isize,
    ESERVFAIL = c_ares_sys::ARES_ESERVFAIL as isize,
    ENOTFOUND = c_ares_sys::ARES_ENOTFOUND as isize,
    ENOTIMP = c_ares_sys::ARES_ENOTIMP as isize,
    EREFUSED = c_ares_sys::ARES_EREFUSED as isize,
    EBADQUERY = c_ares_sys::ARES_EBADQUERY as isize,
    EBADNAME = c_ares_sys::ARES_EBADNAME as isize,
    EBADFAMILY = c_ares_sys::ARES_EBADFAMILY as isize,
    EBADRESP = c_ares_sys::ARES_EBADRESP as isize,
    ECONNREFUSED = c_ares_sys::ARES_ECONNREFUSED as isize,
    ETIMEOUT = c_ares_sys::ARES_ETIMEOUT as isize,
    EOF = c_ares_sys::ARES_EOF as isize,
    EFILE = c_ares_sys::ARES_EFILE as isize,
    ENOMEM = c_ares_sys::ARES_ENOMEM as isize,
    EDESTRUCTION = c_ares_sys::ARES_EDESTRUCTION as isize,
    EBADSTR = c_ares_sys::ARES_EBADSTR as isize,
    EBADFLAGS = c_ares_sys::ARES_EBADFLAGS as isize,
    ENONAME = c_ares_sys::ARES_ENONAME as isize,
    EBADHINTS = c_ares_sys::ARES_EBADHINTS as isize,
    ENOTINITIALIZED = c_ares_sys::ARES_ENOTINITIALIZED as isize,
    ELOADIPHLPAPI = c_ares_sys::ARES_ELOADIPHLPAPI as isize,
    EADDRGETNETWORKPARAMS = c_ares_sys::ARES_EADDRGETNETWORKPARAMS as isize,
    ECANCELLED = c_ares_sys::ARES_ECANCELLED as isize,
    UNKNOWN,
}

/// The result of a successful lookup for an A record.
#[derive(Debug, Clone)]
pub struct AResult {
    /// The IP addresses returned by the lookup.
    pub ip_addrs: Vec<Ipv4Addr>,
}

/// The result of a successful lookup for an AAAA record.
#[derive(Debug, Clone)]
pub struct AAAAResult {
    /// The IP addresses returned by the lookup.
    pub ip_addrs: Vec<Ipv6Addr>,
}

#[repr(C)]
pub struct hostent {
    pub h_name: *mut libc::c_char,
    pub h_aliases: *mut *mut libc::c_char,
    pub h_addrtype: libc::c_int,
    pub h_length: libc::c_int,
    pub h_addr_list: *mut *mut libc::c_char,
}

// See arpa/nameser.h
pub enum QueryType {
    A = 1,
    AAAA = 28,
}

// See arpa/nameser.h
pub enum DnsClass {
   IN = 1,
}
<|endoftext|>