<commit_before>use std::f32::consts::*;

use Vector;
use scene::Scene;
use ray::Ray;
use colour::Colourf;
use integrator::Integrator;
use geometry::TextureCoordinate;
use na::{Norm, Dot, zero};
use na;

pub struct Whitted {
    pub max_ray_depth: u8,
}

impl Whitted {
    pub fn new(n: u8) -> Whitted {
        Whitted { max_ray_depth: n }
    }
}

/// Compute the reflection direction
fn reflect(i: &Vector, n: &Vector) -> Vector {
    (*i - *n * 2.0 * n.dot(i)).normalize()
}

/// Compute the refraction direction
fn refract(i: &Vector, n: &Vector, ior: f32) -> Vector {
    let mut cos_i = na::clamp(i.dot(n), -1.0, 1.0);
    let (etai, etat, n_refr) = if cos_i < 0.0 {
        cos_i = -cos_i;
        (1.0, ior, *n)
    } else {
        (ior, 1.0, -*n)
    };

    let eta = etai / etat;
    let k = 1.0 - eta * eta * (1.0 - cos_i * cos_i);

    if k > 0.0 {
        *i * eta + n_refr * (eta * cos_i - k.sqrt())
    } else {
        zero()
    }
}

/// Compute the Fresnel coefficient
fn fresnel(i: &Vector, n: &Vector, ior: f32) -> f32 {
    let mut cosi = na::clamp(i.dot(n), -1.0, 1.0);
    let (etai, etat) = if cosi > 0.0 { (ior, 1.0) } else { (1.0, ior) };

    let sint = etai / etat * (1.0 - cosi * cosi).max(0.0).sqrt();
    if sint >= 1.0 {
        1.0
    } else {
        let cost = (1.0 - sint * sint).max(0.0).sqrt();
        cosi = cosi.abs();
        let r_s = ((etat * cosi) - (etai * cost)) / ((etat * cosi) + (etai * cost));
        let r_p = ((etai * cosi) - (etat * cost)) / ((etai * cosi) + (etat * cost));
        (r_s * r_s + r_p * r_p) / 2.0
    }
}

fn fmod(x: f32) -> f32 {
    x - x.floor()
}

fn pattern(tex_coord: &TextureCoordinate, scale_u: f32, scale_v: f32) -> f32 {
    let p = (fmod(tex_coord.u * scale_u) < 0.5) ^ (fmod(tex_coord.v * scale_v) < 0.5);
    if p { 1.0 } else { 0.5 }
}

impl Integrator for Whitted {
    fn illumination(&self, scene: &Scene, ray: &mut Ray) -> Colourf {
        let mut colour = Colourf::black();

        if ray.depth > self.max_ray_depth {
            return Colourf::rgb(0.0, 0.0, 0.5);
        }

        if let Some(intersection) = scene.intersect(ray) {
            let hit = intersection.hit;
            let mat = &hit.material;
            let n = intersection.dg.nhit;
            let p = intersection.dg.phit;

            // colour += Colourf::grey(w_o.dot(&n));
            if mat.reflection == 0.0 && mat.transparency == 0.0 {
                // Diffuse material
                for light in &scene.lights {
                    let shading_info = light.shading_info(&p);
                    let mut shadow_ray = ray.spawn(p, shading_info.w_i);
                    shadow_ray.t_max = shading_info.light_distance;
                    if let None = scene.intersect(&mut shadow_ray) {
                        let diffuse = mat.surface_colour * FRAC_1_PI * shading_info.l_i *
                                      shading_info.w_i.dot(&n).max(0.0) *
                                      pattern(&intersection.dg.tex_coord, 10.0, 10.0);
                        colour += diffuse;
                    }
                }
            } else {
                // Fresnel reflection / refraction
                let kr = fresnel(&ray.dir, &n, 1.5);
                let bias = if ray.dir.dot(&n) < 0.0 {
                    // outside
                    1e-4 * n
                } else {
                    // inside
                    -1e-4 * n
                };

                if kr < 1.0 {
                    // refraction
                    let refr_dir = refract(&ray.dir, &n, 1.5);
                    let mut refr_ray = ray.spawn(p - bias, refr_dir);
                    colour += self.illumination(scene, &mut refr_ray) * (1.0 - kr);
                }
                // Reflection
                let mut refl_ray = ray.spawn(p + bias, reflect(&ray.dir, &n));
                let refl = self.illumination(scene, &mut refl_ray);
                colour += refl * kr;
            }

        } else {
            return Colourf::rgb(0.0, 0.0, 0.5);
            // return scene.atmosphere.compute_incident_light(ray);
        }

        colour
    }
}
<commit_msg>Add skydome back<commit_after>use std::f32::consts::*;

use Vector;
use scene::Scene;
use ray::Ray;
use colour::Colourf;
use integrator::Integrator;
use geometry::TextureCoordinate;
use na::{Norm, Dot, zero};
use na;

pub struct Whitted {
    pub max_ray_depth: u8,
}

impl Whitted {
    pub fn new(n: u8) -> Whitted {
        Whitted { max_ray_depth: n }
    }
}

/// Compute the reflection direction
fn reflect(i: &Vector, n: &Vector) -> Vector {
    (*i - *n * 2.0 * n.dot(i)).normalize()
}

/// Compute the refraction direction
fn refract(i: &Vector, n: &Vector, ior: f32) -> Vector {
    let mut cos_i = na::clamp(i.dot(n), -1.0, 1.0);
    let (etai, etat, n_refr) = if cos_i < 0.0 {
        cos_i = -cos_i;
        (1.0, ior, *n)
    } else {
        (ior, 1.0, -*n)
    };

    let eta = etai / etat;
    let k = 1.0 - eta * eta * (1.0 - cos_i * cos_i);

    if k > 0.0 {
        *i * eta + n_refr * (eta * cos_i - k.sqrt())
    } else {
        zero()
    }
}

/// Compute the Fresnel coefficient
fn fresnel(i: &Vector, n: &Vector, ior: f32) -> f32 {
    let mut cosi = na::clamp(i.dot(n), -1.0, 1.0);
    let (etai, etat) = if cosi > 0.0 { (ior, 1.0) } else { (1.0, ior) };

    let sint = etai / etat * (1.0 - cosi * cosi).max(0.0).sqrt();
    if sint >= 1.0 {
        1.0
    } else {
        let cost = (1.0 - sint * sint).max(0.0).sqrt();
        cosi = cosi.abs();
        let r_s = ((etat * cosi) - (etai * cost)) / ((etat * cosi) + (etai * cost));
        let r_p = ((etai * cosi) - (etat * cost)) / ((etai * cosi) + (etat * cost));
        (r_s * r_s + r_p * r_p) / 2.0
    }
}

fn fmod(x: f32) -> f32 {
    x - x.floor()
}

fn pattern(tex_coord: &TextureCoordinate, scale_u: f32, scale_v: f32) -> f32 {
    let p = (fmod(tex_coord.u * scale_u) < 0.5) ^ (fmod(tex_coord.v * scale_v) < 0.5);
    if p { 1.0 } else { 0.5 }
}

impl Integrator for Whitted {
    fn illumination(&self, scene: &Scene, ray: &mut Ray) -> Colourf {
        let mut colour = Colourf::black();

        if ray.depth > self.max_ray_depth {
            return Colourf::rgb(0.0, 0.0, 0.5);
        }

        if let Some(intersection) = scene.intersect(ray) {
            let hit = intersection.hit;
            let mat = &hit.material;
            let n = intersection.dg.nhit;
            let p = intersection.dg.phit;

            // colour += Colourf::grey(w_o.dot(&n));
            if mat.reflection == 0.0 && mat.transparency == 0.0 {
                // Diffuse material
                for light in &scene.lights {
                    let shading_info = light.shading_info(&p);
                    let mut shadow_ray = ray.spawn(p, shading_info.w_i);
                    shadow_ray.t_max = shading_info.light_distance;
                    if let None = scene.intersect(&mut shadow_ray) {
                        let diffuse = mat.surface_colour * FRAC_1_PI * shading_info.l_i *
                                      shading_info.w_i.dot(&n).max(0.0) *
                                      pattern(&intersection.dg.tex_coord, 10.0, 10.0);
                        colour += diffuse;
                    }
                }
            } else {
                // Fresnel reflection / refraction
                let kr = fresnel(&ray.dir, &n, 1.5);
                let bias = if ray.dir.dot(&n) < 0.0 {
                    // outside
                    1e-4 * n
                } else {
                    // inside
                    -1e-4 * n
                };

                if kr < 1.0 {
                    // refraction
                    let refr_dir = refract(&ray.dir, &n, 1.5);
                    let mut refr_ray = ray.spawn(p - bias, refr_dir);
                    colour += self.illumination(scene, &mut refr_ray) * (1.0 - kr);
                }
                // Reflection
                let mut refl_ray = ray.spawn(p + bias, reflect(&ray.dir, &n));
                let refl = self.illumination(scene, &mut refl_ray);
                colour += refl * kr;
            }

        } else {
            // return Colourf::rgb(0.0, 0.0, 0.5);
            return scene.atmosphere.compute_incident_light(ray);
        }

        colour
    }
}
<|endoftext|>


<commit_before>//! A generic cursor implementation merging multiple cursors.

use super::Cursor;

/// Provides a cursor interface over a list of cursors.
///
/// The `CursorList` tracks the indices of cursors with the minimum key, and the the indices of cursors with
/// the minimum key and minimum value. It performs no clever management of these sets otherwise.
#[derive(Debug)]
pub struct CursorList<K, V, T, R, C: Cursor<K, V, T, R>> {
	_phantom: ::std::marker::PhantomData<(K, V, T, R)>,
	cursors: Vec<C>,
	min_key: Vec<usize>,
	min_val: Vec<usize>,
}

impl<K, V, T, R, C: Cursor<K, V, T, R>> CursorList<K, V, T, R, C> where K: Ord, V: Ord {
	/// Creates a new cursor list from pre-existing cursors.
	pub fn new(cursors: Vec<C>, storage: &Vec<C::Storage>) -> Self {

		let mut result = CursorList {
			_phantom: ::std::marker::PhantomData,
			cursors: cursors.into_iter().collect(),
			min_key: Vec::new(),
			min_val: Vec::new(),
		};

		result.minimize_keys(storage);
		result
	}

	// Initialize min_key with the indices of cursors with the minimum key.
	fn minimize_keys(&mut self, storage: &Vec<C::Storage>) {

		self.min_key.clear();

		// Determine the index of the cursor with minimum key.
		let mut min_key_index: Option<usize> = None;
		for (index, cursor) in self.cursors.iter().enumerate() {
			if cursor.key_valid(&storage[index]) {
				if let Some(min_index) = min_key_index {
					if cursor.key(&storage[index]).lt(self.cursors[min_index].key(&storage[min_index])) {
						min_key_index = Some(index);
					}
				}
				else {
					min_key_index = Some(index);
				}
			}
		}
		// Install each index with equal key.
		if let Some(min_index) = min_key_index {
			for (index, cursor) in self.cursors.iter().enumerate() {
				if cursor.key_valid(&storage[index]) {
					if cursor.key(&storage[index]).eq(self.cursors[min_index].key(&storage[min_index])) {
						self.min_key.push(index);
					}
				}
			}
		}

		self.minimize_vals(storage);
	}

	// Initialize min_val with the indices of minimum key cursors with the minimum value.
	fn minimize_vals(&mut self, storage: &Vec<C::Storage>) {

		self.min_val.clear();

		// Determine the index of the cursor with minimum value.
		let mut min_val_index: Option<usize> = None;
		for &index in self.min_key.iter() {
			if self.cursors[index].val_valid(&storage[index]) {
				if let Some(min_index) = min_val_index {
					if self.cursors[index].val(&storage[index]).lt(self.cursors[min_index].val(&storage[min_index])) {
						min_val_index = Some(index);
					}
				}
				else {
					min_val_index = Some(index);
				}
			}
		}
		// Install each index with equal value.
		if let Some(min_index) = min_val_index {
			for &index in self.min_key.iter() {
				if self.cursors[index].val_valid(&storage[index]) {
					if self.cursors[index].val(&storage[index]).eq(self.cursors[min_index].val(&storage[min_index])) {
						self.min_val.push(index);
					}
				}
			}
		}
	}
}

impl<K, V, T, R, C: Cursor<K, V, T, R>> Cursor<K, V, T, R> for CursorList<K, V, T, R, C>
where
	K: Ord,
	V: Ord {

	type Storage = Vec<C::Storage>;

	// validation methods
	fn key_valid(&self, _storage: &Self::Storage) -> bool { !self.min_key.is_empty() }
	fn val_valid(&self, _storage: &Self::Storage) -> bool { !self.min_val.is_empty() }

	// accessors
	fn key<'a>(&self, storage: &'a Self::Storage) -> &'a K {
		debug_assert!(self.key_valid(storage));
		assert!(self.cursors[self.min_key[0]].key_valid(&storage[self.min_key[0]]));
		self.cursors[self.min_key[0]].key(&storage[self.min_key[0]])
	}
	fn val<'a>(&self, storage: &'a Self::Storage) -> &'a V {
		debug_assert!(self.key_valid(storage));
		debug_assert!(self.val_valid(storage));
		assert!(self.cursors[self.min_val[0]].val_valid(&storage[self.min_val[0]]));
		self.cursors[self.min_val[0]].val(&storage[self.min_val[0]])
	}
	fn map_times<L: FnMut(&T, R)>(&mut self, storage: &Self::Storage, mut logic: L) {
		for &index in self.min_val.iter() {
			self.cursors[index].map_times(&storage[index], |t,d| logic(t,d));
		}
	}

	// key methods
	fn step_key(&mut self, storage: &Self::Storage) {
		for &index in self.min_key.iter() {
			self.cursors[index].step_key(&storage[index]);
		}
		self.minimize_keys(storage);
	}
	fn seek_key(&mut self, storage: &Self::Storage, key: &K) {
		for index in 0 .. self.cursors.len() {
			self.cursors[index].seek_key(&storage[index], key);
		}
		self.minimize_keys(storage);
	}

	// value methods
	fn step_val(&mut self, storage: &Self::Storage) {
		for &index in self.min_val.iter() {
			self.cursors[index].step_val(&storage[index]);
		}
		self.minimize_vals(storage);
	}
	fn seek_val(&mut self, storage: &Self::Storage, val: &V) {
		for &index in self.min_key.iter() {
			self.cursors[index].seek_val(&storage[index], val);
		}
		self.minimize_vals(storage);
	}

	// rewinding methods
	fn rewind_keys(&mut self, storage: &Self::Storage) {
		for index in 0 .. self.cursors.len() {
			self.cursors[index].rewind_keys(&storage[index]);
		}
		self.minimize_keys(storage);
	}
	fn rewind_vals(&mut self, storage: &Self::Storage) {
		for &index in self.min_key.iter() {
			self.cursors[index].rewind_vals(&storage[index]);
		}
		self.minimize_vals(storage);
	}
}<commit_msg>tabs -> spaces<commit_after>//! A generic cursor implementation merging multiple cursors.

use super::Cursor;

/// Provides a cursor interface over a list of cursors.
///
/// The `CursorList` tracks the indices of cursors with the minimum key, and the the indices of cursors with
/// the minimum key and minimum value. It performs no clever management of these sets otherwise.
#[derive(Debug)]
pub struct CursorList<K, V, T, R, C: Cursor<K, V, T, R>> {
    _phantom: ::std::marker::PhantomData<(K, V, T, R)>,
    cursors: Vec<C>,
    min_key: Vec<usize>,
    min_val: Vec<usize>,
}

impl<K, V, T, R, C: Cursor<K, V, T, R>> CursorList<K, V, T, R, C> where K: Ord, V: Ord {
    /// Creates a new cursor list from pre-existing cursors.
    pub fn new(cursors: Vec<C>, storage: &Vec<C::Storage>) -> Self {

        let mut result = CursorList {
            _phantom: ::std::marker::PhantomData,
            cursors: cursors.into_iter().collect(),
            min_key: Vec::new(),
            min_val: Vec::new(),
        };

        result.minimize_keys(storage);
        result
    }

    // Initialize min_key with the indices of cursors with the minimum key.
    fn minimize_keys(&mut self, storage: &Vec<C::Storage>) {

        self.min_key.clear();

        // Determine the index of the cursor with minimum key.
        let mut min_key_index: Option<usize> = None;
        for (index, cursor) in self.cursors.iter().enumerate() {
            if cursor.key_valid(&storage[index]) {
                if let Some(min_index) = min_key_index {
                    if cursor.key(&storage[index]).lt(self.cursors[min_index].key(&storage[min_index])) {
                        min_key_index = Some(index);
                    }
                }
                else {
                    min_key_index = Some(index);
                }
            }
        }
        // Install each index with equal key.
        if let Some(min_index) = min_key_index {
            for (index, cursor) in self.cursors.iter().enumerate() {
                if cursor.key_valid(&storage[index]) {
                    if cursor.key(&storage[index]).eq(self.cursors[min_index].key(&storage[min_index])) {
                        self.min_key.push(index);
                    }
                }
            }
        }

        self.minimize_vals(storage);
    }

    // Initialize min_val with the indices of minimum key cursors with the minimum value.
    fn minimize_vals(&mut self, storage: &Vec<C::Storage>) {

        self.min_val.clear();

        // Determine the index of the cursor with minimum value.
        let mut min_val_index: Option<usize> = None;
        for &index in self.min_key.iter() {
            if self.cursors[index].val_valid(&storage[index]) {
                if let Some(min_index) = min_val_index {
                    if self.cursors[index].val(&storage[index]).lt(self.cursors[min_index].val(&storage[min_index])) {
                        min_val_index = Some(index);
                    }
                }
                else {
                    min_val_index = Some(index);
                }
            }
        }
        // Install each index with equal value.
        if let Some(min_index) = min_val_index {
            for &index in self.min_key.iter() {
                if self.cursors[index].val_valid(&storage[index]) {
                    if self.cursors[index].val(&storage[index]).eq(self.cursors[min_index].val(&storage[min_index])) {
                        self.min_val.push(index);
                    }
                }
            }
        }
    }
}

impl<K, V, T, R, C: Cursor<K, V, T, R>> Cursor<K, V, T, R> for CursorList<K, V, T, R, C>
where
    K: Ord,
    V: Ord {

    type Storage = Vec<C::Storage>;

    // validation methods
    fn key_valid(&self, _storage: &Self::Storage) -> bool { !self.min_key.is_empty() }
    fn val_valid(&self, _storage: &Self::Storage) -> bool { !self.min_val.is_empty() }

    // accessors
    fn key<'a>(&self, storage: &'a Self::Storage) -> &'a K {
        debug_assert!(self.key_valid(storage));
        assert!(self.cursors[self.min_key[0]].key_valid(&storage[self.min_key[0]]));
        self.cursors[self.min_key[0]].key(&storage[self.min_key[0]])
    }
    fn val<'a>(&self, storage: &'a Self::Storage) -> &'a V {
        debug_assert!(self.key_valid(storage));
        debug_assert!(self.val_valid(storage));
        assert!(self.cursors[self.min_val[0]].val_valid(&storage[self.min_val[0]]));
        self.cursors[self.min_val[0]].val(&storage[self.min_val[0]])
    }
    fn map_times<L: FnMut(&T, R)>(&mut self, storage: &Self::Storage, mut logic: L) {
        for &index in self.min_val.iter() {
            self.cursors[index].map_times(&storage[index], |t,d| logic(t,d));
        }
    }

    // key methods
    fn step_key(&mut self, storage: &Self::Storage) {
        for &index in self.min_key.iter() {
            self.cursors[index].step_key(&storage[index]);
        }
        self.minimize_keys(storage);
    }
    fn seek_key(&mut self, storage: &Self::Storage, key: &K) {
        for index in 0 .. self.cursors.len() {
            self.cursors[index].seek_key(&storage[index], key);
        }
        self.minimize_keys(storage);
    }

    // value methods
    fn step_val(&mut self, storage: &Self::Storage) {
        for &index in self.min_val.iter() {
            self.cursors[index].step_val(&storage[index]);
        }
        self.minimize_vals(storage);
    }
    fn seek_val(&mut self, storage: &Self::Storage, val: &V) {
        for &index in self.min_key.iter() {
            self.cursors[index].seek_val(&storage[index], val);
        }
        self.minimize_vals(storage);
    }

    // rewinding methods
    fn rewind_keys(&mut self, storage: &Self::Storage) {
        for index in 0 .. self.cursors.len() {
            self.cursors[index].rewind_keys(&storage[index]);
        }
        self.minimize_keys(storage);
    }
    fn rewind_vals(&mut self, storage: &Self::Storage) {
        for &index in self.min_key.iter() {
            self.cursors[index].rewind_vals(&storage[index]);
        }
        self.minimize_vals(storage);
    }
}<|endoftext|>


<commit_before>// This file is part of the uutils coreutils package.
//
// (c) Alex Lyon <arcterus@mail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (vars) fperm srwx

use libc::{mode_t, S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR};

pub fn parse_numeric(fperm: u32, mut mode: &str) -> Result<u32, String> {
    let (op, pos) = parse_op(mode, Some('='))?;
    mode = mode[pos..].trim().trim_start_matches('0');
    if mode.len() > 4 {
        Err(format!("mode is too large ({} > 7777)", mode))
    } else {
        match u32::from_str_radix(mode, 8) {
            Ok(change) => Ok(match op {
                '+' => fperm | change,
                '-' => fperm & !change,
                '=' => change,
                _ => unreachable!(),
            }),
            Err(err) => Err(err.to_string()),
        }
    }
}

pub fn parse_symbolic(
    mut fperm: u32,
    mut mode: &str,
    considering_dir: bool,
) -> Result<u32, String> {
    #[cfg(unix)]
    use libc::umask;

    let (mask, pos) = parse_levels(mode);
    if pos == mode.len() {
        return Err(format!("invalid mode ({})", mode));
    }
    let respect_umask = pos == 0;
    let last_umask = unsafe { umask(0) };
    mode = &mode[pos..];
    while !mode.is_empty() {
        let (op, pos) = parse_op(mode, None)?;
        mode = &mode[pos..];
        let (mut srwx, pos) = parse_change(mode, fperm, considering_dir);
        if respect_umask {
            srwx &= !(last_umask as u32);
        }
        mode = &mode[pos..];
        match op {
            '+' => fperm |= srwx & mask,
            '-' => fperm &= !(srwx & mask),
            '=' => fperm = (fperm & !mask) | (srwx & mask),
            _ => unreachable!(),
        }
    }
    unsafe {
        umask(last_umask);
    }
    Ok(fperm)
}

fn parse_levels(mode: &str) -> (u32, usize) {
    let mut mask = 0;
    let mut pos = 0;
    for ch in mode.chars() {
        mask |= match ch {
            'u' => 0o7700,
            'g' => 0o7070,
            'o' => 0o7007,
            'a' => 0o7777,
            _ => break,
        };
        pos += 1;
    }
    if pos == 0 {
        mask = 0o7777; // default to 'a'
    }
    (mask, pos)
}

fn parse_op(mode: &str, default: Option<char>) -> Result<(char, usize), String> {
    let ch = mode
        .chars()
        .next()
        .ok_or_else(|| "unexpected end of mode".to_owned())?;
    Ok(match ch {
        '+' | '-' | '=' => (ch, 1),
        _ => {
            let ch = default.ok_or_else(|| {
                format!("invalid operator (expected +, -, or =, but found {})", ch)
            })?;
            (ch, 0)
        }
    })
}

fn parse_change(mode: &str, fperm: u32, considering_dir: bool) -> (u32, usize) {
    let mut srwx = fperm & 0o7000;
    let mut pos = 0;
    for ch in mode.chars() {
        match ch {
            'r' => srwx |= 0o444,
            'w' => srwx |= 0o222,
            'x' => srwx |= 0o111,
            'X' => {
                if considering_dir || (fperm & 0o0111) != 0 {
                    srwx |= 0o111
                }
            }
            's' => srwx |= 0o4000 | 0o2000,
            't' => srwx |= 0o1000,
            'u' => srwx = (fperm & 0o700) | ((fperm >> 3) & 0o070) | ((fperm >> 6) & 0o007),
            'g' => srwx = ((fperm << 3) & 0o700) | (fperm & 0o070) | ((fperm >> 3) & 0o007),
            'o' => srwx = ((fperm << 6) & 0o700) | ((fperm << 3) & 0o070) | (fperm & 0o007),
            _ => break,
        };
        pos += 1;
    }
    if pos == 0 {
        srwx = 0;
    }
    (srwx, pos)
}

pub fn parse_mode(mode: &str) -> Result<mode_t, String> {
    let fperm = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
    let arr: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
    let result = if mode.contains(arr) {
        parse_numeric(fperm as u32, mode)
    } else {
        parse_symbolic(fperm as u32, mode, true)
    };
    result.map(|mode| mode as mode_t)
}

#[cfg(test)]
mod test {

    #[test]
    fn symbolic_modes() {
        assert_eq!(super::parse_mode("u+x").unwrap(), 0o766);
        assert_eq!(
            super::parse_mode("+x").unwrap(),
            if !crate::os::is_wsl_1() { 0o777 } else { 0o776 }
        );
        assert_eq!(super::parse_mode("a-w").unwrap(), 0o444);
        assert_eq!(super::parse_mode("g-r").unwrap(), 0o626);
    }

    #[test]
    fn numeric_modes() {
        assert_eq!(super::parse_mode("644").unwrap(), 0o644);
        assert_eq!(super::parse_mode("+100").unwrap(), 0o766);
        assert_eq!(super::parse_mode("-4").unwrap(), 0o662);
    }
}
<commit_msg>uucore/mode: handle mode 0<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Alex Lyon <arcterus@mail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (vars) fperm srwx

use libc::{mode_t, S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR};

pub fn parse_numeric(fperm: u32, mut mode: &str) -> Result<u32, String> {
    let (op, pos) = parse_op(mode, Some('='))?;
    mode = mode[pos..].trim();
    match u32::from_str_radix(mode, 8) {
        Ok(change) => {
            if change > 0o7777 {
                Err(format!("mode is too large ({} > 7777", mode))
            } else {
                Ok(match op {
                    '+' => fperm | change,
                    '-' => fperm & !change,
                    '=' => change,
                    _ => unreachable!(),
                })
            }
        }
        Err(err) => Err(err.to_string()),
    }
}

pub fn parse_symbolic(
    mut fperm: u32,
    mut mode: &str,
    considering_dir: bool,
) -> Result<u32, String> {
    #[cfg(unix)]
    use libc::umask;

    let (mask, pos) = parse_levels(mode);
    if pos == mode.len() {
        return Err(format!("invalid mode ({})", mode));
    }
    let respect_umask = pos == 0;
    let last_umask = unsafe { umask(0) };
    mode = &mode[pos..];
    while !mode.is_empty() {
        let (op, pos) = parse_op(mode, None)?;
        mode = &mode[pos..];
        let (mut srwx, pos) = parse_change(mode, fperm, considering_dir);
        if respect_umask {
            srwx &= !(last_umask as u32);
        }
        mode = &mode[pos..];
        match op {
            '+' => fperm |= srwx & mask,
            '-' => fperm &= !(srwx & mask),
            '=' => fperm = (fperm & !mask) | (srwx & mask),
            _ => unreachable!(),
        }
    }
    unsafe {
        umask(last_umask);
    }
    Ok(fperm)
}

fn parse_levels(mode: &str) -> (u32, usize) {
    let mut mask = 0;
    let mut pos = 0;
    for ch in mode.chars() {
        mask |= match ch {
            'u' => 0o7700,
            'g' => 0o7070,
            'o' => 0o7007,
            'a' => 0o7777,
            _ => break,
        };
        pos += 1;
    }
    if pos == 0 {
        mask = 0o7777; // default to 'a'
    }
    (mask, pos)
}

fn parse_op(mode: &str, default: Option<char>) -> Result<(char, usize), String> {
    let ch = mode
        .chars()
        .next()
        .ok_or_else(|| "unexpected end of mode".to_owned())?;
    Ok(match ch {
        '+' | '-' | '=' => (ch, 1),
        _ => {
            let ch = default.ok_or_else(|| {
                format!("invalid operator (expected +, -, or =, but found {})", ch)
            })?;
            (ch, 0)
        }
    })
}

fn parse_change(mode: &str, fperm: u32, considering_dir: bool) -> (u32, usize) {
    let mut srwx = fperm & 0o7000;
    let mut pos = 0;
    for ch in mode.chars() {
        match ch {
            'r' => srwx |= 0o444,
            'w' => srwx |= 0o222,
            'x' => srwx |= 0o111,
            'X' => {
                if considering_dir || (fperm & 0o0111) != 0 {
                    srwx |= 0o111
                }
            }
            's' => srwx |= 0o4000 | 0o2000,
            't' => srwx |= 0o1000,
            'u' => srwx = (fperm & 0o700) | ((fperm >> 3) & 0o070) | ((fperm >> 6) & 0o007),
            'g' => srwx = ((fperm << 3) & 0o700) | (fperm & 0o070) | ((fperm >> 3) & 0o007),
            'o' => srwx = ((fperm << 6) & 0o700) | ((fperm << 3) & 0o070) | (fperm & 0o007),
            _ => break,
        };
        pos += 1;
    }
    if pos == 0 {
        srwx = 0;
    }
    (srwx, pos)
}

pub fn parse_mode(mode: &str) -> Result<mode_t, String> {
    let fperm = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
    let arr: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
    let result = if mode.contains(arr) {
        parse_numeric(fperm as u32, mode)
    } else {
        parse_symbolic(fperm as u32, mode, true)
    };
    result.map(|mode| mode as mode_t)
}

#[cfg(test)]
mod test {

    #[test]
    fn symbolic_modes() {
        assert_eq!(super::parse_mode("u+x").unwrap(), 0o766);
        assert_eq!(
            super::parse_mode("+x").unwrap(),
            if !crate::os::is_wsl_1() { 0o777 } else { 0o776 }
        );
        assert_eq!(super::parse_mode("a-w").unwrap(), 0o444);
        assert_eq!(super::parse_mode("g-r").unwrap(), 0o626);
    }

    #[test]
    fn numeric_modes() {
        assert_eq!(super::parse_mode("644").unwrap(), 0o644);
        assert_eq!(super::parse_mode("+100").unwrap(), 0o766);
        assert_eq!(super::parse_mode("-4").unwrap(), 0o662);
    }
}
<|endoftext|>


<commit_before>
use {
    Borrowed,
    Color,
    Field,
    Line,
    Matrix2d,
    Value,
    View,
};
use vecmath::{
    identity,
};
use internal::{
    CanTransform,
    HasTransform,
};

/// A line context.
pub struct LineColorContext<'a> {
    /// Base/original transform.
    pub base: Field<'a, Matrix2d>,
    /// Current transform.
    pub transform: Field<'a, Matrix2d>,
    /// Current line.
    pub line: Field<'a, Line>,
    /// Current color.
    pub color: Field<'a, Color>,
}

impl<'a> HasTransform<'a, Matrix2d> for LineColorContext<'a> {
    #[inline(always)]
    fn get_transform(&'a self) -> &'a Matrix2d {
        self.transform.get()
    }
}

impl<'a> CanTransform<'a, LineColorContext<'a>, Matrix2d> for LineColorContext<'a> {
    #[inline(always)]
    fn transform(&'a self, value: Matrix2d) -> LineColorContext<'a> {
        LineColorContext {
            base: Borrowed(self.base.get()),
            transform: Value(value),
            line: Borrowed(self.line.get()),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> View<'a> for LineColorContext<'a> {
    #[inline(always)]
    fn view(&'a self) -> LineColorContext<'a> {
        LineColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.base.get()),
            line: Borrowed(self.line.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn reset(&'a self) -> LineColorContext<'a> {
        LineColorContext {
            base: Borrowed(self.base.get()),
            transform: Value(identity()),
            line: Borrowed(self.line.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn store_view(&'a self) -> LineColorContext<'a> {
        LineColorContext {
            base: Borrowed(self.transform.get()),
            transform: Borrowed(self.transform.get()),
            line: Borrowed(self.line.get()),
            color: Borrowed(self.color.get()),
        }
    }
}

<commit_msg>Implemented `AddRoundBorder` for `RoundBorderLineColorContext`<commit_after>
use {
    AddRoundBorder,
    Borrowed,
    Color,
    Field,
    Line,
    Matrix2d,
    RoundBorderLineColorContext,
    Value,
    View,
};
use vecmath::{
    identity,
};
use internal::{
    CanTransform,
    HasTransform,
};

/// A line context.
pub struct LineColorContext<'a> {
    /// Base/original transform.
    pub base: Field<'a, Matrix2d>,
    /// Current transform.
    pub transform: Field<'a, Matrix2d>,
    /// Current line.
    pub line: Field<'a, Line>,
    /// Current color.
    pub color: Field<'a, Color>,
}

impl<'a> HasTransform<'a, Matrix2d> for LineColorContext<'a> {
    #[inline(always)]
    fn get_transform(&'a self) -> &'a Matrix2d {
        self.transform.get()
    }
}

impl<'a> CanTransform<'a, LineColorContext<'a>, Matrix2d> for LineColorContext<'a> {
    #[inline(always)]
    fn transform(&'a self, value: Matrix2d) -> LineColorContext<'a> {
        LineColorContext {
            base: Borrowed(self.base.get()),
            transform: Value(value),
            line: Borrowed(self.line.get()),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> View<'a> for LineColorContext<'a> {
    #[inline(always)]
    fn view(&'a self) -> LineColorContext<'a> {
        LineColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.base.get()),
            line: Borrowed(self.line.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn reset(&'a self) -> LineColorContext<'a> {
        LineColorContext {
            base: Borrowed(self.base.get()),
            transform: Value(identity()),
            line: Borrowed(self.line.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn store_view(&'a self) -> LineColorContext<'a> {
        LineColorContext {
            base: Borrowed(self.transform.get()),
            transform: Borrowed(self.transform.get()),
            line: Borrowed(self.line.get()),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> AddRoundBorder<'a, RoundBorderLineColorContext<'a>> for LineColorContext<'a> {
    #[inline(always)]
    fn round_border(&'a self, radius: f64, width: f64) -> RoundBorderLineColorContext<'a> {
        RoundBorderLineColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            line: Borrowed(self.line.get()),
            round_border: Value([radius, width]),
            color: Borrowed(self.color.get()),
        }
    }
}

<|endoftext|>


<commit_before>use symbols::*;
use support::*;

//TODO change String to Symbol
///start, end, name, namespace, argument types (if applicable)
pub struct MemberBlock (pub usize, pub usize, pub String, pub String, pub Option<Vec<String>>);

pub struct ClassStructure
{
    //TODO add constructor vector
    pub class_symbol: Symbol,
    pub static_variables: Vec<MemberBlock>,
    pub static_methods: Vec<MemberBlock>,
    pub static_classes: Vec<MemberBlock>,

    pub non_static_variables: Vec<MemberBlock>,
    pub non_static_methods: Vec<MemberBlock>,
    pub non_static_classes: Vec<MemberBlock>,
}

impl ClassStructure
{
    pub fn new() -> ClassStructure
    {
        ClassStructure
        {
            class_symbol: Symbol {namespace: String::new(), is_static: false, name: String::new(), symbol_class: SymbolClass::Structure(String::new()), location: SymbolLocation::Structured},
            static_variables: Vec::new(),
            static_methods: Vec::new(),
            static_classes: Vec::new(),

            non_static_variables: Vec::new(),
            non_static_methods: Vec::new(),
            non_static_classes: Vec::new(),
        }
    }
}

pub struct SymbolTable
{
    pub children_scopes: Vec<Symbol>,
}

impl<'a> SymbolTable
{
    pub fn new() -> SymbolTable
    {
        SymbolTable
        {
            children_scopes: Vec::new(),
        }
    }
}

impl StaticSymbolTable for SymbolTable
{
    /// Return all symbols in this table with the specified name (in any namespace)
    fn lookup_by_name(&self, name: &str) -> Vec<&Symbol>
    {
        let mut symbols: Vec<&Symbol> = Vec::new();
        for symbol in self.children_scopes.iter()
        {
            if symbol.name == name
            {
                symbols.push(symbol.clone());
            }
        }
        symbols
    }

    /// Return all symbols in this table with the specified namespace
	fn lookup_by_namespace(&self, namespace: &str) -> Vec<&Symbol>
    {
        let mut symbols: Vec<&Symbol> = Vec::new();
        for symbol in self.children_scopes.iter()
        {
            if symbol.namespace == namespace
            {
                symbols.push(symbol.clone());
            }
        }
        symbols
    }

    /// Lookup a variable by its name and namespace. Duplicate symbols are not allowed, so the result will be unique
    /// @return the specified symbol or None if the specified symbol is not in this namespace
	fn lookup_variable(&self, namespace: &str, name: &str) -> Option<&Symbol>
    {
        let mut namespaces: Vec<&str> = namespace.split_terminator('_').collect();
        let mut length;
        let mut current_namespace;

        loop
        {
            current_namespace = namespaces.connect("_");

            if namespaces.is_empty()
            {
                break;
            }
            else
            {
                for symbol in self.lookup_by_namespace(&*current_namespace).iter()
                {
                    if symbol.namespace == current_namespace
                    {
                        if symbol.name == name
                        {
                            match symbol.symbol_class
                            {
                                SymbolClass::Variable(ref variable_type) => return Some((symbol).clone()),
                                _ => continue,
                            };
                        }
                    }
                }
                length = namespaces.len();
                namespaces.remove(length - 1);
            }
        }
        None
    }

    /// Lookup a function by its name and namespace. Functions with the same signature are not allowed, so the result will be unique
    /// If no result is found in the direct namespace, the parent namespaces will be searched
    /// @return the specified symbol or None if the specified symbol is not in this namespace or a parent namespace
	fn lookup_function(&self, namespace: &str, name: &str, argument_types: &Vec<String>) -> Option<&Symbol>
    {
        //TODO use argument_types
        let mut namespaces: Vec<&str> = namespace.split_terminator('_').collect();
        let mut length;
        let mut current_namespace;

        loop
        {
            current_namespace = namespaces.connect("_");

            if namespaces.is_empty()
            {
                break;
            }
            else
            {
                for symbol in self.lookup_by_namespace(&*current_namespace).iter()
                {
                    if symbol.namespace == current_namespace
                    {
                        if symbol.name == name
                        {
                            //check with starts_with
                            //Add suffix
                            match symbol.symbol_class
                            {
                                SymbolClass::Function(ref return_type, ref arguments, ref static_label, static_length) =>
                                {
                                    if arguments.len() == argument_types.len()
                                    {
                                        for index in 0..arguments.len()
                                        {
                                            if arguments[index] != argument_types[index]
                                            {
                                                continue
                                            }
                                        }
                                        return Some((symbol).clone())
                                    }
                                    else
                                    {
                                        continue
                                    }
                                }
                                _ => {continue}
                            };
                        }
                    }
                }
                length = namespaces.len();
                namespaces.remove(length - 1);
            }
        }
        None
    }

    /// Lookup a structure (class, enum) by its name and namespace.
    /// Duplicate classes in the same namespace are not allowed, so the result will be unique
    /// If no result is found in the direct namespace, the parent namespaces will be searched
    /// @return the specified symbol or None if the specified symbol is not in this namespace or a parent namespace
	fn lookup_structure(&self, namespace: &str, name: &str) -> Option<(&Symbol)>
    {
        let mut namespaces: Vec<&str> = namespace.split_terminator('_').collect();
        let mut length;
        let mut current_namespace;

        loop
        {
            current_namespace = namespaces.connect("_");

            if namespaces.is_empty()
            {
                break;
            }
            else
            {
                for symbol in self.lookup_by_namespace(&*current_namespace).iter()
                {
                    if symbol.namespace == current_namespace
                    {
                        if symbol.name == name
                        {
                            match symbol.symbol_class
                            {
                                SymbolClass::Structure(ref sub_type) => return Some((symbol).clone()),
                                _ => continue,
                            };
                        }
                    }
                }
                length = namespaces.len();
                namespaces.remove(length - 1);
            }
        }
        None
    }

    /// Adds a symbol to this table and allocates it's location
    /// Returns true if the symbol could be added; false otherwise
    /// Duplicate symbols are not allowed
    /// TODO: support overloaded methods
	fn add(&mut self, class: SymbolClass, namespace: String, name: String, is_static: bool, in_method: bool, is_parameter: bool, local_variable_count: u16, static_variable_count: u16, parameter_offset: u16) -> bool
    {
        let mut static_label = namespace.replace(".", "_").clone();
        static_label.push_str("_static");
        let mut method_namespace = namespace.replace(".", "_").clone();
        method_namespace.push_str("_");
        method_namespace.push_str(&*name);

        //TODO add return false
        let mut location: SymbolLocation = match class
        {
            //TODO replace with storing logic
            SymbolClass::Structure(ref sub_type) => SymbolLocation::Structured,
            SymbolClass::Variable(ref variable_type) => match in_method
                {
                    true => match is_parameter
                        {
                            true => SymbolLocation::MethodArgument(parameter_offset),
                            false =>SymbolLocation::Memory(MemoryAddress {label_name: static_label, offset: static_variable_count * 4}),
                        },
                    false => match is_static
                        {
                            true => SymbolLocation::Memory(MemoryAddress {label_name: static_label, offset: static_variable_count * 4}),
                            false => SymbolLocation::InstancedMemory(local_variable_count * 4),
                        },
                },
            SymbolClass::Function(ref return_type, ref arguments, ref static_label, static_length) => SymbolLocation::Memory(MemoryAddress {label_name: method_namespace, offset: 0}),
        };

        let mut symbol: Symbol =  Symbol
        {
            name: name,
            namespace: namespace,
            is_static: is_static,
            symbol_class: class,
            location: location,
        };

        self.children_scopes.push(symbol);
        return true;
    }

    fn concatenate_namespace(&self, namespace: String, extension: String) -> String
    {
        return namespace + &extension;
    }
}
<commit_msg>Housekeeping<commit_after>use symbols::*;
use support::*;

//TODO change String to Symbol
///start, end, name, namespace, argument types (if applicable)
pub struct MemberBlock (pub usize, pub usize, pub String, pub String, pub Option<Vec<String>>);

pub struct ClassStructure
{
    //TODO add constructor vector
    pub class_symbol: Symbol,
    pub static_variables: Vec<MemberBlock>,
    pub static_methods: Vec<MemberBlock>,
    // TODO make this a Vec of ClassStructure
    pub static_classes: Vec<MemberBlock>,

    pub non_static_variables: Vec<MemberBlock>,
    pub non_static_methods: Vec<MemberBlock>,
    // TODO make this a Vec of ClassStructure
    pub non_static_classes: Vec<MemberBlock>,
}

impl ClassStructure
{
    pub fn new() -> ClassStructure
    {
        ClassStructure
        {
            class_symbol: Symbol {namespace: String::new(), is_static: false, name: String::new(), symbol_class: SymbolClass::Structure(String::new()), location: SymbolLocation::Structured},
            static_variables: Vec::new(),
            static_methods: Vec::new(),
            static_classes: Vec::new(),

            non_static_variables: Vec::new(),
            non_static_methods: Vec::new(),
            non_static_classes: Vec::new(),
        }
    }
}

pub struct SymbolTable
{
    pub children_scopes: Vec<Symbol>,
}

impl<'a> SymbolTable
{
    pub fn new() -> SymbolTable
    {
        SymbolTable
        {
            children_scopes: Vec::new(),
        }
    }
}

impl StaticSymbolTable for SymbolTable
{
    /// Return all symbols in this table with the specified name (in any namespace)
    fn lookup_by_name(&self, name: &str) -> Vec<&Symbol>
    {
        let mut symbols: Vec<&Symbol> = Vec::new();
        for symbol in self.children_scopes.iter()
        {
            if symbol.name == name
            {
                symbols.push(symbol.clone());
            }
        }
        symbols
    }

    /// Return all symbols in this table with the specified namespace
	fn lookup_by_namespace(&self, namespace: &str) -> Vec<&Symbol>
    {
        let mut symbols: Vec<&Symbol> = Vec::new();
        for symbol in self.children_scopes.iter()
        {
            if symbol.namespace == namespace
            {
                symbols.push(symbol.clone());
            }
        }
        symbols
    }

    /// Lookup a variable by its name and namespace. Duplicate symbols are not allowed, so the result will be unique
    /// @return the specified symbol or None if the specified symbol is not in this namespace
	fn lookup_variable(&self, namespace: &str, name: &str) -> Option<&Symbol>
    {
        let mut namespaces: Vec<&str> = namespace.split_terminator('_').collect();
        let mut length;
        let mut current_namespace;

        loop
        {
            current_namespace = namespaces.connect("_");

            if namespaces.is_empty()
            {
                break;
            }
            else
            {
                for symbol in self.lookup_by_namespace(&*current_namespace).iter()
                {
                    if symbol.namespace == current_namespace
                    {
                        if symbol.name == name
                        {
                            match symbol.symbol_class
                            {
                                SymbolClass::Variable(ref variable_type) => return Some((symbol).clone()),
                                _ => continue,
                            };
                        }
                    }
                }
                length = namespaces.len();
                namespaces.remove(length - 1);
            }
        }
        None
    }

    /// Lookup a function by its name and namespace. Functions with the same signature are not allowed, so the result will be unique
    /// If no result is found in the direct namespace, the parent namespaces will be searched
    /// @return the specified symbol or None if the specified symbol is not in this namespace or a parent namespace
	fn lookup_function(&self, namespace: &str, name: &str, argument_types: &Vec<String>) -> Option<&Symbol>
    {
        //TODO use argument_types
        let mut namespaces: Vec<&str> = namespace.split_terminator('_').collect();
        let mut length;
        let mut current_namespace;

        loop
        {
            current_namespace = namespaces.connect("_");

            if namespaces.is_empty()
            {
                break;
            }
            else
            {
                for symbol in self.lookup_by_namespace(&*current_namespace).iter()
                {
                    if symbol.namespace == current_namespace
                    {
                        if symbol.name == name
                        {
                            //check with starts_with
                            //Add suffix
                            match symbol.symbol_class
                            {
                                SymbolClass::Function(ref return_type, ref arguments, ref static_label, static_length) =>
                                {
                                    if arguments.len() == argument_types.len()
                                    {
                                        for index in 0..arguments.len()
                                        {
                                            if arguments[index] != argument_types[index]
                                            {
                                                continue
                                            }
                                        }
                                        return Some((symbol).clone())
                                    }
                                    else
                                    {
                                        continue
                                    }
                                }
                                _ => {continue}
                            };
                        }
                    }
                }
                length = namespaces.len();
                namespaces.remove(length - 1);
            }
        }
        None
    }

    /// Lookup a structure (class, enum) by its name and namespace.
    /// Duplicate classes in the same namespace are not allowed, so the result will be unique
    /// If no result is found in the direct namespace, the parent namespaces will be searched
    /// @return the specified symbol or None if the specified symbol is not in this namespace or a parent namespace
	fn lookup_structure(&self, namespace: &str, name: &str) -> Option<(&Symbol)>
    {
        let mut namespaces: Vec<&str> = namespace.split_terminator('_').collect();
        let mut length;
        let mut current_namespace;

        loop
        {
            current_namespace = namespaces.connect("_");

            if namespaces.is_empty()
            {
                break;
            }
            else
            {
                for symbol in self.lookup_by_namespace(&*current_namespace).iter()
                {
                    if symbol.namespace == current_namespace
                    {
                        if symbol.name == name
                        {
                            match symbol.symbol_class
                            {
                                SymbolClass::Structure(ref sub_type) => return Some((symbol).clone()),
                                _ => continue,
                            };
                        }
                    }
                }
                length = namespaces.len();
                namespaces.remove(length - 1);
            }
        }
        None
    }

    /// Adds a symbol to this table and allocates it's location
    /// Returns true if the symbol could be added; false otherwise
    /// Duplicate symbols are not allowed
    /// TODO: support overloaded methods
	fn add(&mut self, class: SymbolClass, namespace: String, name: String, is_static: bool, in_method: bool, is_parameter: bool, local_variable_count: u16, static_variable_count: u16, parameter_offset: u16) -> bool
    {
        let mut static_label = namespace.replace(".", "_").clone();
        static_label.push_str("_static");
        let mut method_namespace = namespace.replace(".", "_").clone();
        method_namespace.push_str("_");
        method_namespace.push_str(&*name);

        //TODO add return false
        let mut location: SymbolLocation = match class
        {
            //TODO replace with storing logic
            SymbolClass::Structure(ref sub_type) => SymbolLocation::Structured,
            SymbolClass::Variable(ref variable_type) => match in_method
                {
                    true => match is_parameter
                        {
                            true => SymbolLocation::MethodArgument(parameter_offset),
                            false =>SymbolLocation::Memory(MemoryAddress {label_name: static_label, offset: static_variable_count * 4}),
                        },
                    false => match is_static
                        {
                            true => SymbolLocation::Memory(MemoryAddress {label_name: static_label, offset: static_variable_count * 4}),
                            false => SymbolLocation::InstancedMemory(local_variable_count * 4),
                        },
                },
            SymbolClass::Function(ref return_type, ref arguments, ref static_label, static_length) => SymbolLocation::Memory(MemoryAddress {label_name: method_namespace, offset: 0}),
        };

        let mut symbol: Symbol =  Symbol
        {
            name: name,
            namespace: namespace,
            is_static: is_static,
            symbol_class: class,
            location: location,
        };

        self.children_scopes.push(symbol);
        return true;
    }

    fn concatenate_namespace(&self, namespace: String, extension: String) -> String
    {
        return namespace + &extension;
    }
}
<|endoftext|>


<commit_before>use crate::cell::UnsafeCell;
use crate::collections::VecDeque;
use crate::ffi::c_void;
use crate::ops::{Deref, DerefMut, Drop};
use crate::ptr;
use crate::sync::atomic::{spin_loop_hint, AtomicUsize, Ordering};
use crate::sys::hermit::abi;

/// This type provides a lock based on busy waiting to realize mutual exclusion
///
/// # Description
///
/// This structure behaves a lot like a common mutex. There are some differences:
///
/// - By using busy waiting, it can be used outside the runtime.
/// - It is a so called ticket lock and is completly fair.
#[cfg_attr(target_arch = "x86_64", repr(align(128)))]
#[cfg_attr(not(target_arch = "x86_64"), repr(align(64)))]
struct Spinlock<T: ?Sized> {
    queue: AtomicUsize,
    dequeue: AtomicUsize,
    data: UnsafeCell<T>,
}

unsafe impl<T: ?Sized + Send> Sync for Spinlock<T> {}
unsafe impl<T: ?Sized + Send> Send for Spinlock<T> {}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
struct SpinlockGuard<'a, T: ?Sized + 'a> {
    dequeue: &'a AtomicUsize,
    data: &'a mut T,
}

impl<T> Spinlock<T> {
    pub const fn new(user_data: T) -> Spinlock<T> {
        Spinlock {
            queue: AtomicUsize::new(0),
            dequeue: AtomicUsize::new(1),
            data: UnsafeCell::new(user_data),
        }
    }

    #[inline]
    fn obtain_lock(&self) {
        let ticket = self.queue.fetch_add(1, Ordering::SeqCst) + 1;
        while self.dequeue.load(Ordering::SeqCst) != ticket {
            spin_loop_hint();
        }
    }

    #[inline]
    pub unsafe fn lock(&self) -> SpinlockGuard<'_, T> {
        self.obtain_lock();
        SpinlockGuard { dequeue: &self.dequeue, data: &mut *self.data.get() }
    }
}

impl<T: ?Sized + Default> Default for Spinlock<T> {
    fn default() -> Spinlock<T> {
        Spinlock::new(Default::default())
    }
}

impl<'a, T: ?Sized> Deref for SpinlockGuard<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        &*self.data
    }
}

impl<'a, T: ?Sized> DerefMut for SpinlockGuard<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut *self.data
    }
}

impl<'a, T: ?Sized> Drop for SpinlockGuard<'a, T> {
    /// The dropping of the SpinlockGuard will release the lock it was created from.
    fn drop(&mut self) {
        self.dequeue.fetch_add(1, Ordering::SeqCst);
    }
}

/// Realize a priority queue for tasks
struct PriorityQueue {
    queues: [Option<VecDeque<abi::Tid>>; abi::NO_PRIORITIES],
    prio_bitmap: u64,
}

impl PriorityQueue {
    pub const fn new() -> PriorityQueue {
        PriorityQueue {
            queues: [
                None, None, None, None, None, None, None, None, None, None, None, None, None, None,
                None, None, None, None, None, None, None, None, None, None, None, None, None, None,
                None, None, None,
            ],
            prio_bitmap: 0,
        }
    }

    /// Add a task id by its priority to the queue
    pub fn push(&mut self, prio: abi::Priority, id: abi::Tid) {
        let i: usize = prio.into().into();
        self.prio_bitmap |= (1 << i) as u64;
        if let Some(queue) = &mut self.queues[i] {
            queue.push_back(id);
        } else {
            let mut queue = VecDeque::new();
            queue.push_back(id);
            self.queues[i] = Some(queue);
        }
    }

    fn pop_from_queue(&mut self, queue_index: usize) -> Option<abi::Tid> {
        if let Some(queue) = &mut self.queues[queue_index] {
            let id = queue.pop_front();

            if queue.is_empty() {
                self.prio_bitmap &= !(1 << queue_index as u64);
            }

            id
        } else {
            None
        }
    }

    /// Pop the task handle with the highest priority from the queue
    pub fn pop(&mut self) -> Option<abi::Tid> {
        for i in 0..abi::NO_PRIORITIES {
            if self.prio_bitmap & (1 << i) != 0 {
                return self.pop_from_queue(i);
            }
        }

        None
    }
}

struct MutexInner {
    locked: bool,
    blocked_task: PriorityQueue,
}

impl MutexInner {
    pub const fn new() -> MutexInner {
        MutexInner { locked: false, blocked_task: PriorityQueue::new() }
    }
}

pub struct Mutex {
    inner: Spinlock<MutexInner>,
}

pub type MovableMutex = Mutex;

unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {}

impl Mutex {
    pub const fn new() -> Mutex {
        Mutex { inner: Spinlock::new(MutexInner::new()) }
    }

    #[inline]
    pub unsafe fn init(&mut self) {
        self.inner = Spinlock::new(MutexInner::new());
    }

    #[inline]
    pub unsafe fn lock(&self) {
        loop {
            let mut guard = self.inner.lock();
            if guard.locked == false {
                guard.locked = true;
                return;
            } else {
                let prio = abi::get_priority();
                let id = abi::getpid();

                guard.blocked_task.push(prio, id);
                abi::block_current_task();
                drop(guard);
                abi::yield_now();
            }
        }
    }

    #[inline]
    pub unsafe fn unlock(&self) {
        let mut guard = self.inner.lock();
        guard.locked = false;
        if let Some(tid) = guard.blocked_task.pop() {
            abi::wakeup_task(tid);
        }
    }

    #[inline]
    pub unsafe fn try_lock(&self) -> bool {
        let mut guard = self.inner.lock();
        if guard.locked == false {
            guard.locked = true;
        }
        guard.locked
    }

    #[inline]
    pub unsafe fn destroy(&self) {}
}

pub struct ReentrantMutex {
    inner: *const c_void,
}

impl ReentrantMutex {
    pub const unsafe fn uninitialized() -> ReentrantMutex {
        ReentrantMutex { inner: ptr::null() }
    }

    #[inline]
    pub unsafe fn init(&self) {
        let _ = abi::recmutex_init(&self.inner as *const *const c_void as *mut _);
    }

    #[inline]
    pub unsafe fn lock(&self) {
        let _ = abi::recmutex_lock(self.inner);
    }

    #[inline]
    pub unsafe fn try_lock(&self) -> bool {
        true
    }

    #[inline]
    pub unsafe fn unlock(&self) {
        let _ = abi::recmutex_unlock(self.inner);
    }

    #[inline]
    pub unsafe fn destroy(&self) {
        let _ = abi::recmutex_destroy(self.inner);
    }
}
<commit_msg>box mutex to get a movable mutex<commit_after>use crate::cell::UnsafeCell;
use crate::collections::VecDeque;
use crate::ffi::c_void;
use crate::ops::{Deref, DerefMut, Drop};
use crate::ptr;
use crate::sync::atomic::{spin_loop_hint, AtomicUsize, Ordering};
use crate::sys::hermit::abi;

/// This type provides a lock based on busy waiting to realize mutual exclusion
///
/// # Description
///
/// This structure behaves a lot like a common mutex. There are some differences:
///
/// - By using busy waiting, it can be used outside the runtime.
/// - It is a so called ticket lock and is completly fair.
#[cfg_attr(target_arch = "x86_64", repr(align(128)))]
#[cfg_attr(not(target_arch = "x86_64"), repr(align(64)))]
struct Spinlock<T: ?Sized> {
    queue: AtomicUsize,
    dequeue: AtomicUsize,
    data: UnsafeCell<T>,
}

unsafe impl<T: ?Sized + Send> Sync for Spinlock<T> {}
unsafe impl<T: ?Sized + Send> Send for Spinlock<T> {}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
struct SpinlockGuard<'a, T: ?Sized + 'a> {
    dequeue: &'a AtomicUsize,
    data: &'a mut T,
}

impl<T> Spinlock<T> {
    pub const fn new(user_data: T) -> Spinlock<T> {
        Spinlock {
            queue: AtomicUsize::new(0),
            dequeue: AtomicUsize::new(1),
            data: UnsafeCell::new(user_data),
        }
    }

    #[inline]
    fn obtain_lock(&self) {
        let ticket = self.queue.fetch_add(1, Ordering::SeqCst) + 1;
        while self.dequeue.load(Ordering::SeqCst) != ticket {
            spin_loop_hint();
        }
    }

    #[inline]
    pub unsafe fn lock(&self) -> SpinlockGuard<'_, T> {
        self.obtain_lock();
        SpinlockGuard { dequeue: &self.dequeue, data: &mut *self.data.get() }
    }
}

impl<T: ?Sized + Default> Default for Spinlock<T> {
    fn default() -> Spinlock<T> {
        Spinlock::new(Default::default())
    }
}

impl<'a, T: ?Sized> Deref for SpinlockGuard<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        &*self.data
    }
}

impl<'a, T: ?Sized> DerefMut for SpinlockGuard<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut *self.data
    }
}

impl<'a, T: ?Sized> Drop for SpinlockGuard<'a, T> {
    /// The dropping of the SpinlockGuard will release the lock it was created from.
    fn drop(&mut self) {
        self.dequeue.fetch_add(1, Ordering::SeqCst);
    }
}

/// Realize a priority queue for tasks
struct PriorityQueue {
    queues: [Option<VecDeque<abi::Tid>>; abi::NO_PRIORITIES],
    prio_bitmap: u64,
}

impl PriorityQueue {
    pub const fn new() -> PriorityQueue {
        PriorityQueue {
            queues: [
                None, None, None, None, None, None, None, None, None, None, None, None, None, None,
                None, None, None, None, None, None, None, None, None, None, None, None, None, None,
                None, None, None,
            ],
            prio_bitmap: 0,
        }
    }

    /// Add a task id by its priority to the queue
    pub fn push(&mut self, prio: abi::Priority, id: abi::Tid) {
        let i: usize = prio.into().into();
        self.prio_bitmap |= (1 << i) as u64;
        if let Some(queue) = &mut self.queues[i] {
            queue.push_back(id);
        } else {
            let mut queue = VecDeque::new();
            queue.push_back(id);
            self.queues[i] = Some(queue);
        }
    }

    fn pop_from_queue(&mut self, queue_index: usize) -> Option<abi::Tid> {
        if let Some(queue) = &mut self.queues[queue_index] {
            let id = queue.pop_front();

            if queue.is_empty() {
                self.prio_bitmap &= !(1 << queue_index as u64);
            }

            id
        } else {
            None
        }
    }

    /// Pop the task handle with the highest priority from the queue
    pub fn pop(&mut self) -> Option<abi::Tid> {
        for i in 0..abi::NO_PRIORITIES {
            if self.prio_bitmap & (1 << i) != 0 {
                return self.pop_from_queue(i);
            }
        }

        None
    }
}

struct MutexInner {
    locked: bool,
    blocked_task: PriorityQueue,
}

impl MutexInner {
    pub const fn new() -> MutexInner {
        MutexInner { locked: false, blocked_task: PriorityQueue::new() }
    }
}

pub struct Mutex {
    inner: Spinlock<MutexInner>,
}

pub type MovableMutex = Box<Mutex>;

unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {}

impl Mutex {
    pub const fn new() -> Mutex {
        Mutex { inner: Spinlock::new(MutexInner::new()) }
    }

    #[inline]
    pub unsafe fn init(&mut self) {
        self.inner = Spinlock::new(MutexInner::new());
    }

    #[inline]
    pub unsafe fn lock(&self) {
        loop {
            let mut guard = self.inner.lock();
            if guard.locked == false {
                guard.locked = true;
                return;
            } else {
                let prio = abi::get_priority();
                let id = abi::getpid();

                guard.blocked_task.push(prio, id);
                abi::block_current_task();
                drop(guard);
                abi::yield_now();
            }
        }
    }

    #[inline]
    pub unsafe fn unlock(&self) {
        let mut guard = self.inner.lock();
        guard.locked = false;
        if let Some(tid) = guard.blocked_task.pop() {
            abi::wakeup_task(tid);
        }
    }

    #[inline]
    pub unsafe fn try_lock(&self) -> bool {
        let mut guard = self.inner.lock();
        if guard.locked == false {
            guard.locked = true;
        }
        guard.locked
    }

    #[inline]
    pub unsafe fn destroy(&self) {}
}

pub struct ReentrantMutex {
    inner: *const c_void,
}

impl ReentrantMutex {
    pub const unsafe fn uninitialized() -> ReentrantMutex {
        ReentrantMutex { inner: ptr::null() }
    }

    #[inline]
    pub unsafe fn init(&self) {
        let _ = abi::recmutex_init(&self.inner as *const *const c_void as *mut _);
    }

    #[inline]
    pub unsafe fn lock(&self) {
        let _ = abi::recmutex_lock(self.inner);
    }

    #[inline]
    pub unsafe fn try_lock(&self) -> bool {
        true
    }

    #[inline]
    pub unsafe fn unlock(&self) {
        let _ = abi::recmutex_unlock(self.inner);
    }

    #[inline]
    pub unsafe fn destroy(&self) {
        let _ = abi::recmutex_destroy(self.inner);
    }
}
<|endoftext|>


<commit_before>extern crate typenum;
use matrix::{ColumnPanelMatrix, RowPanelMatrix, Matrix, Subcomputation};
use composables::{PartM, PartN, PartK, PackA, PackB,
                  ForceB, SpawnThreads, ParallelN, TheRest};
use kern::{KernelNM};
use typenum::{UInt, B0};

// BLIS's constants
type U4080 = UInt<UInt<typenum::U1020, B0>, B0>;
type Nc = U4080;
type Kc = typenum::U256;
type Mc = typenum::U72;
type Mr = typenum::U6;
type Nr = typenum::U8;

// Old constants
// type U3000 = UInt<UInt<typenum::U750, B0>, B0>;
// type Nc = U3000;
// type Kc = typenum::U192;
// type Mc = typenum::U120;
// type Mr = typenum::U4;
// type Nr = typenum::U12;

type Goto<T, MTA, MTB, MTC> =
      PartN<T, MTA, MTB, MTC, Nc,
      PartK<T, MTA, MTB, MTC, Kc,
      PackB<T, MTA, MTB, MTC, ColumnPanelMatrix<T, Nr>,
      PartM<T, MTA, ColumnPanelMatrix<T,Nr>, MTC, Mc,
      PackA<T, MTA, ColumnPanelMatrix<T,Nr>, MTC, RowPanelMatrix<T,Mr>,
      ParallelN<T, RowPanelMatrix<T,Mr>, ColumnPanelMatrix<T,Nr>, MTC, Nr, TheRest,
      KernelNM<T, RowPanelMatrix<T,Mr>, ColumnPanelMatrix<T,Nr>, MTC, Nr, Mr>>>>>>>;

pub type GotoDgemm = Goto<f64, Matrix<f64>, Matrix<f64>, Matrix<f64>>;
pub type GotoDgemm3Sub = Subcomputation<f64, Matrix<f64>, Matrix<f64>, Matrix<f64>>;
pub type GotoDgemm3 =
    SpawnThreads<f64, Matrix<f64>, GotoDgemm3Sub, Matrix<f64>,
    ForceB<f64, Matrix<f64>,
           Matrix<f64>, Matrix<f64>, Matrix<f64>, GotoDgemm3Sub,
           Matrix<f64>,
    GotoDgemm, GotoDgemm>>;

    // type RootS3 = typenum::U768;
type McL2 = typenum::U72; //typenum::U120;
pub type ColPM<T> = ColumnPanelMatrix<T, Nr>;
pub type RowPM<T> = RowPanelMatrix<T, Mr>;

type L3CNc = typenum::U624;
type L3CKc = typenum::U156;
//Resident C algorithm, inner loops
type L3CInner<T, MTA, MTB, MTC> =
      PartK<T, MTA, MTB, MTC, L3CKc,
      PackB<T, MTA, MTB, MTC, ColPM<T>,
      PartM<T, MTA, ColPM<T>, MTC, L3CKc,
      PackA<T, MTA, ColPM<T>, MTC, RowPM<T>,
      ParallelN<T, RowPM<T>, ColPM<T>, MTC, Nr, TheRest,
      KernelNM<T, RowPM<T>, ColPM<T>, MTC, Nr, Mr>>>>>>;

type L3CInnerSub<T> = Subcomputation<T, Matrix<T>, Matrix<T>, ColPM<T>>;
pub type Dgemm3Sub = L3CInnerSub<f64>;
pub type Dgemm3TmpWidth = L3CNc;
pub type Dgemm3TmpHeight = L3CNc;
type L3BOuter<T, MTA, MTAi, MTBi, MTC> =
      SpawnThreads<T, MTA, Subcomputation<T, MTAi, MTBi, ColPM<T>>, MTC,
      PartN<T, MTA, Subcomputation<T, MTAi, MTBi, ColPM<T>>, MTC, L3CNc,
      PartK<T, MTA, Subcomputation<T, MTAi, MTBi, ColPM<T>>, MTC, L3CNc, // Also the Mc of that algorithm, and outer k -> inner m
      ForceB<T, MTA, MTAi, MTBi, ColPM<T>, Subcomputation<T, MTAi, MTBi, ColPM<T>>, MTC,
                L3CInner<T, MTAi, MTBi, ColPM<T>>,
      PartM<T, MTA, ColPM<T>, MTC, McL2,
      PartK<T, MTA, ColPM<T>, MTC, Kc,
      PackA<T, MTA, ColPM<T>, MTC, RowPM<T>,
      ParallelN<T, RowPM<T>, ColPM<T>, MTC, Nr, TheRest,
      KernelNM<T, RowPM<T>, ColPM<T>, MTC, Nr, Mr>>>>>>>>>;

pub type Dgemm3 = L3BOuter<f64, Matrix<f64>, Matrix<f64>, Matrix<f64>, Matrix<f64>>;
<commit_msg>Minor constant tweaks<commit_after>extern crate typenum;
use matrix::{ColumnPanelMatrix, RowPanelMatrix, Matrix, Subcomputation};
use composables::{PartM, PartN, PartK, PackA, PackB,
                  ForceB, SpawnThreads, ParallelN, TheRest};
use kern::{KernelNM};
use typenum::{UInt, B0};

// BLIS's constants
type U4080 = UInt<UInt<typenum::U1020, B0>, B0>;
type Nc = U4080;
type Kc = typenum::U256;
type Mc = typenum::U72;
type Mr = typenum::U6;
type Nr = typenum::U8;

// Old constants
// type U3000 = UInt<UInt<typenum::U750, B0>, B0>;
// type Nc = U3000;
// type Kc = typenum::U192;
// type Mc = typenum::U120;
// type Mr = typenum::U4;
// type Nr = typenum::U12;

type Goto<T, MTA, MTB, MTC> =
      PartN<T, MTA, MTB, MTC, Nc,
      PartK<T, MTA, MTB, MTC, Kc,
      PackB<T, MTA, MTB, MTC, ColumnPanelMatrix<T, Nr>,
      PartM<T, MTA, ColumnPanelMatrix<T,Nr>, MTC, Mc,
      PackA<T, MTA, ColumnPanelMatrix<T,Nr>, MTC, RowPanelMatrix<T,Mr>,
      ParallelN<T, RowPanelMatrix<T,Mr>, ColumnPanelMatrix<T,Nr>, MTC, Nr, TheRest,
      KernelNM<T, RowPanelMatrix<T,Mr>, ColumnPanelMatrix<T,Nr>, MTC, Nr, Mr>>>>>>>;

pub type GotoDgemm = Goto<f64, Matrix<f64>, Matrix<f64>, Matrix<f64>>;
pub type GotoDgemm3Sub = Subcomputation<f64, Matrix<f64>, Matrix<f64>, Matrix<f64>>;
pub type GotoDgemm3 =
    SpawnThreads<f64, Matrix<f64>, GotoDgemm3Sub, Matrix<f64>,
    ForceB<f64, Matrix<f64>,
           Matrix<f64>, Matrix<f64>, Matrix<f64>, GotoDgemm3Sub,
           Matrix<f64>,
    GotoDgemm, GotoDgemm>>;

    // type RootS3 = typenum::U768;
type McL2 = typenum::U156; //typenum::U120;
pub type ColPM<T> = ColumnPanelMatrix<T, Nr>;
pub type RowPM<T> = RowPanelMatrix<T, Mr>;

type L3CNc = typenum::U780;
type L3CKc = typenum::U156;
//Resident C algorithm, inner loops
type L3CInner<T, MTA, MTB, MTC> =
      PartK<T, MTA, MTB, MTC, L3CKc,
      PackB<T, MTA, MTB, MTC, ColPM<T>,
      PartM<T, MTA, ColPM<T>, MTC, L3CKc,
      PackA<T, MTA, ColPM<T>, MTC, RowPM<T>,
      ParallelN<T, RowPM<T>, ColPM<T>, MTC, Nr, TheRest,
      KernelNM<T, RowPM<T>, ColPM<T>, MTC, Nr, Mr>>>>>>;

type L3CInnerSub<T> = Subcomputation<T, Matrix<T>, Matrix<T>, ColPM<T>>;
pub type Dgemm3Sub = L3CInnerSub<f64>;
pub type Dgemm3TmpWidth = L3CNc;
pub type Dgemm3TmpHeight = L3CNc;
type L3BOuter<T, MTA, MTAi, MTBi, MTC> =
      SpawnThreads<T, MTA, Subcomputation<T, MTAi, MTBi, ColPM<T>>, MTC,
      PartN<T, MTA, Subcomputation<T, MTAi, MTBi, ColPM<T>>, MTC, L3CNc,
      PartK<T, MTA, Subcomputation<T, MTAi, MTBi, ColPM<T>>, MTC, L3CNc, // Also the Mc of that algorithm, and outer k -> inner m
      ForceB<T, MTA, MTAi, MTBi, ColPM<T>, Subcomputation<T, MTAi, MTBi, ColPM<T>>, MTC,
                L3CInner<T, MTAi, MTBi, ColPM<T>>,
      PartM<T, MTA, ColPM<T>, MTC, McL2,
      PartK<T, MTA, ColPM<T>, MTC, Kc,
      PackA<T, MTA, ColPM<T>, MTC, RowPM<T>,
      ParallelN<T, RowPM<T>, ColPM<T>, MTC, Nr, TheRest,
      KernelNM<T, RowPM<T>, ColPM<T>, MTC, Nr, Mr>>>>>>>>>;

pub type Dgemm3 = L3BOuter<f64, Matrix<f64>, Matrix<f64>, Matrix<f64>, Matrix<f64>>;
<|endoftext|>


<commit_before>use std::fmt::{self, Display, Formatter};
use std::default::Default;
use rlua::{self, Table, Lua, UserData, ToLua, Value, AnyUserData, UserDataMethods, MetaMethod};
use super::object::{Object, Objectable};
use super::signal;
use super::property::Property;
use super::class::{self, Class};
use rustwlc::types::KeyMod;
use xcb::ffi::xproto::xcb_button_t;

#[derive(Clone, Debug)]
pub struct ButtonState {
    button: xcb_button_t,
    modifiers: KeyMod
}

#[derive(Clone, Debug)]
pub struct Button<'lua>(Object<'lua>);

impl Display for ButtonState {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Button: {:p}", self)
    }
}

impl Default for ButtonState {
    fn default() -> Self {
        ButtonState {
            button: xcb_button_t::default(),
            modifiers: KeyMod::empty()
        }
    }
}

impl UserData for ButtonState {
    fn add_methods(methods: &mut UserDataMethods<Self>) {
        methods.add_meta_function(MetaMethod::Index, super::object::default_index);
        methods.add_meta_function(MetaMethod::NewIndex, super::object::default_newindex)
    }
}

impl <'lua> Button<'lua> {
    fn new(lua: &'lua Lua, args: rlua::Table) -> rlua::Result<Object<'lua>> {
        let class = class::class_setup(lua, "button")?;
        Ok(Button::allocate(lua, class)?
           .handle_constructor_argument(args)?
           .build())
    }

    pub fn button(&self) -> rlua::Result<Value<'lua>> {
        let button = self.state()?;
        Ok(Value::Integer(button.button as _))
    }

    pub fn set_button(&mut self, new_val: xcb_button_t) -> rlua::Result<()> {
        let mut button = self.state()?;
        button.button = new_val;
        self.set_state(button)?;
        Ok(())
    }

    pub fn modifiers(&self) -> rlua::Result<KeyMod> {
        let button = self.state()?;
        Ok(button.modifiers)
    }

    pub fn set_modifiers(&mut self, mods: Table<'lua>) -> rlua::Result<()> {
        use ::lua::mods_to_rust;
        let mut button = self.state()?;
        button.modifiers = mods_to_rust(mods)?;
        self.set_state(button)?;
        Ok(())
    }
}

impl <'lua> ToLua<'lua> for Button<'lua> {
    fn to_lua(self, lua: &'lua Lua) -> rlua::Result<Value<'lua>> {
        self.0.to_lua(lua)
    }
}

impl_objectable!(Button, ButtonState);

pub fn init(lua: &Lua) -> rlua::Result<Class> {
    Class::builder(lua, "button", None, None, None)?
        .method("__call".into(),
                lua.create_function(|lua, (_, args): (rlua::Value, rlua::Table)| Button::new(lua, args))?)?
        .property(Property::new("button".into(),
                                Some(lua.create_function(set_button)?),
                                Some(lua.create_function(get_button)?),
                                Some(lua.create_function(set_button)?)))?
        .property(Property::new("modifiers".into(),
                                Some(lua.create_function(set_modifiers)?),
                                Some(lua.create_function(get_modifiers)?),
                                Some(lua.create_function(set_modifiers)?)))?
        .save_class("button")?
        .build()
}

fn set_button<'lua>(lua: &'lua Lua, (obj, val): (AnyUserData<'lua>, Value<'lua>))
                    -> rlua::Result<Value<'lua>> {
    use rlua::Value::*;
    let mut button = Button::cast(obj.clone().into())?;
    match val {
        Number(num) => button.set_button(num as _)?,
        Integer(num) => button.set_button(num as _)?,
        _ => button.set_button(xcb_button_t::default())?
    }
    signal::emit_object_signal(lua,
                        obj.into(),
                        "property::button".into(),
                        val)?;
    Ok(Value::Nil)
}

fn get_button<'lua>(_: &'lua Lua, obj: AnyUserData<'lua>)
                    -> rlua::Result<Value<'lua>> {
    Button::cast(obj.into())?.button()
}

fn set_modifiers<'lua>(lua: &'lua Lua, (obj, modifiers): (AnyUserData<'lua>, Table<'lua>))
                       -> rlua::Result<Value<'lua>> {
    let mut button = Button::cast(obj.clone().into())?;
    button.set_modifiers(modifiers.clone())?;
    signal::emit_object_signal(lua,
                        obj.into(),
                        "property::modifiers".into(),
                        modifiers)?;
    Ok(Value::Nil)
}

fn get_modifiers<'lua>(lua: &'lua Lua, obj: AnyUserData<'lua>)
                    -> rlua::Result<Value<'lua>> {
    use ::lua::mods_to_lua;
    mods_to_lua(lua, Button::cast(obj.into())?.modifiers()?).map(Value::Table)
}

#[cfg(test)]
mod test {
    use rlua::{AnyUserData, Lua};
    use super::super::button::{self, Button};
    use super::super::object;

    #[test]
    fn button_object_test() {
        let lua = Lua::new();
        button::init(&lua).unwrap();
        lua.globals().set("button0", Button::new(&lua, lua.create_table().unwrap()).unwrap())
            .unwrap();
        lua.globals().set("button1", Button::new(&lua, lua.create_table().unwrap()).unwrap())
            .unwrap();
        lua.eval(r#"
assert(button0.button == 0)
assert(button1.button == 0)
button0:connect_signal("test", function(button) button.button = 3 end)
button0:emit_signal("test")
assert(button1.button == 0)
assert(button0.button == 3)
"#, None).unwrap()
    }

    #[test]
    fn button_class_test() {
        let lua = Lua::new();
        button::init(&lua).unwrap();
        lua.eval(r#"
a_button = button{}
assert(a_button.button == 0)
a_button:connect_signal("test", function(button) button.button = 2 end)
a_button:emit_signal("test")
assert(a_button.button == 2)
"#, None).unwrap()
    }

    #[test]
    fn button_property_test() {
        let lua = Lua::new();
        let button_class = button::init(&lua).unwrap();
        assert_eq!(button_class.properties().unwrap().len().unwrap(), 2);
        lua.eval(r#"
a_button = button{}
assert(a_button.button == 0)
a_button.button = 5
assert(a_button.button == 5)
"#, None).unwrap()
    }

    #[test]
    fn button_remove_signal_test() {
        let lua = Lua::new();
        button::init(&lua).unwrap();
        lua.eval(r#"
button0 = button{}
assert(button0.button == 0)
button0:connect_signal("test", function(button) button.button = 3 end)
button0:emit_signal("test")
assert(button0.button == 3)
button0.button = 0
button0:disconnect_signal("test")
button0:emit_signal("test")
assert(button0.button == 0)
"#, None).unwrap()
    }

    #[test]
    fn button_emit_signal_multiple_args() {
        let lua = Lua::new();
        button::init(&lua).unwrap();
        lua.globals().set("a_button", Button::new(&lua, lua.create_table().unwrap()).unwrap())
            .unwrap();
        lua.eval(r#"
 assert(a_button.button == 0)
 a_button:connect_signal("test", function(button, num) button.button = num end)
 a_button:emit_signal("test", 5)
 assert(a_button.button == 5)
 a_button:emit_signal("test", 0)
 assert(a_button.button == 0)
 "#, None).unwrap()
    }

    #[test]
    fn button_modifiers_test() {
        use rustwlc::*;
        use self::button::Button;
        use self::object::Objectable;
        let lua = Lua::new();
        button::init(&lua).unwrap();
        lua.globals().set("a_button", Button::new(&lua, lua.create_table().unwrap()).unwrap())
            .unwrap();
        let button = Button::cast(lua.globals().get::<_, AnyUserData>("a_button")
                                  .unwrap().into()).unwrap();
        assert_eq!(button.modifiers().unwrap(), KeyMod::empty());
        lua.eval::<()>(r#"
a_button.modifiers = { "Caps" }
"#, None).unwrap();
        assert_eq!(button.modifiers().unwrap(), MOD_CAPS);
    }

    #[test]
    fn button_multiple_modifiers_test() {
        use rustwlc::*;
        use self::button::Button;
        use self::object::Objectable;
        let lua = Lua::new();
        button::init(&lua).unwrap();
        lua.globals().set("a_button", Button::new(&lua, lua.create_table().unwrap()).unwrap())
            .unwrap();
        let button = Button::cast(lua.globals().get::<_, AnyUserData>("a_button")
                                  .unwrap().into()).unwrap();
        assert_eq!(button.modifiers().unwrap(), KeyMod::empty());
        lua.eval::<()>(r#"
a_button.modifiers = { "Caps", "Mod2" }
"#, None).unwrap();
        assert_eq!(button.modifiers().unwrap(), MOD_CAPS | MOD_MOD2);
    }

    #[test]
    /// Tests that setting the button index property updates the
    /// callback for all instances of button
    fn button_index_property() {
        let lua = Lua::new();
        button::init(&lua).unwrap();
        lua.globals().set("a_button", Button::new(&lua, lua.create_table().unwrap()).unwrap())
            .unwrap();
        lua.eval::<()>(r#"
hit = false
button.set_index_miss_handler(function(button)
    hit = true
    return 5
end)
assert(not hit)
a = button.button
assert(a ~= 5)
assert(not hit)
a = a_button.aoeu
assert(hit)
assert(a == 5)
a = nil
hit = false
a = button{}.aoeu
assert(hit)
assert(a == 5)
"#, None).unwrap()
    }

    #[test]
    fn button_modifiers_signal_test() {
        let lua = Lua::new();
        button::init(&lua).unwrap();
        lua.eval::<()>(r#"
a_button = button{}
hit = false
a_button:connect_signal("property::modifiers", function(button) hit = true end)
a_button:emit_signal("property::modifiers")
assert(hit)
hit = false
assert(not hit)
button.button = nil
assert(not hit)
a_button.modifiers = { "Caps", "Mod2" }
assert(hit)
"#, None).unwrap()
    }

    #[test]
    fn button_button_signal_test() {
        let lua = Lua::new();
        button::init(&lua).unwrap();
        lua.eval::<()>(r#"
a_button = button{}
hit = false
a_button:connect_signal("property::button", function(button) hit = true end)
a_button:emit_signal("property::button")
assert(hit)
hit = false
assert(not hit)
a_button.button = nil
assert(hit)
"#, None).unwrap()
    }

    #[test]
    fn button_test_valid() {
        let lua = Lua::new();
        button::init(&lua).unwrap();
        lua.eval::<()>(r#"
a_button = button{}
assert(a_button.valid)
"#, None).unwrap();
    }
}

<commit_msg>Better imports button.rs<commit_after>use std::fmt::{self, Display, Formatter};
use std::default::Default;
use rlua::{self, Table, Lua, UserData, ToLua, Value, AnyUserData, UserDataMethods, MetaMethod};
use super::object::{self, Object, Objectable};
use super::signal;
use super::property::Property;
use super::class::{self, Class};
use rustwlc::types::KeyMod;
use xcb::ffi::xproto::xcb_button_t;

#[derive(Clone, Debug)]
pub struct ButtonState {
    button: xcb_button_t,
    modifiers: KeyMod
}

#[derive(Clone, Debug)]
pub struct Button<'lua>(Object<'lua>);

impl Display for ButtonState {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Button: {:p}", self)
    }
}

impl Default for ButtonState {
    fn default() -> Self {
        ButtonState {
            button: xcb_button_t::default(),
            modifiers: KeyMod::empty()
        }
    }
}

impl UserData for ButtonState {
    fn add_methods(methods: &mut UserDataMethods<Self>) {
        methods.add_meta_function(MetaMethod::Index, object::default_index);
        methods.add_meta_function(MetaMethod::NewIndex, object::default_newindex)
    }
}

impl <'lua> Button<'lua> {
    fn new(lua: &'lua Lua, args: rlua::Table) -> rlua::Result<Object<'lua>> {
        let class = class::class_setup(lua, "button")?;
        Ok(Button::allocate(lua, class)?
           .handle_constructor_argument(args)?
           .build())
    }

    pub fn button(&self) -> rlua::Result<Value<'lua>> {
        let button = self.state()?;
        Ok(Value::Integer(button.button as _))
    }

    pub fn set_button(&mut self, new_val: xcb_button_t) -> rlua::Result<()> {
        let mut button = self.state()?;
        button.button = new_val;
        self.set_state(button)?;
        Ok(())
    }

    pub fn modifiers(&self) -> rlua::Result<KeyMod> {
        let button = self.state()?;
        Ok(button.modifiers)
    }

    pub fn set_modifiers(&mut self, mods: Table<'lua>) -> rlua::Result<()> {
        use ::lua::mods_to_rust;
        let mut button = self.state()?;
        button.modifiers = mods_to_rust(mods)?;
        self.set_state(button)?;
        Ok(())
    }
}

impl <'lua> ToLua<'lua> for Button<'lua> {
    fn to_lua(self, lua: &'lua Lua) -> rlua::Result<Value<'lua>> {
        self.0.to_lua(lua)
    }
}

impl_objectable!(Button, ButtonState);

pub fn init(lua: &Lua) -> rlua::Result<Class> {
    Class::builder(lua, "button", None, None, None)?
        .method("__call".into(),
                lua.create_function(|lua, (_, args): (rlua::Value, rlua::Table)| Button::new(lua, args))?)?
        .property(Property::new("button".into(),
                                Some(lua.create_function(set_button)?),
                                Some(lua.create_function(get_button)?),
                                Some(lua.create_function(set_button)?)))?
        .property(Property::new("modifiers".into(),
                                Some(lua.create_function(set_modifiers)?),
                                Some(lua.create_function(get_modifiers)?),
                                Some(lua.create_function(set_modifiers)?)))?
        .save_class("button")?
        .build()
}

fn set_button<'lua>(lua: &'lua Lua, (obj, val): (AnyUserData<'lua>, Value<'lua>))
                    -> rlua::Result<Value<'lua>> {
    use rlua::Value::*;
    let mut button = Button::cast(obj.clone().into())?;
    match val {
        Number(num) => button.set_button(num as _)?,
        Integer(num) => button.set_button(num as _)?,
        _ => button.set_button(xcb_button_t::default())?
    }
    signal::emit_object_signal(lua,
                        obj.into(),
                        "property::button".into(),
                        val)?;
    Ok(Value::Nil)
}

fn get_button<'lua>(_: &'lua Lua, obj: AnyUserData<'lua>)
                    -> rlua::Result<Value<'lua>> {
    Button::cast(obj.into())?.button()
}

fn set_modifiers<'lua>(lua: &'lua Lua, (obj, modifiers): (AnyUserData<'lua>, Table<'lua>))
                       -> rlua::Result<Value<'lua>> {
    let mut button = Button::cast(obj.clone().into())?;
    button.set_modifiers(modifiers.clone())?;
    signal::emit_object_signal(lua,
                        obj.into(),
                        "property::modifiers".into(),
                        modifiers)?;
    Ok(Value::Nil)
}

fn get_modifiers<'lua>(lua: &'lua Lua, obj: AnyUserData<'lua>)
                    -> rlua::Result<Value<'lua>> {
    use ::lua::mods_to_lua;
    mods_to_lua(lua, Button::cast(obj.into())?.modifiers()?).map(Value::Table)
}

#[cfg(test)]
mod test {
    use rlua::{AnyUserData, Lua};
    use super::super::button::{self, Button};
    use super::super::object;

    #[test]
    fn button_object_test() {
        let lua = Lua::new();
        button::init(&lua).unwrap();
        lua.globals().set("button0", Button::new(&lua, lua.create_table().unwrap()).unwrap())
            .unwrap();
        lua.globals().set("button1", Button::new(&lua, lua.create_table().unwrap()).unwrap())
            .unwrap();
        lua.eval(r#"
assert(button0.button == 0)
assert(button1.button == 0)
button0:connect_signal("test", function(button) button.button = 3 end)
button0:emit_signal("test")
assert(button1.button == 0)
assert(button0.button == 3)
"#, None).unwrap()
    }

    #[test]
    fn button_class_test() {
        let lua = Lua::new();
        button::init(&lua).unwrap();
        lua.eval(r#"
a_button = button{}
assert(a_button.button == 0)
a_button:connect_signal("test", function(button) button.button = 2 end)
a_button:emit_signal("test")
assert(a_button.button == 2)
"#, None).unwrap()
    }

    #[test]
    fn button_property_test() {
        let lua = Lua::new();
        let button_class = button::init(&lua).unwrap();
        assert_eq!(button_class.properties().unwrap().len().unwrap(), 2);
        lua.eval(r#"
a_button = button{}
assert(a_button.button == 0)
a_button.button = 5
assert(a_button.button == 5)
"#, None).unwrap()
    }

    #[test]
    fn button_remove_signal_test() {
        let lua = Lua::new();
        button::init(&lua).unwrap();
        lua.eval(r#"
button0 = button{}
assert(button0.button == 0)
button0:connect_signal("test", function(button) button.button = 3 end)
button0:emit_signal("test")
assert(button0.button == 3)
button0.button = 0
button0:disconnect_signal("test")
button0:emit_signal("test")
assert(button0.button == 0)
"#, None).unwrap()
    }

    #[test]
    fn button_emit_signal_multiple_args() {
        let lua = Lua::new();
        button::init(&lua).unwrap();
        lua.globals().set("a_button", Button::new(&lua, lua.create_table().unwrap()).unwrap())
            .unwrap();
        lua.eval(r#"
 assert(a_button.button == 0)
 a_button:connect_signal("test", function(button, num) button.button = num end)
 a_button:emit_signal("test", 5)
 assert(a_button.button == 5)
 a_button:emit_signal("test", 0)
 assert(a_button.button == 0)
 "#, None).unwrap()
    }

    #[test]
    fn button_modifiers_test() {
        use rustwlc::*;
        use self::button::Button;
        use self::object::Objectable;
        let lua = Lua::new();
        button::init(&lua).unwrap();
        lua.globals().set("a_button", Button::new(&lua, lua.create_table().unwrap()).unwrap())
            .unwrap();
        let button = Button::cast(lua.globals().get::<_, AnyUserData>("a_button")
                                  .unwrap().into()).unwrap();
        assert_eq!(button.modifiers().unwrap(), KeyMod::empty());
        lua.eval::<()>(r#"
a_button.modifiers = { "Caps" }
"#, None).unwrap();
        assert_eq!(button.modifiers().unwrap(), MOD_CAPS);
    }

    #[test]
    fn button_multiple_modifiers_test() {
        use rustwlc::*;
        use self::button::Button;
        use self::object::Objectable;
        let lua = Lua::new();
        button::init(&lua).unwrap();
        lua.globals().set("a_button", Button::new(&lua, lua.create_table().unwrap()).unwrap())
            .unwrap();
        let button = Button::cast(lua.globals().get::<_, AnyUserData>("a_button")
                                  .unwrap().into()).unwrap();
        assert_eq!(button.modifiers().unwrap(), KeyMod::empty());
        lua.eval::<()>(r#"
a_button.modifiers = { "Caps", "Mod2" }
"#, None).unwrap();
        assert_eq!(button.modifiers().unwrap(), MOD_CAPS | MOD_MOD2);
    }

    #[test]
    /// Tests that setting the button index property updates the
    /// callback for all instances of button
    fn button_index_property() {
        let lua = Lua::new();
        button::init(&lua).unwrap();
        lua.globals().set("a_button", Button::new(&lua, lua.create_table().unwrap()).unwrap())
            .unwrap();
        lua.eval::<()>(r#"
hit = false
button.set_index_miss_handler(function(button)
    hit = true
    return 5
end)
assert(not hit)
a = button.button
assert(a ~= 5)
assert(not hit)
a = a_button.aoeu
assert(hit)
assert(a == 5)
a = nil
hit = false
a = button{}.aoeu
assert(hit)
assert(a == 5)
"#, None).unwrap()
    }

    #[test]
    fn button_modifiers_signal_test() {
        let lua = Lua::new();
        button::init(&lua).unwrap();
        lua.eval::<()>(r#"
a_button = button{}
hit = false
a_button:connect_signal("property::modifiers", function(button) hit = true end)
a_button:emit_signal("property::modifiers")
assert(hit)
hit = false
assert(not hit)
button.button = nil
assert(not hit)
a_button.modifiers = { "Caps", "Mod2" }
assert(hit)
"#, None).unwrap()
    }

    #[test]
    fn button_button_signal_test() {
        let lua = Lua::new();
        button::init(&lua).unwrap();
        lua.eval::<()>(r#"
a_button = button{}
hit = false
a_button:connect_signal("property::button", function(button) hit = true end)
a_button:emit_signal("property::button")
assert(hit)
hit = false
assert(not hit)
a_button.button = nil
assert(hit)
"#, None).unwrap()
    }

    #[test]
    fn button_test_valid() {
        let lua = Lua::new();
        button::init(&lua).unwrap();
        lua.eval::<()>(r#"
a_button = button{}
assert(a_button.valid)
"#, None).unwrap();
    }
}

<|endoftext|>


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

use rustc_serialize::Encoder;
use rustc_serialize::Encodable;
use rustc_serialize::Decoder;
use rustc_serialize::Decodable;
use rustc_serialize::hex::FromHex;

#[derive(Clone,Debug)]
pub struct BytesContainer {
    bytes: Vec<u8>,
}

impl BytesContainer {
    pub fn new(bytes: Vec<u8>) -> BytesContainer {
        BytesContainer { bytes: bytes }
    }

    pub fn get<'a>(&'a self) -> &'a Vec<u8> {
        &self.bytes
    }

    pub fn get_mut<'a>(&'a mut self) -> &'a mut Vec<u8> {
        &mut self.bytes
    }

    pub fn to_bytestr(&self) -> String {
        let bytestr: Vec<String> = self.bytes.iter().map(|b| format!("{:02X}", b)).collect();
        bytestr.join("")
    }

    pub fn from_bytestr(bytestr: &str) -> Result<BytesContainer, ()> {
        println!("lese 2");

        match bytestr.from_hex() {
            Ok(vec) => Ok(BytesContainer::new(vec)),
            _ => Err(()),
        }
    }
}

impl Decodable for BytesContainer {
    fn decode<T: Decoder>(d: &mut T) -> Result<BytesContainer, T::Error> {
        let bytestr = try!(String::decode(d));
        match BytesContainer::from_bytestr(&bytestr) {
            Ok(bc) => Ok(bc),
            Err(_) => Err(d.error("Failed to parse hex string")),
        }
    }
}

impl Encodable for BytesContainer {
    fn encode<T: Encoder>(&self, d: &mut T) -> Result<(), T::Error> {
        self.to_bytestr().encode(d)
    }
}
<commit_msg>removed a testing println.<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2016 Marvin Böcker
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use rustc_serialize::Encoder;
use rustc_serialize::Encodable;
use rustc_serialize::Decoder;
use rustc_serialize::Decodable;
use rustc_serialize::hex::FromHex;

#[derive(Clone,Debug)]
pub struct BytesContainer {
    bytes: Vec<u8>,
}

impl BytesContainer {
    pub fn new(bytes: Vec<u8>) -> BytesContainer {
        BytesContainer { bytes: bytes }
    }

    pub fn get<'a>(&'a self) -> &'a Vec<u8> {
        &self.bytes
    }

    pub fn get_mut<'a>(&'a mut self) -> &'a mut Vec<u8> {
        &mut self.bytes
    }

    pub fn to_bytestr(&self) -> String {
        let bytestr: Vec<String> = self.bytes.iter().map(|b| format!("{:02X}", b)).collect();
        bytestr.join("")
    }

    pub fn from_bytestr(bytestr: &str) -> Result<BytesContainer, ()> {
        match bytestr.from_hex() {
            Ok(vec) => Ok(BytesContainer::new(vec)),
            _ => Err(()),
        }
    }
}

impl Decodable for BytesContainer {
    fn decode<T: Decoder>(d: &mut T) -> Result<BytesContainer, T::Error> {
        let bytestr = try!(String::decode(d));
        match BytesContainer::from_bytestr(&bytestr) {
            Ok(bc) => Ok(bc),
            Err(_) => Err(d.error("Failed to parse hex string")),
        }
    }
}

impl Encodable for BytesContainer {
    fn encode<T: Encoder>(&self, d: &mut T) -> Result<(), T::Error> {
        self.to_bytestr().encode(d)
    }
}
<|endoftext|>