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

//! An interface for numeric types
use cmp::{Eq, Ord};
use ops::{Neg, Add, Sub, Mul, Div, Modulo};
use option::Option;
use kinds::Copy;

pub mod strconv;

pub trait IntConvertible {
    fn to_int(&self) -> int;
    fn from_int(n: int) -> Self;
}

pub trait Zero {
    fn zero() -> Self;
}

pub trait One {
    fn one() -> Self;
}

pub fn abs<T:Ord + Zero + Neg<T>>(v: T) -> T {
    if v < Zero::zero() { v.neg() } else { v }
}

pub trait Round {
    fn round(&self, mode: RoundMode) -> Self;

    fn floor(&self) -> Self;
    fn ceil(&self)  -> Self;
    fn fract(&self) -> Self;
}

pub enum RoundMode {
    RoundDown,
    RoundUp,
    RoundToZero,
    RoundFromZero
}

/**
 * Cast from one machine scalar to another
 *
 * # Example
 *
 * ~~~
 * let twenty: f32 = num::cast(0x14);
 * assert!(twenty == 20f32);
 * ~~~
 */
#[inline(always)]
pub fn cast<T:NumCast,U:NumCast>(n: T) -> U {
    NumCast::from(n)
}

/**
 * An interface for casting between machine scalars
 */
pub trait NumCast {
    fn from<T:NumCast>(n: T) -> Self;

    fn to_u8(&self) -> u8;
    fn to_u16(&self) -> u16;
    fn to_u32(&self) -> u32;
    fn to_u64(&self) -> u64;
    fn to_uint(&self) -> uint;

    fn to_i8(&self) -> i8;
    fn to_i16(&self) -> i16;
    fn to_i32(&self) -> i32;
    fn to_i64(&self) -> i64;
    fn to_int(&self) -> int;

    fn to_f32(&self) -> f32;
    fn to_f64(&self) -> f64;
    fn to_float(&self) -> float;
}

macro_rules! impl_num_cast(
    ($T:ty, $conv:ident) => (
        // FIXME #4375: This enclosing module is necessary because
        // of a bug with macros expanding into multiple items
        pub mod $conv {
            use num::NumCast;

            #[cfg(notest)]
            impl NumCast for $T {
                #[doc = "Cast `n` to a `$T`"]
                #[inline(always)]
                fn from<N:NumCast>(n: N) -> $T {
                    // `$conv` could be generated using `concat_idents!`, but that
                    // macro seems to be broken at the moment
                    n.$conv()
                }

                #[inline(always)] fn to_u8(&self)    -> u8    { *self as u8    }
                #[inline(always)] fn to_u16(&self)   -> u16   { *self as u16   }
                #[inline(always)] fn to_u32(&self)   -> u32   { *self as u32   }
                #[inline(always)] fn to_u64(&self)   -> u64   { *self as u64   }
                #[inline(always)] fn to_uint(&self)  -> uint  { *self as uint  }

                #[inline(always)] fn to_i8(&self)    -> i8    { *self as i8    }
                #[inline(always)] fn to_i16(&self)   -> i16   { *self as i16   }
                #[inline(always)] fn to_i32(&self)   -> i32   { *self as i32   }
                #[inline(always)] fn to_i64(&self)   -> i64   { *self as i64   }
                #[inline(always)] fn to_int(&self)   -> int   { *self as int   }

                #[inline(always)] fn to_f32(&self)   -> f32   { *self as f32   }
                #[inline(always)] fn to_f64(&self)   -> f64   { *self as f64   }
                #[inline(always)] fn to_float(&self) -> float { *self as float }
            }
        }
    )
)

impl_num_cast!(u8,    to_u8)
impl_num_cast!(u16,   to_u16)
impl_num_cast!(u32,   to_u32)
impl_num_cast!(u64,   to_u64)
impl_num_cast!(uint,  to_uint)
impl_num_cast!(i8,    to_i8)
impl_num_cast!(i16,   to_i16)
impl_num_cast!(i32,   to_i32)
impl_num_cast!(i64,   to_i64)
impl_num_cast!(int,   to_int)
impl_num_cast!(f32,   to_f32)
impl_num_cast!(f64,   to_f64)
impl_num_cast!(float, to_float)

pub trait ToStrRadix {
    pub fn to_str_radix(&self, radix: uint) -> ~str;
}

pub trait FromStrRadix {
    pub fn from_str_radix(str: &str, radix: uint) -> Option<Self>;
}

// Generic math functions:

/**
 * Calculates a power to a given radix, optimized for uint `pow` and `radix`.
 *
 * Returns `radix^pow` as `T`.
 *
 * Note:
 * Also returns `1` for `0^0`, despite that technically being an
 * undefined number. The reason for this is twofold:
 * - If code written to use this function cares about that special case, it's
 *   probably going to catch it before making the call.
 * - If code written to use this function doesn't care about it, it's
 *   probably assuming that `x^0` always equals `1`.
 */
pub fn pow_with_uint<T:NumCast+One+Zero+Copy+Div<T,T>+Mul<T,T>>(
    radix: uint, pow: uint) -> T {
    let _0: T = Zero::zero();
    let _1: T = One::one();

    if pow   == 0u { return _1; }
    if radix == 0u { return _0; }
    let mut my_pow     = pow;
    let mut total      = _1;
    let mut multiplier = cast(radix as int);
    while (my_pow > 0u) {
        if my_pow % 2u == 1u {
            total *= multiplier;
        }
        my_pow     /= 2u;
        multiplier *= multiplier;
    }
    total
}

macro_rules! test_cast_20(
    ($_20:expr) => ({
        let _20 = $_20;

        assert!(20u   == _20.to_uint());
        assert!(20u8  == _20.to_u8());
        assert!(20u16 == _20.to_u16());
        assert!(20u32 == _20.to_u32());
        assert!(20u64 == _20.to_u64());
        assert!(20i   == _20.to_int());
        assert!(20i8  == _20.to_i8());
        assert!(20i16 == _20.to_i16());
        assert!(20i32 == _20.to_i32());
        assert!(20i64 == _20.to_i64());
        assert!(20f   == _20.to_float());
        assert!(20f32 == _20.to_f32());
        assert!(20f64 == _20.to_f64());

        assert!(_20 == NumCast::from(20u));
        assert!(_20 == NumCast::from(20u8));
        assert!(_20 == NumCast::from(20u16));
        assert!(_20 == NumCast::from(20u32));
        assert!(_20 == NumCast::from(20u64));
        assert!(_20 == NumCast::from(20i));
        assert!(_20 == NumCast::from(20i8));
        assert!(_20 == NumCast::from(20i16));
        assert!(_20 == NumCast::from(20i32));
        assert!(_20 == NumCast::from(20i64));
        assert!(_20 == NumCast::from(20f));
        assert!(_20 == NumCast::from(20f32));
        assert!(_20 == NumCast::from(20f64));

        assert!(_20 == cast(20u));
        assert!(_20 == cast(20u8));
        assert!(_20 == cast(20u16));
        assert!(_20 == cast(20u32));
        assert!(_20 == cast(20u64));
        assert!(_20 == cast(20i));
        assert!(_20 == cast(20i8));
        assert!(_20 == cast(20i16));
        assert!(_20 == cast(20i32));
        assert!(_20 == cast(20i64));
        assert!(_20 == cast(20f));
        assert!(_20 == cast(20f32));
        assert!(_20 == cast(20f64));
    })
)

#[test] fn test_u8_cast()    { test_cast_20!(20u8)  }
#[test] fn test_u16_cast()   { test_cast_20!(20u16) }
#[test] fn test_u32_cast()   { test_cast_20!(20u32) }
#[test] fn test_u64_cast()   { test_cast_20!(20u64) }
#[test] fn test_uint_cast()  { test_cast_20!(20u)   }
#[test] fn test_i8_cast()    { test_cast_20!(20i8)  }
#[test] fn test_i16_cast()   { test_cast_20!(20i16) }
#[test] fn test_i32_cast()   { test_cast_20!(20i32) }
#[test] fn test_i64_cast()   { test_cast_20!(20i64) }
#[test] fn test_int_cast()   { test_cast_20!(20i)   }
#[test] fn test_f32_cast()   { test_cast_20!(20f32) }
#[test] fn test_f64_cast()   { test_cast_20!(20f64) }
#[test] fn test_float_cast() { test_cast_20!(20f)   }<commit_msg>Add a test to show how NumCast can be used in type parameters<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! An interface for numeric types
use cmp::{Eq, Ord};
use ops::{Neg, Add, Sub, Mul, Div, Modulo};
use option::Option;
use kinds::Copy;

pub mod strconv;

pub trait IntConvertible {
    fn to_int(&self) -> int;
    fn from_int(n: int) -> Self;
}

pub trait Zero {
    fn zero() -> Self;
}

pub trait One {
    fn one() -> Self;
}

pub fn abs<T:Ord + Zero + Neg<T>>(v: T) -> T {
    if v < Zero::zero() { v.neg() } else { v }
}

pub trait Round {
    fn round(&self, mode: RoundMode) -> Self;

    fn floor(&self) -> Self;
    fn ceil(&self)  -> Self;
    fn fract(&self) -> Self;
}

pub enum RoundMode {
    RoundDown,
    RoundUp,
    RoundToZero,
    RoundFromZero
}

/**
 * Cast from one machine scalar to another
 *
 * # Example
 *
 * ~~~
 * let twenty: f32 = num::cast(0x14);
 * assert!(twenty == 20f32);
 * ~~~
 */
#[inline(always)]
pub fn cast<T:NumCast,U:NumCast>(n: T) -> U {
    NumCast::from(n)
}

/**
 * An interface for casting between machine scalars
 */
pub trait NumCast {
    fn from<T:NumCast>(n: T) -> Self;

    fn to_u8(&self) -> u8;
    fn to_u16(&self) -> u16;
    fn to_u32(&self) -> u32;
    fn to_u64(&self) -> u64;
    fn to_uint(&self) -> uint;

    fn to_i8(&self) -> i8;
    fn to_i16(&self) -> i16;
    fn to_i32(&self) -> i32;
    fn to_i64(&self) -> i64;
    fn to_int(&self) -> int;

    fn to_f32(&self) -> f32;
    fn to_f64(&self) -> f64;
    fn to_float(&self) -> float;
}

macro_rules! impl_num_cast(
    ($T:ty, $conv:ident) => (
        // FIXME #4375: This enclosing module is necessary because
        // of a bug with macros expanding into multiple items
        pub mod $conv {
            use num::NumCast;

            #[cfg(notest)]
            impl NumCast for $T {
                #[doc = "Cast `n` to a `$T`"]
                #[inline(always)]
                fn from<N:NumCast>(n: N) -> $T {
                    // `$conv` could be generated using `concat_idents!`, but that
                    // macro seems to be broken at the moment
                    n.$conv()
                }

                #[inline(always)] fn to_u8(&self)    -> u8    { *self as u8    }
                #[inline(always)] fn to_u16(&self)   -> u16   { *self as u16   }
                #[inline(always)] fn to_u32(&self)   -> u32   { *self as u32   }
                #[inline(always)] fn to_u64(&self)   -> u64   { *self as u64   }
                #[inline(always)] fn to_uint(&self)  -> uint  { *self as uint  }

                #[inline(always)] fn to_i8(&self)    -> i8    { *self as i8    }
                #[inline(always)] fn to_i16(&self)   -> i16   { *self as i16   }
                #[inline(always)] fn to_i32(&self)   -> i32   { *self as i32   }
                #[inline(always)] fn to_i64(&self)   -> i64   { *self as i64   }
                #[inline(always)] fn to_int(&self)   -> int   { *self as int   }

                #[inline(always)] fn to_f32(&self)   -> f32   { *self as f32   }
                #[inline(always)] fn to_f64(&self)   -> f64   { *self as f64   }
                #[inline(always)] fn to_float(&self) -> float { *self as float }
            }
        }
    )
)

impl_num_cast!(u8,    to_u8)
impl_num_cast!(u16,   to_u16)
impl_num_cast!(u32,   to_u32)
impl_num_cast!(u64,   to_u64)
impl_num_cast!(uint,  to_uint)
impl_num_cast!(i8,    to_i8)
impl_num_cast!(i16,   to_i16)
impl_num_cast!(i32,   to_i32)
impl_num_cast!(i64,   to_i64)
impl_num_cast!(int,   to_int)
impl_num_cast!(f32,   to_f32)
impl_num_cast!(f64,   to_f64)
impl_num_cast!(float, to_float)

pub trait ToStrRadix {
    pub fn to_str_radix(&self, radix: uint) -> ~str;
}

pub trait FromStrRadix {
    pub fn from_str_radix(str: &str, radix: uint) -> Option<Self>;
}

// Generic math functions:

/**
 * Calculates a power to a given radix, optimized for uint `pow` and `radix`.
 *
 * Returns `radix^pow` as `T`.
 *
 * Note:
 * Also returns `1` for `0^0`, despite that technically being an
 * undefined number. The reason for this is twofold:
 * - If code written to use this function cares about that special case, it's
 *   probably going to catch it before making the call.
 * - If code written to use this function doesn't care about it, it's
 *   probably assuming that `x^0` always equals `1`.
 */
pub fn pow_with_uint<T:NumCast+One+Zero+Copy+Div<T,T>+Mul<T,T>>(
    radix: uint, pow: uint) -> T {
    let _0: T = Zero::zero();
    let _1: T = One::one();

    if pow   == 0u { return _1; }
    if radix == 0u { return _0; }
    let mut my_pow     = pow;
    let mut total      = _1;
    let mut multiplier = cast(radix as int);
    while (my_pow > 0u) {
        if my_pow % 2u == 1u {
            total *= multiplier;
        }
        my_pow     /= 2u;
        multiplier *= multiplier;
    }
    total
}

macro_rules! test_cast_20(
    ($_20:expr) => ({
        let _20 = $_20;

        assert!(20u   == _20.to_uint());
        assert!(20u8  == _20.to_u8());
        assert!(20u16 == _20.to_u16());
        assert!(20u32 == _20.to_u32());
        assert!(20u64 == _20.to_u64());
        assert!(20i   == _20.to_int());
        assert!(20i8  == _20.to_i8());
        assert!(20i16 == _20.to_i16());
        assert!(20i32 == _20.to_i32());
        assert!(20i64 == _20.to_i64());
        assert!(20f   == _20.to_float());
        assert!(20f32 == _20.to_f32());
        assert!(20f64 == _20.to_f64());

        assert!(_20 == NumCast::from(20u));
        assert!(_20 == NumCast::from(20u8));
        assert!(_20 == NumCast::from(20u16));
        assert!(_20 == NumCast::from(20u32));
        assert!(_20 == NumCast::from(20u64));
        assert!(_20 == NumCast::from(20i));
        assert!(_20 == NumCast::from(20i8));
        assert!(_20 == NumCast::from(20i16));
        assert!(_20 == NumCast::from(20i32));
        assert!(_20 == NumCast::from(20i64));
        assert!(_20 == NumCast::from(20f));
        assert!(_20 == NumCast::from(20f32));
        assert!(_20 == NumCast::from(20f64));

        assert!(_20 == cast(20u));
        assert!(_20 == cast(20u8));
        assert!(_20 == cast(20u16));
        assert!(_20 == cast(20u32));
        assert!(_20 == cast(20u64));
        assert!(_20 == cast(20i));
        assert!(_20 == cast(20i8));
        assert!(_20 == cast(20i16));
        assert!(_20 == cast(20i32));
        assert!(_20 == cast(20i64));
        assert!(_20 == cast(20f));
        assert!(_20 == cast(20f32));
        assert!(_20 == cast(20f64));
    })
)

#[test] fn test_u8_cast()    { test_cast_20!(20u8)  }
#[test] fn test_u16_cast()   { test_cast_20!(20u16) }
#[test] fn test_u32_cast()   { test_cast_20!(20u32) }
#[test] fn test_u64_cast()   { test_cast_20!(20u64) }
#[test] fn test_uint_cast()  { test_cast_20!(20u)   }
#[test] fn test_i8_cast()    { test_cast_20!(20i8)  }
#[test] fn test_i16_cast()   { test_cast_20!(20i16) }
#[test] fn test_i32_cast()   { test_cast_20!(20i32) }
#[test] fn test_i64_cast()   { test_cast_20!(20i64) }
#[test] fn test_int_cast()   { test_cast_20!(20i)   }
#[test] fn test_f32_cast()   { test_cast_20!(20f32) }
#[test] fn test_f64_cast()   { test_cast_20!(20f64) }
#[test] fn test_float_cast() { test_cast_20!(20f)   }

#[test]
fn test_generic_cast() {
    use ops::Add;

    fn add_2<T: Add<T,T> + NumCast>(n: T) -> T {
        n + cast(2)
    }

    assert!(add_2(1u)   == 3u);
    assert!(add_2(1u8)  == 3u8);
    assert!(add_2(1u16) == 3u16);
    assert!(add_2(1u32) == 3u32);
    assert!(add_2(1u64) == 3u64);
    assert!(add_2(1i)   == 3i);
    assert!(add_2(1i8)  == 3i8);
    assert!(add_2(1i16) == 3i16);
    assert!(add_2(1i32) == 3i32);
    assert!(add_2(1i64) == 3i64);
    assert!(add_2(1f)   == 3f);
    assert!(add_2(1f32) == 3f32);
    assert!(add_2(1f64) == 3f64);
}
<|endoftext|>


<commit_before>//! Data structure for a small block of terrain.

use cgmath;
use cgmath::{Point, Point3, Vector3, Vector, EuclideanVector, Matrix, Aabb, Aabb3};
use isosurface_extraction::dual_contouring;
use num::iter::range_inclusive;
use rand;
use rand::Rng;
use std::f32;
use std::sync::{Arc, Mutex};
use stopwatch;

use common::entity_id;
use common::id_allocator;
use common::voxel;
// TODO: Move the server-only parts to the server, like BLOCK_WIDTH and sample_info.

use block_position;
use lod;

/// Number of LODs
pub const LOD_COUNT: usize = 4;
/// lg(WIDTH)
pub const LG_WIDTH: i16 = 3;
/// The width of a block of terrain.
pub const WIDTH: i32 = 1 << LG_WIDTH;

/// lg(EDGE_SAMPLES)
// NOTE: If there are duplicates here, weird invariants will fail.
// Just remove the LODs if you don't want duplicates.
pub const LG_EDGE_SAMPLES: [u16; LOD_COUNT] = [3, 2, 1, 0];
/// The number of voxels along an axis within a block, indexed by LOD.
pub const EDGE_SAMPLES: [u16; LOD_COUNT] = [
  1 << LG_EDGE_SAMPLES[0],
  1 << LG_EDGE_SAMPLES[1],
  1 << LG_EDGE_SAMPLES[2],
  1 << LG_EDGE_SAMPLES[3],
];

/// The width of a voxel within a block, indexed by LOD.
pub const LG_SAMPLE_SIZE: [i16; LOD_COUNT] = [
  LG_WIDTH - LG_EDGE_SAMPLES[0] as i16,
  LG_WIDTH - LG_EDGE_SAMPLES[1] as i16,
  LG_WIDTH - LG_EDGE_SAMPLES[2] as i16,
  LG_WIDTH - LG_EDGE_SAMPLES[3] as i16,
];

#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable)]
/// [T; 3], but serializable.
pub struct Triangle<T> {
  #[allow(missing_docs)]
  pub v1: T,
  #[allow(missing_docs)]
  pub v2: T,
  #[allow(missing_docs)]
  pub v3: T,
}

/// Construct a triangle.
pub fn tri<T>(v1: T, v2: T, v3: T) -> Triangle<T> {
  Triangle {
    v1: v1,
    v2: v2,
    v3: v3,
  }
}

fn make_bounds(
  v1: &Point3<f32>,
  v2: &Point3<f32>,
  v3: &Point3<f32>,
) -> Aabb3<f32> {
  let minx = f32::min(v1.x, f32::min(v2.x, v3.x));
  let maxx = f32::max(v1.x, f32::max(v2.x, v3.x));

  let miny = f32::min(v1.y, f32::min(v2.y, v3.y));
  let maxy = f32::max(v1.y, f32::max(v2.y, v3.y));

  let minz = f32::min(v1.z, f32::min(v2.z, v3.z));
  let maxz = f32::max(v1.z, f32::max(v2.z, v3.z));

  Aabb3::new(
    // TODO: Remove this - 1.0. It's a temporary hack until voxel collisions work,
    // to avoid zero-height Aabb3s.
    Point3::new(minx, miny - 1.0, minz),
    Point3::new(maxx, maxy, maxz),
  )
}

pub fn voxels_in(bounds: &Aabb3<i32>, lg_size: i16) -> Vec<voxel::bounds::T> {
  let delta = bounds.max().sub_p(bounds.min());

  // assert that lg_size samples fit neatly into the bounds.
  let mod_size = (1 << lg_size) - 1;
  assert!(bounds.min().x & mod_size == 0);
  assert!(bounds.min().y & mod_size == 0);
  assert!(bounds.min().z & mod_size == 0);
  assert!(bounds.max().x & mod_size == 0);
  assert!(bounds.max().y & mod_size == 0);
  assert!(bounds.max().z & mod_size == 0);

  let x_len = delta.x >> lg_size;
  let y_len = delta.y >> lg_size;
  let z_len = delta.z >> lg_size;

  let x_off = bounds.min().x >> lg_size;
  let y_off = bounds.min().y >> lg_size;
  let z_off = bounds.min().z >> lg_size;

  let mut voxels =
    Vec::with_capacity(x_len as usize + y_len as usize + z_len as usize);

  for dx in 0 .. x_len {
  for dy in 0 .. y_len {
  for dz in 0 .. z_len {
    let x = x_off + dx;
    let y = y_off + dy;
    let z = z_off + dz;
    voxels.push(voxel::bounds::new(x, y, z, lg_size));
  }}}
  voxels
}

mod voxel_storage {
  use isosurface_extraction::dual_contouring;

  use common::voxel;

  pub struct T<'a> {
    pub voxels: &'a voxel::tree::T,
  }

  fn get_voxel<'a>(this: &mut T<'a>, bounds: &voxel::bounds::T) -> Option<&'a voxel::T> {
    trace!("fetching {:?}", bounds);
    Some(this.voxels.get(bounds).unwrap_or_else(|| panic!("No entry for {:?}", bounds)))
  }

  impl<'a> dual_contouring::voxel_storage::T<voxel::Material> for T<'a> {
    fn get_material(&mut self, bounds: &voxel::bounds::T) -> Option<voxel::Material> {
      match get_voxel(self, bounds) {
        None => None,
        Some(&voxel::Surface(ref voxel)) => Some(voxel.corner),
        Some(&voxel::Volume(ref material)) => Some(*material),
      }
    }

    fn get_voxel_data(&mut self, bounds: &voxel::bounds::T) -> Option<dual_contouring::voxel_storage::VoxelData> {
      match get_voxel(self, bounds) {
        None => None,
        Some(&voxel::Volume(_)) => panic!("Can't extract voxel data from a volume"),
        Some(&voxel::Surface(ref voxel)) =>
          Some({
            dual_contouring::voxel_storage::VoxelData {
              bounds: *bounds,
              vertex: voxel.surface_vertex.to_world_vertex(&bounds),
              normal: voxel.normal.to_float_normal(),
            }
          })
      }
    }
  }
}

fn place_grass<T, Rng: rand::Rng>(
  polygon: &dual_contouring::polygon::T<T>,
  rng: &mut Rng,
) -> Vec<Grass> {
  let v = &polygon.vertices;
  let normal = v[1].sub_p(&v[0]).cross(&v[2].sub_p(&v[0]));
  let to_middle =
    &v[0].to_vec()
    .add_v(&v[1].to_vec())
    .add_v(&v[2].to_vec())
    .div_s(3.0)
  ;

  let y = cgmath::Vector3::new(0.0, 1.0, 0.0);
  let z = cgmath::Vector3::new(0.0, 0.0, 1.0);

  let scale =
    (rng.next_f32() + 1.0) *
         (v[1].sub_p(&v[0]).length())
    .max((v[2].sub_p(&v[1]).length())
    .max((v[0].sub_p(&v[2]).length())));
  let scale = cgmath::Vector3::new(1.0, 0.5, 1.0) * cgmath::Vector3::from_value(scale);

  let normal = normal.normalize();

  // TODO: Point straight up
  let up =
  {
    let altitude = (rng.next_f32()  * 2.0 - 1.0) * f32::consts::PI / 6.0;
    let altitude: cgmath::Matrix3<f32> = cgmath::Matrix3::from_axis_angle(&z, cgmath::rad(altitude));
    let azimuth = rng.next_f32() * 2.0 * f32::consts::PI;
    let azimuth: cgmath::Matrix3<f32> = cgmath::Matrix3::from_axis_angle(&y, cgmath::rad(azimuth));
    (azimuth * altitude).mul_v(&normal)
  };

  let rotate_up: cgmath::Quaternion<f32> = cgmath::Rotation::between_vectors(&y, &up);
  let rotate_up: cgmath::Matrix4<f32> = From::from(rotate_up);

  let rotate_root: cgmath::Quaternion<f32> = cgmath::Rotation3::from_axis_angle(&y, cgmath::rad(2.0 * f32::consts::PI * rng.next_f32()));
  let rotate_root: cgmath::Matrix4<f32> = From::from(rotate_root);

  let translate = cgmath::Matrix4::from_translation(&to_middle);

  let mut scale_mat = cgmath::Matrix4::from_value(1.0);
  scale_mat[0][0] = scale[0];
  scale_mat[1][1] = scale[1];
  scale_mat[2][2] = scale[2];

  let model = From::from(translate * rotate_up * rotate_root * scale_mat);

  let billboard_indices = [
    rng.gen_range(0, 9),
    rng.gen_range(0, 9),
    rng.gen_range(0, 9),
  ];
  vec!(
    Grass {
      model_matrix: model,
      normal: normal,
      tex_ids: billboard_indices,
    }
  )
}

pub fn generate<Rng: rand::Rng>(
  voxels: &voxel::tree::T,
  block_position: &block_position::T,
  lod: lod::T,
  id_allocator: &Mutex<id_allocator::T<entity_id::T>>,
  rng: &mut Rng,
) -> T
{
  stopwatch::time("terrain_mesh::generate", || {
    let mut block = empty();
    {
      let block2 = Arc::make_mut(&mut block);

      let lg_edge_samples = LG_EDGE_SAMPLES[lod.0 as usize];
      let lg_sample_size = LG_SAMPLE_SIZE[lod.0 as usize];

      let low = *block_position.as_pnt();
      let high = low.add_v(&Vector3::new(1, 1, 1));
      let low =
        Point3::new(
          low.x << lg_edge_samples,
          low.y << lg_edge_samples,
          low.z << lg_edge_samples,
        );
      let high =
        Point3::new(
          high.x << lg_edge_samples,
          high.y << lg_edge_samples,
          high.z << lg_edge_samples,
        );

      trace!("low {:?}", low);
      trace!("high {:?}", high);

      {
        let mut edges = |direction, low_x, high_x, low_y, high_y, low_z, high_z| {
          for x in range_inclusive(low_x, high_x) {
          for y in range_inclusive(low_y, high_y) {
          for z in range_inclusive(low_z, high_z) {
            trace!("edge: {:?} {:?}", direction, Point3::new(x, y, z));
            let edge =
              dual_contouring::edge::T {
                low_corner: Point3::new(x, y, z),
                direction: direction,
                lg_size: lg_sample_size,
              };

            let _ =
              dual_contouring::edge::extract(
                &mut voxel_storage::T { voxels: voxels },
                &edge,
                &mut |polygon: dual_contouring::polygon::T<voxel::Material>| {
                  let id = id_allocator::allocate(id_allocator);

                  block2.vertex_coordinates.push(tri(polygon.vertices[0], polygon.vertices[1], polygon.vertices[2]));
                  block2.normals.push(tri(polygon.normals[0], polygon.normals[1], polygon.normals[2]));
                  block2.materials.push(polygon.material as i32);
                  block2.ids.push(id);
                  let v = &polygon.vertices;
                  block2.bounds.push((id, make_bounds(&v[0], &v[1], &v[2])));

                  if polygon.material == voxel::Material::Terrain && lod <= lod::T(1) {
                    for grass in place_grass(&polygon, rng) {
                      let id = id_allocator::allocate(id_allocator);
                      block2.grass.push(grass);
                      block2.grass_ids.push(id);
                    }
                  }
                }
              );
          }}}
        };

        edges(
          dual_contouring::edge::Direction::X,
          low.x, high.x - 1,
          low.y, high.y - 1,
          low.z, high.z - 1,
        );
        edges(
          dual_contouring::edge::Direction::Y,
          low.x, high.x - 1,
          low.y, high.y - 1,
          low.z, high.z - 1,
        );
        edges(
          dual_contouring::edge::Direction::Z,
          low.x, high.x - 1,
          low.y, high.y - 1,
          low.z, high.z - 1,
        );
      }
    }
    block
  })
}

#[derive(Debug, Clone)]
pub struct Grass {
  pub model_matrix: cgmath::Matrix4<f32>,
  pub normal: cgmath::Vector3<f32>,
  pub tex_ids: [u32; 3],
}

#[derive(Debug, Clone)]
/// A small continguous chunk of terrain.
pub struct T2 {
  // These Vecs must all be ordered the same way; each entry is the next triangle.

  /// Position of each vertex.
  pub vertex_coordinates: Vec<Triangle<Point3<f32>>>,
  /// Vertex normals. These should be normalized!
  pub normals: Vec<Triangle<Vector3<f32>>>,
  /// Entity IDs for each triangle.
  pub ids: Vec<entity_id::T>,
  /// Material IDs for each triangle.
  pub materials: Vec<i32>,
  // TODO: Change this back to a HashMap once initial capacity is zero for those.
  /// Per-triangle bounding boxes.
  pub bounds: Vec<(entity_id::T, Aabb3<f32>)>,

  pub grass: Vec<Grass>,
  pub grass_ids: Vec<entity_id::T>,
}

pub type T = Arc<T2>;

/// Construct an empty `T`.
pub fn empty() -> T {
  Arc::new(T2 {
    vertex_coordinates: Vec::new(),
    normals: Vec::new(),

    ids: Vec::new(),
    materials: Vec::new(),
    bounds: Vec::new(),

    grass: Vec::new(),
    grass_ids: Vec::new(),
  })
}
<commit_msg>grass points roughly straight up<commit_after>//! Data structure for a small block of terrain.

use cgmath;
use cgmath::{Point, Point3, Vector3, Vector, EuclideanVector, Matrix, Aabb, Aabb3};
use isosurface_extraction::dual_contouring;
use num::iter::range_inclusive;
use rand;
use rand::Rng;
use std::f32;
use std::sync::{Arc, Mutex};
use stopwatch;

use common::entity_id;
use common::id_allocator;
use common::voxel;
// TODO: Move the server-only parts to the server, like BLOCK_WIDTH and sample_info.

use block_position;
use lod;

/// Number of LODs
pub const LOD_COUNT: usize = 4;
/// lg(WIDTH)
pub const LG_WIDTH: i16 = 3;
/// The width of a block of terrain.
pub const WIDTH: i32 = 1 << LG_WIDTH;

/// lg(EDGE_SAMPLES)
// NOTE: If there are duplicates here, weird invariants will fail.
// Just remove the LODs if you don't want duplicates.
pub const LG_EDGE_SAMPLES: [u16; LOD_COUNT] = [3, 2, 1, 0];
/// The number of voxels along an axis within a block, indexed by LOD.
pub const EDGE_SAMPLES: [u16; LOD_COUNT] = [
  1 << LG_EDGE_SAMPLES[0],
  1 << LG_EDGE_SAMPLES[1],
  1 << LG_EDGE_SAMPLES[2],
  1 << LG_EDGE_SAMPLES[3],
];

/// The width of a voxel within a block, indexed by LOD.
pub const LG_SAMPLE_SIZE: [i16; LOD_COUNT] = [
  LG_WIDTH - LG_EDGE_SAMPLES[0] as i16,
  LG_WIDTH - LG_EDGE_SAMPLES[1] as i16,
  LG_WIDTH - LG_EDGE_SAMPLES[2] as i16,
  LG_WIDTH - LG_EDGE_SAMPLES[3] as i16,
];

#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable)]
/// [T; 3], but serializable.
pub struct Triangle<T> {
  #[allow(missing_docs)]
  pub v1: T,
  #[allow(missing_docs)]
  pub v2: T,
  #[allow(missing_docs)]
  pub v3: T,
}

/// Construct a triangle.
pub fn tri<T>(v1: T, v2: T, v3: T) -> Triangle<T> {
  Triangle {
    v1: v1,
    v2: v2,
    v3: v3,
  }
}

fn make_bounds(
  v1: &Point3<f32>,
  v2: &Point3<f32>,
  v3: &Point3<f32>,
) -> Aabb3<f32> {
  let minx = f32::min(v1.x, f32::min(v2.x, v3.x));
  let maxx = f32::max(v1.x, f32::max(v2.x, v3.x));

  let miny = f32::min(v1.y, f32::min(v2.y, v3.y));
  let maxy = f32::max(v1.y, f32::max(v2.y, v3.y));

  let minz = f32::min(v1.z, f32::min(v2.z, v3.z));
  let maxz = f32::max(v1.z, f32::max(v2.z, v3.z));

  Aabb3::new(
    // TODO: Remove this - 1.0. It's a temporary hack until voxel collisions work,
    // to avoid zero-height Aabb3s.
    Point3::new(minx, miny - 1.0, minz),
    Point3::new(maxx, maxy, maxz),
  )
}

pub fn voxels_in(bounds: &Aabb3<i32>, lg_size: i16) -> Vec<voxel::bounds::T> {
  let delta = bounds.max().sub_p(bounds.min());

  // assert that lg_size samples fit neatly into the bounds.
  let mod_size = (1 << lg_size) - 1;
  assert!(bounds.min().x & mod_size == 0);
  assert!(bounds.min().y & mod_size == 0);
  assert!(bounds.min().z & mod_size == 0);
  assert!(bounds.max().x & mod_size == 0);
  assert!(bounds.max().y & mod_size == 0);
  assert!(bounds.max().z & mod_size == 0);

  let x_len = delta.x >> lg_size;
  let y_len = delta.y >> lg_size;
  let z_len = delta.z >> lg_size;

  let x_off = bounds.min().x >> lg_size;
  let y_off = bounds.min().y >> lg_size;
  let z_off = bounds.min().z >> lg_size;

  let mut voxels =
    Vec::with_capacity(x_len as usize + y_len as usize + z_len as usize);

  for dx in 0 .. x_len {
  for dy in 0 .. y_len {
  for dz in 0 .. z_len {
    let x = x_off + dx;
    let y = y_off + dy;
    let z = z_off + dz;
    voxels.push(voxel::bounds::new(x, y, z, lg_size));
  }}}
  voxels
}

mod voxel_storage {
  use isosurface_extraction::dual_contouring;

  use common::voxel;

  pub struct T<'a> {
    pub voxels: &'a voxel::tree::T,
  }

  fn get_voxel<'a>(this: &mut T<'a>, bounds: &voxel::bounds::T) -> Option<&'a voxel::T> {
    trace!("fetching {:?}", bounds);
    Some(this.voxels.get(bounds).unwrap_or_else(|| panic!("No entry for {:?}", bounds)))
  }

  impl<'a> dual_contouring::voxel_storage::T<voxel::Material> for T<'a> {
    fn get_material(&mut self, bounds: &voxel::bounds::T) -> Option<voxel::Material> {
      match get_voxel(self, bounds) {
        None => None,
        Some(&voxel::Surface(ref voxel)) => Some(voxel.corner),
        Some(&voxel::Volume(ref material)) => Some(*material),
      }
    }

    fn get_voxel_data(&mut self, bounds: &voxel::bounds::T) -> Option<dual_contouring::voxel_storage::VoxelData> {
      match get_voxel(self, bounds) {
        None => None,
        Some(&voxel::Volume(_)) => panic!("Can't extract voxel data from a volume"),
        Some(&voxel::Surface(ref voxel)) =>
          Some({
            dual_contouring::voxel_storage::VoxelData {
              bounds: *bounds,
              vertex: voxel.surface_vertex.to_world_vertex(&bounds),
              normal: voxel.normal.to_float_normal(),
            }
          })
      }
    }
  }
}

fn place_grass<T, Rng: rand::Rng>(
  polygon: &dual_contouring::polygon::T<T>,
  rng: &mut Rng,
) -> Vec<Grass> {
  let v = &polygon.vertices;
  let normal = v[1].sub_p(&v[0]).cross(&v[2].sub_p(&v[0]));
  let to_middle =
    &v[0].to_vec()
    .add_v(&v[1].to_vec())
    .add_v(&v[2].to_vec())
    .div_s(3.0)
  ;

  let y = cgmath::Vector3::new(0.0, 1.0, 0.0);
  let z = cgmath::Vector3::new(0.0, 0.0, 1.0);

  let scale =
    (rng.next_f32() + 1.0) *
         (v[1].sub_p(&v[0]).length())
    .max((v[2].sub_p(&v[1]).length())
    .max((v[0].sub_p(&v[2]).length())));
  let scale = cgmath::Vector3::new(1.0, 0.5, 1.0) * cgmath::Vector3::from_value(scale);

  let normal = normal.normalize();

  let skew = {
    let d = normal.dot(&y);
    let skewness = (1.0 - d*d).sqrt();
    let mut skew = cgmath::Matrix4::from_value(1.0);
    skew[1][0] = -normal.x * skewness;
    skew[1][1] = d;
    skew[1][2] = -normal.z * skewness;
    skew
  };

  let up = {
    let altitude = (rng.next_f32()  * 2.0 - 1.0) * f32::consts::PI / 8.0;
    let altitude: cgmath::Matrix3<f32> = cgmath::Matrix3::from_axis_angle(&z, cgmath::rad(altitude));
    let azimuth = rng.next_f32() * 2.0 * f32::consts::PI;
    let azimuth: cgmath::Matrix3<f32> = cgmath::Matrix3::from_axis_angle(&y, cgmath::rad(azimuth));
    let to_normal: cgmath::Basis3<f32> = cgmath::Rotation::between_vectors(&y, &normal);
    (*to_normal.as_ref() * azimuth * altitude).mul_v(&y)
  };

  let rotate_up: cgmath::Quaternion<f32> = cgmath::Rotation::between_vectors(&y, &up);
  let rotate_up: cgmath::Matrix4<f32> = From::from(rotate_up);

  let rotate_root: cgmath::Quaternion<f32> = cgmath::Rotation3::from_axis_angle(&y, cgmath::rad(2.0 * f32::consts::PI * rng.next_f32()));
  let rotate_root: cgmath::Matrix4<f32> = From::from(rotate_root);

  let translate = cgmath::Matrix4::from_translation(&to_middle);

  let mut scale_mat = cgmath::Matrix4::from_value(1.0);
  scale_mat[0][0] = scale[0];
  scale_mat[1][1] = scale[1];
  scale_mat[2][2] = scale[2];

  let model = From::from(translate * rotate_up * skew * rotate_root * scale_mat);

  let billboard_indices = [
    rng.gen_range(0, 9),
    rng.gen_range(0, 9),
    rng.gen_range(0, 9),
  ];
  vec!(
    Grass {
      model_matrix: model,
      normal: normal,
      tex_ids: billboard_indices,
    }
  )
}

pub fn generate<Rng: rand::Rng>(
  voxels: &voxel::tree::T,
  block_position: &block_position::T,
  lod: lod::T,
  id_allocator: &Mutex<id_allocator::T<entity_id::T>>,
  rng: &mut Rng,
) -> T
{
  stopwatch::time("terrain_mesh::generate", || {
    let mut block = empty();
    {
      let block2 = Arc::make_mut(&mut block);

      let lg_edge_samples = LG_EDGE_SAMPLES[lod.0 as usize];
      let lg_sample_size = LG_SAMPLE_SIZE[lod.0 as usize];

      let low = *block_position.as_pnt();
      let high = low.add_v(&Vector3::new(1, 1, 1));
      let low =
        Point3::new(
          low.x << lg_edge_samples,
          low.y << lg_edge_samples,
          low.z << lg_edge_samples,
        );
      let high =
        Point3::new(
          high.x << lg_edge_samples,
          high.y << lg_edge_samples,
          high.z << lg_edge_samples,
        );

      trace!("low {:?}", low);
      trace!("high {:?}", high);

      {
        let mut edges = |direction, low_x, high_x, low_y, high_y, low_z, high_z| {
          for x in range_inclusive(low_x, high_x) {
          for y in range_inclusive(low_y, high_y) {
          for z in range_inclusive(low_z, high_z) {
            trace!("edge: {:?} {:?}", direction, Point3::new(x, y, z));
            let edge =
              dual_contouring::edge::T {
                low_corner: Point3::new(x, y, z),
                direction: direction,
                lg_size: lg_sample_size,
              };

            let _ =
              dual_contouring::edge::extract(
                &mut voxel_storage::T { voxels: voxels },
                &edge,
                &mut |polygon: dual_contouring::polygon::T<voxel::Material>| {
                  let id = id_allocator::allocate(id_allocator);

                  block2.vertex_coordinates.push(tri(polygon.vertices[0], polygon.vertices[1], polygon.vertices[2]));
                  block2.normals.push(tri(polygon.normals[0], polygon.normals[1], polygon.normals[2]));
                  block2.materials.push(polygon.material as i32);
                  block2.ids.push(id);
                  let v = &polygon.vertices;
                  block2.bounds.push((id, make_bounds(&v[0], &v[1], &v[2])));

                  if polygon.material == voxel::Material::Terrain && lod <= lod::T(1) {
                    for grass in place_grass(&polygon, rng) {
                      let id = id_allocator::allocate(id_allocator);
                      block2.grass.push(grass);
                      block2.grass_ids.push(id);
                    }
                  }
                }
              );
          }}}
        };

        edges(
          dual_contouring::edge::Direction::X,
          low.x, high.x - 1,
          low.y, high.y - 1,
          low.z, high.z - 1,
        );
        edges(
          dual_contouring::edge::Direction::Y,
          low.x, high.x - 1,
          low.y, high.y - 1,
          low.z, high.z - 1,
        );
        edges(
          dual_contouring::edge::Direction::Z,
          low.x, high.x - 1,
          low.y, high.y - 1,
          low.z, high.z - 1,
        );
      }
    }
    block
  })
}

#[derive(Debug, Clone)]
pub struct Grass {
  pub model_matrix: cgmath::Matrix4<f32>,
  pub normal: cgmath::Vector3<f32>,
  pub tex_ids: [u32; 3],
}

#[derive(Debug, Clone)]
/// A small continguous chunk of terrain.
pub struct T2 {
  // These Vecs must all be ordered the same way; each entry is the next triangle.

  /// Position of each vertex.
  pub vertex_coordinates: Vec<Triangle<Point3<f32>>>,
  /// Vertex normals. These should be normalized!
  pub normals: Vec<Triangle<Vector3<f32>>>,
  /// Entity IDs for each triangle.
  pub ids: Vec<entity_id::T>,
  /// Material IDs for each triangle.
  pub materials: Vec<i32>,
  // TODO: Change this back to a HashMap once initial capacity is zero for those.
  /// Per-triangle bounding boxes.
  pub bounds: Vec<(entity_id::T, Aabb3<f32>)>,

  pub grass: Vec<Grass>,
  pub grass_ids: Vec<entity_id::T>,
}

pub type T = Arc<T2>;

/// Construct an empty `T`.
pub fn empty() -> T {
  Arc::new(T2 {
    vertex_coordinates: Vec::new(),
    normals: Vec::new(),

    ids: Vec::new(),
    materials: Vec::new(),
    bounds: Vec::new(),

    grass: Vec::new(),
    grass_ids: Vec::new(),
  })
}
<|endoftext|>


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

// compile-flags: -Z borrowck=mir -Z nll

#![allow(dead_code)]

// Test that we relate the type of the fn type to the type of the fn
// ptr when doing a `ReifyFnPointer` cast.
//
// This test is a bit tortured, let me explain:
//

// The `where 'a: 'a` clause here ensures that `'a` is early bound,
// which is needed below to ensure that this test hits the path we are
// concerned with.
fn foo<'a>(x: &'a u32) -> &'a u32
where
    'a: 'a,
{
    panic!()
}

fn bar<'a>(x: &'a u32) -> &'static u32 {
    // Here, the type of `foo` is `typeof(foo::<'x>)` for some fresh variable `'x`.
    // During NLL region analysis, this will get renumbered to `typeof(foo::<'?0>)`
    // where `'?0` is a new region variable.
    //
    // (Note that if `'a` on `foo` were early-bound, the type would be
    // `typeof(foo)`, which would interact differently with because
    // the renumbering later.)
    //
    // This type is then coerced to a fn type `fn(&'?1 u32) -> &'?2
    // u32`. Here, the `'?1` and `'?2` will have been created during
    // the NLL region renumbering.
    //
    // The MIR type checker must therefore relate `'?0` to `'?1` and `'?2`
    // as part of checking the `ReifyFnPointer`.
    let f: fn(_) -> _ = foo;
    //~^ WARNING not reporting region error due to -Znll
    f(x)
    //~^ ERROR free region `'_#1r` does not outlive free region `'static`
}

fn main() {}
<commit_msg>correct comment in test<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// compile-flags: -Z borrowck=mir -Z nll

#![allow(dead_code)]

// Test that we relate the type of the fn type to the type of the fn
// ptr when doing a `ReifyFnPointer` cast.
//
// This test is a bit tortured, let me explain:
//

// The `where 'a: 'a` clause here ensures that `'a` is early bound,
// which is needed below to ensure that this test hits the path we are
// concerned with.
fn foo<'a>(x: &'a u32) -> &'a u32
where
    'a: 'a,
{
    panic!()
}

fn bar<'a>(x: &'a u32) -> &'static u32 {
    // Here, the type of `foo` is `typeof(foo::<'x>)` for some fresh variable `'x`.
    // During NLL region analysis, this will get renumbered to `typeof(foo::<'?0>)`
    // where `'?0` is a new region variable.
    //
    // (Note that if `'a` on `foo` were late-bound, the type would be
    // `typeof(foo)`, which would interact differently with because
    // the renumbering later.)
    //
    // This type is then coerced to a fn type `fn(&'?1 u32) -> &'?2
    // u32`. Here, the `'?1` and `'?2` will have been created during
    // the NLL region renumbering.
    //
    // The MIR type checker must therefore relate `'?0` to `'?1` and `'?2`
    // as part of checking the `ReifyFnPointer`.
    let f: fn(_) -> _ = foo;
    //~^ WARNING not reporting region error due to -Znll
    f(x)
    //~^ ERROR free region `'_#1r` does not outlive free region `'static`
}

fn main() {}
<|endoftext|>


<commit_before>//! Windows provides three different ways to get the paths to roaming and local
//! app data: environment variables, KNOWNFOLDERID, and CSIDL. From the CSIDL
//! documentation:
//!
//! *"These values supersede the use of environment variables for this purpose.
//! They are in turn superseded in Windows Vista and later by the KNOWNFOLDERID
//! values."*
//! - https://msdn.microsoft.com/en-us/library/windows/desktop/bb762494.aspx
//!
//! -_-

// The function get_folder_path was adapted from:
// https://github.com/AndyBarron/preferences-rs/blob/f03c7/src/lib.rs#L211-L296
//
// Credit for the above code goes to Connorcpu (https://github.com/Connorcpu).

extern crate ole32;
extern crate shell32;
extern crate winapi;
use AppDataType::*;
use common::*;
use self::shell32::SHGetKnownFolderPath;
use self::winapi::{GUID, PWSTR};
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use std::path::PathBuf;
use std::ptr;
use std::slice;

pub const USE_AUTHOR: bool = true;

pub fn get_app_dir(t: AppDataType) -> Result<PathBuf, AppDirsError> {
    let folder_id = match t {
        UserConfig | UserData => &FOLDERID_RoamingAppData,
        SharedConfig | SharedData => &FOLDERID_ProgramData,
        UserCache => &FOLDERID_LocalAppData,
    };
    get_folder_path(folder_id).map(|os_str| os_str.into())
}

/// https://msdn.microsoft.com/en-us/library/dd378457.aspx#FOLDERID_RoamingAppData
#[allow(non_upper_case_globals)]
static FOLDERID_RoamingAppData: GUID = GUID {
    Data1: 0x3EB685DB,
    Data2: 0x65F9,
    Data3: 0x4CF6,
    Data4: [0xA0, 0x3A, 0xE3, 0xEF, 0x65, 0x72, 0x9F, 0x3D],
};

/// https://msdn.microsoft.com/en-us/library/dd378457.aspx#FOLDERID_LocalAppData
#[allow(non_upper_case_globals)]
static FOLDERID_LocalAppData: GUID = GUID {
    Data1: 0xF1B32785,
    Data2: 0x6FBA,
    Data3: 0x4FCF,
    Data4: [0x9D, 0x55, 0x7B, 0x8E, 0x7F, 0x15, 0x70, 0x91],
};

/// https://msdn.microsoft.com/en-us/library/dd378457.aspx#FOLDERID_ProgramData
#[allow(non_upper_case_globals)]
static FOLDERID_ProgramData: GUID = GUID {
    Data1: 0x62AB5D82,
    Data2: 0xFDC1,
    Data3: 0x4DC3,
    Data4: [0xA9, 0xDD, 0x07, 0x0D, 0x1D, 0x49, 0x5D, 0x97],
};

/// Wrapper around `winapi::PWSTR` to automatically free the string pointer.
/// This ensures the memory is freed when `get_folder_path` scope is left,
/// regardless of whether the call succeeded or failed/panicked.
struct SafePwstr(PWSTR);
impl Drop for SafePwstr {
    fn drop(&mut self) {
        unsafe { ole32::CoTaskMemFree(self.0 as *mut _) }
    }
}

fn get_folder_path(folder_id: &GUID) -> Result<OsString, AppDirsError> {
    unsafe {
        // Wide C string to be allocated by SHGetKnownFolderPath.
        // We are responsible for freeing this!
        let mut raw_path: PWSTR = ptr::null_mut();

        // SHGetKnownFolderPath arguments:
        // 1. reference to KNOWNFOLDERID
        // 2. no flags
        // 3. null handle -> current user
        // 4. output location
        let result = SHGetKnownFolderPath(folder_id, 0, ptr::null_mut(), &mut raw_path);

        // SHGetKnownFolderPath shouldn't ever fail, but if it does,
        // it will return a negative HRESULT.
        if result < 0 {
            return Err(AppDirsError::NotSupported);
        }

        // Ensures that the PWSTR is free when we leave this scope through
        // normal execution or a thread panic.
        let _cleanup = SafePwstr(raw_path);

        // Manually calculate length of wide C string.
        let mut length = 0;
        for i in 0.. {
            if *raw_path.offset(i) == 0 {
                length = i as usize;
                break;
            }
        }

        let wpath: &[u16] = slice::from_raw_parts(raw_path, length);
        let path: OsString = OsStringExt::from_wide(wpath);
        Ok(path)
        // _cleanup is deallocated, so raw_path is freed
    }
}
<commit_msg>Changes paths to match Windows standards.<commit_after>//! Windows provides three different ways to get the paths to roaming and local
//! app data: environment variables, KNOWNFOLDERID, and CSIDL. From the CSIDL
//! documentation:
//!
//! *"These values supersede the use of environment variables for this purpose.
//! They are in turn superseded in Windows Vista and later by the KNOWNFOLDERID
//! values."*
//! - https://msdn.microsoft.com/en-us/library/windows/desktop/bb762494.aspx
//!
//! -_-

// The function get_folder_path was adapted from:
// https://github.com/AndyBarron/preferences-rs/blob/f03c7/src/lib.rs#L211-L296
//
// Credit for the above code goes to Connorcpu (https://github.com/Connorcpu).

extern crate ole32;
extern crate shell32;
extern crate winapi;
use AppDataType::*;
use common::*;
use self::shell32::SHGetKnownFolderPath;
use self::winapi::{GUID, PWSTR};
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use std::path::PathBuf;
use std::ptr;
use std::slice;

pub const USE_AUTHOR: bool = true;

pub fn get_app_dir(t: AppDataType) -> Result<PathBuf, AppDirsError> {
    let folder_id = match t {
        UserConfig => &FOLDERID_RoamingAppData,
        SharedConfig | SharedData => &FOLDERID_ProgramData,
        UserCache | UserData => &FOLDERID_LocalAppData,
    };
    get_folder_path(folder_id).map(|os_str| os_str.into())
}

/// https://msdn.microsoft.com/en-us/library/dd378457.aspx#FOLDERID_RoamingAppData
#[allow(non_upper_case_globals)]
static FOLDERID_RoamingAppData: GUID = GUID {
    Data1: 0x3EB685DB,
    Data2: 0x65F9,
    Data3: 0x4CF6,
    Data4: [0xA0, 0x3A, 0xE3, 0xEF, 0x65, 0x72, 0x9F, 0x3D],
};

/// https://msdn.microsoft.com/en-us/library/dd378457.aspx#FOLDERID_LocalAppData
#[allow(non_upper_case_globals)]
static FOLDERID_LocalAppData: GUID = GUID {
    Data1: 0xF1B32785,
    Data2: 0x6FBA,
    Data3: 0x4FCF,
    Data4: [0x9D, 0x55, 0x7B, 0x8E, 0x7F, 0x15, 0x70, 0x91],
};

/// https://msdn.microsoft.com/en-us/library/dd378457.aspx#FOLDERID_ProgramData
#[allow(non_upper_case_globals)]
static FOLDERID_ProgramData: GUID = GUID {
    Data1: 0x62AB5D82,
    Data2: 0xFDC1,
    Data3: 0x4DC3,
    Data4: [0xA9, 0xDD, 0x07, 0x0D, 0x1D, 0x49, 0x5D, 0x97],
};

/// Wrapper around `winapi::PWSTR` to automatically free the string pointer.
/// This ensures the memory is freed when `get_folder_path` scope is left,
/// regardless of whether the call succeeded or failed/panicked.
struct SafePwstr(PWSTR);
impl Drop for SafePwstr {
    fn drop(&mut self) {
        unsafe { ole32::CoTaskMemFree(self.0 as *mut _) }
    }
}

fn get_folder_path(folder_id: &GUID) -> Result<OsString, AppDirsError> {
    unsafe {
        // Wide C string to be allocated by SHGetKnownFolderPath.
        // We are responsible for freeing this!
        let mut raw_path: PWSTR = ptr::null_mut();

        // SHGetKnownFolderPath arguments:
        // 1. reference to KNOWNFOLDERID
        // 2. no flags
        // 3. null handle -> current user
        // 4. output location
        let result = SHGetKnownFolderPath(folder_id, 0, ptr::null_mut(), &mut raw_path);

        // SHGetKnownFolderPath shouldn't ever fail, but if it does,
        // it will return a negative HRESULT.
        if result < 0 {
            return Err(AppDirsError::NotSupported);
        }

        // Ensures that the PWSTR is free when we leave this scope through
        // normal execution or a thread panic.
        let _cleanup = SafePwstr(raw_path);

        // Manually calculate length of wide C string.
        let mut length = 0;
        for i in 0.. {
            if *raw_path.offset(i) == 0 {
                length = i as usize;
                break;
            }
        }

        let wpath: &[u16] = slice::from_raw_parts(raw_path, length);
        let path: OsString = OsStringExt::from_wide(wpath);
        Ok(path)
        // _cleanup is deallocated, so raw_path is freed
    }
}
<|endoftext|>


<commit_before><commit_msg>the server accepts connections from everywhere<commit_after><|endoftext|>


<commit_before><commit_msg>Allow passing custom parameters to method handler<commit_after><|endoftext|>


<commit_before><commit_msg>lib: use HashMap::or_insert_with<commit_after><|endoftext|>


<commit_before><commit_msg>Switched numbers to chars so that its clearer which part of the tuple result is the count.<commit_after><|endoftext|>


<commit_before><commit_msg>Put the hack for sending msgs to NickServ back<commit_after><|endoftext|>


<commit_before><commit_msg>Feature: Iterate through all worksheets<commit_after><|endoftext|>


<commit_before><commit_msg>Add `read_n` that reads up to `cnt` midi messages at once<commit_after><|endoftext|>


<commit_before><commit_msg>WIP: Stack guarded page<commit_after><|endoftext|>


<commit_before><commit_msg>Replace all try!() with ?<commit_after><|endoftext|>


<commit_before><commit_msg>Replace most try!s with the ? operator<commit_after><|endoftext|>


<commit_before><commit_msg>Remove unused feature<commit_after><|endoftext|>


<commit_before><commit_msg>Improvements.<commit_after><|endoftext|>


<commit_before><commit_msg>WaitError implements Error trait<commit_after><|endoftext|>


<commit_before><commit_msg>Public modules in top-level.<commit_after><|endoftext|>


<commit_before><commit_msg>Moving code into lib.rs<commit_after><|endoftext|>


<commit_before><commit_msg>comments in pin.rs<commit_after><|endoftext|>


<commit_before>use super::super::commands::CommandResult;
use super::super::{LayoutTree, TreeError};
use super::super::core::Direction;
use super::super::core::container::{Container, ContainerType, Layout};

use petgraph::graph::NodeIndex;
use rustwlc::WlcView;
use uuid::Uuid;

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum FocusError {
    /// Reached a container where we can keep climbing the tree no longer.
    ///
    /// Usually this is a workspace, because it doesn't make sense to move a
    /// container out of a workspace
    ReachedLimit(NodeIndex),
    /// Tried to focus on a container that was not a view.
    NotAView(Uuid),
    /// Tried to focus on a container (first one),
    /// but that container was superseded by a fullscreen container (second one)
    BlockedByFullscreen(Uuid, Uuid)
}

impl LayoutTree {
    /// Focuses on the container by the uuid, if it points to a View.
    /// Otherwise, an error is returned.
    pub fn focus_on(&mut self, uuid: Uuid) -> CommandResult {
        if let Some(fullscreen_id) = try!(self.in_fullscreen_workspace(uuid)) {
            if fullscreen_id != uuid {
                return Err(TreeError::Focus(FocusError::BlockedByFullscreen(uuid, fullscreen_id)))
            }
        }
        let node_ix = self.tree.lookup_id(uuid)
            .ok_or(TreeError::NodeNotFound(uuid))?;
        match self.tree[node_ix] {
            Container::View { handle, .. } => {
                handle.focus();
                self.active_container = Some(node_ix);
            },
            _ => return Err(TreeError::Focus(FocusError::NotAView(uuid)))
        }
        if !self.tree[node_ix].floating() {
            self.tree.set_ancestor_paths_active(node_ix);
        }
        Ok(())
    }
    /// Focus on the container relative to the active container.
    ///
    /// If Horizontal, left and right will move within siblings.
    /// If Vertical, up and down will move within siblings.
    /// Other wise, it moves to the next sibling of the parent container.
    ///
    /// If the edge of the children is hit, it does not wrap around,
    /// but moves between ancestor siblings.
    pub fn move_focus(&mut self, direction: Direction) -> CommandResult {
        if let Some(prev_active_ix) = self.active_container {
            let active_id = self.tree[prev_active_ix].get_id();
            if let Some(fullscreen_id) = try!(self.in_fullscreen_workspace(active_id)) {
                return Err(TreeError::Focus(
                    FocusError::BlockedByFullscreen(active_id, fullscreen_id)))
            }
            let new_active_ix = self.move_focus_recurse(prev_active_ix, direction)
                .unwrap_or(prev_active_ix);
            try!(self.set_active_node(new_active_ix));
            match self.tree[self.active_container.unwrap()] {
                Container::View { ref handle, .. } => handle.focus(),
                _ => warn!("move_focus returned a non-view, cannot focus")
            }
        } else {
            return Err(TreeError::NoActiveContainer)
        }
        self.validate();
        Ok(())
    }

    fn move_focus_recurse(&mut self, node_ix: NodeIndex, direction: Direction)
                          -> Result<NodeIndex, TreeError> {
        match self.tree[node_ix].get_type() {
            ContainerType::View | ContainerType::Container => { /* continue */ },
            _ => return Err(TreeError::UuidWrongType(self.tree[node_ix].get_id(),
                                                     vec!(ContainerType::View, ContainerType::Container)))
        }
        let parent_ix = self.tree.parent_of(node_ix)
            .expect("Active ix had no parent");
        match self.tree[parent_ix] {
            Container::Container { layout, .. } => {
                match (layout, direction) {
                    (Layout::Horizontal, Direction::Left) |
                    (Layout::Horizontal, Direction::Right) |
                    (Layout::Vertical, Direction::Up) |
                    (Layout::Vertical, Direction::Down) => {
                        let siblings = self.tree.children_of(parent_ix);
                        let cur_index = siblings.iter().position(|node| {
                            *node == node_ix
                        }).expect("Could not find self in parent");
                        let maybe_new_index = match direction {
                            Direction::Right | Direction::Down => {
                                cur_index.checked_add(1)
                            }
                            Direction::Left  | Direction::Up => {
                                cur_index.checked_sub(1)
                            }
                        };
                        if maybe_new_index.is_some() &&
                            maybe_new_index.unwrap() < siblings.len() {
                                // There is a sibling to move to.
                                let new_index = maybe_new_index.unwrap();
                                let new_active_ix = siblings[new_index];
                                match self.tree[new_active_ix].get_type() {
                                    ContainerType::Container => {
                                        let path_ix = self.tree.follow_path(new_active_ix);
                                        // If the path wasn't complete, find the first view and focus on that
                                        let node_ix = try!(self.tree.descendant_of_type(path_ix, ContainerType::View)
                                                           .map_err(|err| TreeError::PetGraph(err)));
                                        let parent_ix = try!(self.tree.parent_of(node_ix)
                                                             .map_err(|err| TreeError::PetGraph(err)));
                                        match self.tree[node_ix].get_type() {
                                            ContainerType::View | ContainerType::Container => {},
                                            _ => panic!("Following path did not lead to a container or a view!")
                                        }
                                        trace!("Moving to different view {:?} in container {:?}",
                                                self.tree[node_ix], self.tree[parent_ix]);
                                        return Ok(node_ix);
                                    },
                                    ContainerType::View => {
                                        trace!("Moving to other view {:?}", self.tree[new_active_ix]);
                                        return Ok(new_active_ix)
                                    },
                                    _ => unreachable!()
                                };
                            }
                    },
                    _ => { /* We are moving out of siblings, recurse */ }
                }
            }
            Container::Workspace { .. } => {
                return Err(TreeError::Focus(FocusError::ReachedLimit(parent_ix)));
            }
            _ => unreachable!()
        }
        let parent_ix = self.tree.parent_of(node_ix)
            .expect("Node had no parent");
        return self.move_focus_recurse(parent_ix, direction);
    }

    /// Updates the current active container to be the next container or view
    /// to focus on after the previous view/container was moved/removed.
    ///
    /// A new view will tried to be set, starting with the children of the
    /// parent node. If a view cannot be found there, it starts climbing the
    /// tree until either a view is found or the workspace is (in which case
    /// it set the active container to the root container of the workspace)
    ///
    /// If there are siblings, the chosen node is the one with the lowest
    /// active count.
    ///
    /// If there is a fullscreen container in this workspace, that is focused on next,
    /// with the active path updated accordingly.
    pub fn focus_on_next_container(&mut self, mut parent_ix: NodeIndex) {
        let last_ix = self.tree.active_path().last()
            .expect("Active path did not lead anywhere").0;
        let id = self.tree[last_ix].get_id();
        match self.in_fullscreen_workspace(id) {
            Ok(Some(fullscreen_id)) => {
                self.set_active_container(fullscreen_id)
                    .unwrap_or_else(|err| {
                        error!("Could not set {:?} to be the active container, \
                                even though it's the fullscreen container! {:?}",
                               fullscreen_id, err);
                        error!("{:#?}", self);
                        panic!("Could not set the fullscreen container to be \
                                the active container!")
                    });
                return;
            },
            _ => {}
        }
        match self.tree[last_ix] {
            Container::View { handle, .. } => {
                handle.focus();
                self.active_container = Some(last_ix);
                return
            },
            Container::Container { .. } => {
                parent_ix = last_ix;
            },
            _ => {}
        }
        while self.tree.node_type(parent_ix)
            .expect("Node not part of the tree") != ContainerType::Workspace {
                if let Some(node_ix) = self.tree.lowest_active_view(parent_ix) {
                    match self.tree[node_ix] {
                        Container::View { .. } => {
                            trace!("Active container set to view at {:?}", node_ix);
                            let id = self.tree[node_ix].get_id();
                            self.set_active_container(id)
                                .expect("Could not set active container");
                            return;
                        },
                        _ => {}
                    }
                }
                parent_ix = self.tree.ancestor_of_type(parent_ix,
                                                       ContainerType::Container)
                    .unwrap_or_else(|_| {
                        self.tree.ancestor_of_type(parent_ix, ContainerType::Workspace)
                            .expect("Container was not part of a workspace")
                    });
        }
        // If this is reached, parent is workspace
        let container_ix = self.tree.children_of(parent_ix).get(0).cloned();
        if container_ix.is_none() {
            trace!("There were no other containers to focus on, \
                    focusing on nothing in particular!");
            return;
        }
        let container_ix = container_ix.unwrap();
        let root_c_children = self.tree.grounded_children(container_ix);
        if root_c_children.len() > 0 {
            // Only searches first child of root container, can't be floating view.
            let new_active_ix = self.tree.descendant_of_type(root_c_children[0],
                                                                ContainerType::View)
                .unwrap_or(root_c_children[0]);
            let id = self.tree[new_active_ix].get_id();
            self.set_active_container(id)
                .expect("Could not set active container");
            match self.tree[new_active_ix] {
                Container::View { ref handle, .. } => {
                    debug!("Focusing on {:?}", handle);
                    handle.focus();
                },
                Container::Container { .. } => {
                    debug!("No view found, focusing on nothing in workspace {:?}", parent_ix);
                    WlcView::root().focus();
                }
                _ => unreachable!()
            };
            return;
        } else {
            let floating_children = self.tree.floating_children(container_ix);
            for child_ix in floating_children {
                if let Ok(view_ix) = self.tree.descendant_of_type(child_ix,
                                                                    ContainerType::View) {
                    match self.tree[view_ix] {
                        Container::View { handle, id, .. } => {
                            debug!("Floating view found, focusing on {:#?}", handle);
                            handle.focus();
                            self.set_active_container(id)
                                .expect("Could not set active container");
                            return;
                        },
                        _ => unreachable!()
                    };
                }
            }
        }
        trace!("Active container set to container {:?}", container_ix);
        let id = self.tree[container_ix].get_id();
        self.set_active_container(id)
            .expect("Could not set active container");

        // Update focus to new container
        self.get_active_container().map(|con| match *con {
            Container::View { ref handle, .. } => handle.focus(),
            Container::Container { .. } => WlcView::root().focus(),
            _ => panic!("Active container not view or container!")
        });
    }

    /// If the currently focused view is floating, then the non-floating at the end of
    /// the path becomes the focused view. Otherwise, the first floating view becomes
    /// the focused view.
    ///
    /// If there is no currently focused view, does nothing.
    pub fn toggle_floating_focus(&mut self) -> CommandResult {
        let active_ix = try!(self.active_container.ok_or(TreeError::NoActiveContainer));
        let id; let floating;
        {
            let container = &self.tree[active_ix];
            id = container.get_id();
            floating = container.floating();
        }
        if let Some(fullscreen_id) = try!(self.in_fullscreen_workspace(id)) {
            return Err(TreeError::Focus(FocusError::BlockedByFullscreen(id, fullscreen_id)))
        }
        if floating {
            let root_ix = self.tree.root_ix();
            let new_ix = self.tree.follow_path(root_ix);
            match self.tree[new_ix].get_type() {
                ContainerType::View | ContainerType::Container  => {
                    try!(self.set_active_node(new_ix));
                    Ok(())
                },
                type_ => {
                    error!("Path lead to the wrong container, {:#?}\n{:#?}\n{:#?}",
                           active_ix, type_, self);
                    panic!("toggle_floating_focused: bad path");
                }
            }
        } else {
            // Current view is not floating, gotta focus on floating view
            let root_c_ix = self.root_container_ix()
                .expect("No root container ancestor of active container");
            let floating_children = self.tree.floating_children(root_c_ix);
            if floating_children.len() > 0 {
                try!(self.set_active_node(floating_children[0]));
            }
            Ok(())
        }
    }
}

#[cfg(test)]
mod tests {
    use super::super::super::core::tree::tests::basic_tree;
    use rustwlc::*;

    /// Tests the new algorithm, the one that i3 uses, to determine which
    /// sibling to focus on when the active one is closed.
    #[test]
    fn test_sibling_focus_algorithm() {
        let mut tree = basic_tree();
        let fake_view = WlcView::root();
        tree.switch_to_workspace("some_unique_workspace");
        let view_1 = tree.add_view(fake_view).unwrap().get_id();
        let view_2 = tree.add_view(fake_view).unwrap().get_id();
        let view_3 = tree.add_view(fake_view).unwrap().get_id();
        let view_4 = tree.add_view(fake_view).unwrap().get_id();
        let view_5 = tree.add_view(fake_view).unwrap().get_id();

        tree.focus_on(view_3).unwrap();
        tree.focus_on(view_1).unwrap();
        // should focus 1 -> 3 -> 5 -> 4 -> 2
        // because this the "stack" of viewing them.
        // NOTE that adding a view implicitly focuses and adds it to the "stack"
        let views = vec![view_1, view_3, view_5, view_4, view_2];
        for view in views {
            let active_ix = tree.tree.lookup_id(view);
            assert_eq!(tree.active_container, active_ix);
            tree.remove_active().unwrap();
        }
    }

    /// Tests that after sending a floating view to a new workspace,
    /// there are no duplicate active numbers (and we can focus on that
    /// workspace with no problem)
    ///
    /// The expected behaviour is that we focus on tiled windows first,
    /// and that anything we send over has a bumped up active count.
    #[test]
    fn test_focus_on_floating_after_sending_to_workspace() {
        let mut tree = basic_tree();
        let fake_view = WlcView::root();
        let target_workspace = "some_unique_workspace";
        let source_workspace = "a different workspace";
        tree.switch_to_workspace(target_workspace);
        let tiled_view = tree.add_view(fake_view).unwrap().get_id();

        tree.switch_to_workspace(source_workspace);
        let _floating_view_1 = tree.add_floating_view(fake_view, None).unwrap().get_id();
        let floating_view_2 = tree.add_floating_view(fake_view, None).unwrap().get_id();
        tree.focus_on(floating_view_2).unwrap();
        assert_eq!(tree.tree.lookup_id(floating_view_2), tree.active_container);

        // now send the view to the workspace with the tiled window.
        tree.send_active_to_workspace(target_workspace);
        tree.switch_to_workspace(target_workspace);
        assert_eq!(tree.tree.lookup_id(tiled_view), tree.active_container);

        // and again with the other one
        tree.switch_to_workspace(source_workspace);
        tree.send_active_to_workspace(target_workspace);
        tree.switch_to_workspace(target_workspace);
        assert_eq!(tree.tree.lookup_id(tiled_view), tree.active_container);

    }
}
<commit_msg>Updated test to reflect new focus semantics<commit_after>use super::super::commands::CommandResult;
use super::super::{LayoutTree, TreeError};
use super::super::core::Direction;
use super::super::core::container::{Container, ContainerType, Layout};

use petgraph::graph::NodeIndex;
use rustwlc::WlcView;
use uuid::Uuid;

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum FocusError {
    /// Reached a container where we can keep climbing the tree no longer.
    ///
    /// Usually this is a workspace, because it doesn't make sense to move a
    /// container out of a workspace
    ReachedLimit(NodeIndex),
    /// Tried to focus on a container that was not a view.
    NotAView(Uuid),
    /// Tried to focus on a container (first one),
    /// but that container was superseded by a fullscreen container (second one)
    BlockedByFullscreen(Uuid, Uuid)
}

impl LayoutTree {
    /// Focuses on the container by the uuid, if it points to a View.
    /// Otherwise, an error is returned.
    pub fn focus_on(&mut self, uuid: Uuid) -> CommandResult {
        if let Some(fullscreen_id) = try!(self.in_fullscreen_workspace(uuid)) {
            if fullscreen_id != uuid {
                return Err(TreeError::Focus(FocusError::BlockedByFullscreen(uuid, fullscreen_id)))
            }
        }
        let node_ix = self.tree.lookup_id(uuid)
            .ok_or(TreeError::NodeNotFound(uuid))?;
        match self.tree[node_ix] {
            Container::View { handle, .. } => {
                handle.focus();
                self.active_container = Some(node_ix);
            },
            _ => return Err(TreeError::Focus(FocusError::NotAView(uuid)))
        }
        if !self.tree[node_ix].floating() {
            self.tree.set_ancestor_paths_active(node_ix);
        }
        Ok(())
    }
    /// Focus on the container relative to the active container.
    ///
    /// If Horizontal, left and right will move within siblings.
    /// If Vertical, up and down will move within siblings.
    /// Other wise, it moves to the next sibling of the parent container.
    ///
    /// If the edge of the children is hit, it does not wrap around,
    /// but moves between ancestor siblings.
    pub fn move_focus(&mut self, direction: Direction) -> CommandResult {
        if let Some(prev_active_ix) = self.active_container {
            let active_id = self.tree[prev_active_ix].get_id();
            if let Some(fullscreen_id) = try!(self.in_fullscreen_workspace(active_id)) {
                return Err(TreeError::Focus(
                    FocusError::BlockedByFullscreen(active_id, fullscreen_id)))
            }
            let new_active_ix = self.move_focus_recurse(prev_active_ix, direction)
                .unwrap_or(prev_active_ix);
            try!(self.set_active_node(new_active_ix));
            match self.tree[self.active_container.unwrap()] {
                Container::View { ref handle, .. } => handle.focus(),
                _ => warn!("move_focus returned a non-view, cannot focus")
            }
        } else {
            return Err(TreeError::NoActiveContainer)
        }
        self.validate();
        Ok(())
    }

    fn move_focus_recurse(&mut self, node_ix: NodeIndex, direction: Direction)
                          -> Result<NodeIndex, TreeError> {
        match self.tree[node_ix].get_type() {
            ContainerType::View | ContainerType::Container => { /* continue */ },
            _ => return Err(TreeError::UuidWrongType(self.tree[node_ix].get_id(),
                                                     vec!(ContainerType::View, ContainerType::Container)))
        }
        let parent_ix = self.tree.parent_of(node_ix)
            .expect("Active ix had no parent");
        match self.tree[parent_ix] {
            Container::Container { layout, .. } => {
                match (layout, direction) {
                    (Layout::Horizontal, Direction::Left) |
                    (Layout::Horizontal, Direction::Right) |
                    (Layout::Vertical, Direction::Up) |
                    (Layout::Vertical, Direction::Down) => {
                        let siblings = self.tree.children_of(parent_ix);
                        let cur_index = siblings.iter().position(|node| {
                            *node == node_ix
                        }).expect("Could not find self in parent");
                        let maybe_new_index = match direction {
                            Direction::Right | Direction::Down => {
                                cur_index.checked_add(1)
                            }
                            Direction::Left  | Direction::Up => {
                                cur_index.checked_sub(1)
                            }
                        };
                        if maybe_new_index.is_some() &&
                            maybe_new_index.unwrap() < siblings.len() {
                                // There is a sibling to move to.
                                let new_index = maybe_new_index.unwrap();
                                let new_active_ix = siblings[new_index];
                                match self.tree[new_active_ix].get_type() {
                                    ContainerType::Container => {
                                        let path_ix = self.tree.follow_path(new_active_ix);
                                        // If the path wasn't complete, find the first view and focus on that
                                        let node_ix = try!(self.tree.descendant_of_type(path_ix, ContainerType::View)
                                                           .map_err(|err| TreeError::PetGraph(err)));
                                        let parent_ix = try!(self.tree.parent_of(node_ix)
                                                             .map_err(|err| TreeError::PetGraph(err)));
                                        match self.tree[node_ix].get_type() {
                                            ContainerType::View | ContainerType::Container => {},
                                            _ => panic!("Following path did not lead to a container or a view!")
                                        }
                                        trace!("Moving to different view {:?} in container {:?}",
                                                self.tree[node_ix], self.tree[parent_ix]);
                                        return Ok(node_ix);
                                    },
                                    ContainerType::View => {
                                        trace!("Moving to other view {:?}", self.tree[new_active_ix]);
                                        return Ok(new_active_ix)
                                    },
                                    _ => unreachable!()
                                };
                            }
                    },
                    _ => { /* We are moving out of siblings, recurse */ }
                }
            }
            Container::Workspace { .. } => {
                return Err(TreeError::Focus(FocusError::ReachedLimit(parent_ix)));
            }
            _ => unreachable!()
        }
        let parent_ix = self.tree.parent_of(node_ix)
            .expect("Node had no parent");
        return self.move_focus_recurse(parent_ix, direction);
    }

    /// Updates the current active container to be the next container or view
    /// to focus on after the previous view/container was moved/removed.
    ///
    /// A new view will tried to be set, starting with the children of the
    /// parent node. If a view cannot be found there, it starts climbing the
    /// tree until either a view is found or the workspace is (in which case
    /// it set the active container to the root container of the workspace)
    ///
    /// If there are siblings, the chosen node is the one with the lowest
    /// active count.
    ///
    /// If there is a fullscreen container in this workspace, that is focused on next,
    /// with the active path updated accordingly.
    pub fn focus_on_next_container(&mut self, mut parent_ix: NodeIndex) {
        let last_ix = self.tree.active_path().last()
            .expect("Active path did not lead anywhere").0;
        let id = self.tree[last_ix].get_id();
        match self.in_fullscreen_workspace(id) {
            Ok(Some(fullscreen_id)) => {
                self.set_active_container(fullscreen_id)
                    .unwrap_or_else(|err| {
                        error!("Could not set {:?} to be the active container, \
                                even though it's the fullscreen container! {:?}",
                               fullscreen_id, err);
                        error!("{:#?}", self);
                        panic!("Could not set the fullscreen container to be \
                                the active container!")
                    });
                return;
            },
            _ => {}
        }
        match self.tree[last_ix] {
            Container::View { handle, .. } => {
                handle.focus();
                self.active_container = Some(last_ix);
                return
            },
            Container::Container { .. } => {
                parent_ix = last_ix;
            },
            _ => {}
        }
        while self.tree.node_type(parent_ix)
            .expect("Node not part of the tree") != ContainerType::Workspace {
                if let Some(node_ix) = self.tree.lowest_active_view(parent_ix) {
                    match self.tree[node_ix] {
                        Container::View { .. } => {
                            trace!("Active container set to view at {:?}", node_ix);
                            let id = self.tree[node_ix].get_id();
                            self.set_active_container(id)
                                .expect("Could not set active container");
                            return;
                        },
                        _ => {}
                    }
                }
                parent_ix = self.tree.ancestor_of_type(parent_ix,
                                                       ContainerType::Container)
                    .unwrap_or_else(|_| {
                        self.tree.ancestor_of_type(parent_ix, ContainerType::Workspace)
                            .expect("Container was not part of a workspace")
                    });
        }
        // If this is reached, parent is workspace
        let container_ix = self.tree.children_of(parent_ix).get(0).cloned();
        if container_ix.is_none() {
            trace!("There were no other containers to focus on, \
                    focusing on nothing in particular!");
            return;
        }
        let container_ix = container_ix.unwrap();
        let root_c_children = self.tree.grounded_children(container_ix);
        if root_c_children.len() > 0 {
            // Only searches first child of root container, can't be floating view.
            let new_active_ix = self.tree.descendant_of_type(root_c_children[0],
                                                                ContainerType::View)
                .unwrap_or(root_c_children[0]);
            let id = self.tree[new_active_ix].get_id();
            self.set_active_container(id)
                .expect("Could not set active container");
            match self.tree[new_active_ix] {
                Container::View { ref handle, .. } => {
                    debug!("Focusing on {:?}", handle);
                    handle.focus();
                },
                Container::Container { .. } => {
                    debug!("No view found, focusing on nothing in workspace {:?}", parent_ix);
                    WlcView::root().focus();
                }
                _ => unreachable!()
            };
            return;
        } else {
            let floating_children = self.tree.floating_children(container_ix);
            for child_ix in floating_children {
                if let Ok(view_ix) = self.tree.descendant_of_type(child_ix,
                                                                    ContainerType::View) {
                    match self.tree[view_ix] {
                        Container::View { handle, id, .. } => {
                            debug!("Floating view found, focusing on {:#?}", handle);
                            handle.focus();
                            self.set_active_container(id)
                                .expect("Could not set active container");
                            return;
                        },
                        _ => unreachable!()
                    };
                }
            }
        }
        trace!("Active container set to container {:?}", container_ix);
        let id = self.tree[container_ix].get_id();
        self.set_active_container(id)
            .expect("Could not set active container");

        // Update focus to new container
        self.get_active_container().map(|con| match *con {
            Container::View { ref handle, .. } => handle.focus(),
            Container::Container { .. } => WlcView::root().focus(),
            _ => panic!("Active container not view or container!")
        });
    }

    /// If the currently focused view is floating, then the non-floating at the end of
    /// the path becomes the focused view. Otherwise, the first floating view becomes
    /// the focused view.
    ///
    /// If there is no currently focused view, does nothing.
    pub fn toggle_floating_focus(&mut self) -> CommandResult {
        let active_ix = try!(self.active_container.ok_or(TreeError::NoActiveContainer));
        let id; let floating;
        {
            let container = &self.tree[active_ix];
            id = container.get_id();
            floating = container.floating();
        }
        if let Some(fullscreen_id) = try!(self.in_fullscreen_workspace(id)) {
            return Err(TreeError::Focus(FocusError::BlockedByFullscreen(id, fullscreen_id)))
        }
        if floating {
            let root_ix = self.tree.root_ix();
            let new_ix = self.tree.follow_path(root_ix);
            match self.tree[new_ix].get_type() {
                ContainerType::View | ContainerType::Container  => {
                    try!(self.set_active_node(new_ix));
                    Ok(())
                },
                type_ => {
                    error!("Path lead to the wrong container, {:#?}\n{:#?}\n{:#?}",
                           active_ix, type_, self);
                    panic!("toggle_floating_focused: bad path");
                }
            }
        } else {
            // Current view is not floating, gotta focus on floating view
            let root_c_ix = self.root_container_ix()
                .expect("No root container ancestor of active container");
            let floating_children = self.tree.floating_children(root_c_ix);
            if floating_children.len() > 0 {
                try!(self.set_active_node(floating_children[0]));
            }
            Ok(())
        }
    }
}

#[cfg(test)]
mod tests {
    use super::super::super::core::tree::tests::basic_tree;
    use rustwlc::*;

    /// Tests the new algorithm, the one that i3 uses, to determine which
    /// sibling to focus on when the active one is closed.
    #[test]
    fn test_sibling_focus_algorithm() {
        let mut tree = basic_tree();
        let fake_view = WlcView::root();
        tree.switch_to_workspace("some_unique_workspace");
        let view_1 = tree.add_view(fake_view).unwrap().get_id();
        let view_2 = tree.add_view(fake_view).unwrap().get_id();
        let view_3 = tree.add_view(fake_view).unwrap().get_id();
        let view_4 = tree.add_view(fake_view).unwrap().get_id();
        let view_5 = tree.add_view(fake_view).unwrap().get_id();

        tree.focus_on(view_3).unwrap();
        tree.focus_on(view_1).unwrap();
        // should focus 1 -> 3 -> 5 -> 4 -> 2
        // because this the "stack" of viewing them.
        // NOTE that adding a view implicitly focuses and adds it to the "stack"
        let views = vec![view_1, view_3, view_5, view_4, view_2];
        for view in views {
            let active_ix = tree.tree.lookup_id(view);
            assert_eq!(tree.active_container, active_ix);
            tree.remove_active().unwrap();
        }
    }

    /// Tests that after sending a floating view to a new workspace,
    /// there are no duplicate active numbers (and we can focus on that
    /// workspace with no problem)
    ///
    /// The expected behaviour is that we focus on the floating windows that
    /// were sent over (e.g, the latest focused view from the user's perspective
    /// is reflected even when sent to a different workspace).
    #[test]
    fn test_focus_on_floating_after_sending_to_workspace() {
        let mut tree = basic_tree();
        let fake_view = WlcView::root();
        let target_workspace = "some_unique_workspace";
        let source_workspace = "a different workspace";
        tree.switch_to_workspace(target_workspace);
        let _unused_tiled_view = tree.add_view(fake_view).unwrap().get_id();

        tree.switch_to_workspace(source_workspace);
        let floating_view_1 = tree.add_floating_view(fake_view, None).unwrap().get_id();
        let floating_view_2 = tree.add_floating_view(fake_view, None).unwrap().get_id();
        tree.focus_on(floating_view_2).unwrap();
        assert_eq!(tree.tree.lookup_id(floating_view_2), tree.active_container);

        // now send the view to the workspace with the tiled window.
        tree.send_active_to_workspace(target_workspace);
        tree.switch_to_workspace(target_workspace);
        assert_eq!(tree.tree.lookup_id(floating_view_2), tree.active_container);

        // and again with the other one
        tree.switch_to_workspace(source_workspace);
        tree.send_active_to_workspace(target_workspace);
        tree.switch_to_workspace(target_workspace);
        assert_eq!(tree.tree.lookup_id(floating_view_1), tree.active_container);

    }
}
<|endoftext|>


<commit_before>//! Handles dynamic library loading for proc macro

use std::{
    convert::TryInto,
    fmt,
    fs::File,
    io,
    path::{Path, PathBuf},
};

use libloading::Library;
use memmap2::Mmap;
use object::Object;
use paths::AbsPath;
use proc_macro_api::{read_dylib_info, ProcMacroKind};

use super::abis::Abi;

const NEW_REGISTRAR_SYMBOL: &str = "_rustc_proc_macro_decls_";

fn invalid_data_err(e: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> io::Error {
    io::Error::new(io::ErrorKind::InvalidData, e)
}

fn is_derive_registrar_symbol(symbol: &str) -> bool {
    symbol.contains(NEW_REGISTRAR_SYMBOL)
}

fn find_registrar_symbol(file: &Path) -> io::Result<Option<String>> {
    let file = File::open(file)?;
    let buffer = unsafe { Mmap::map(&file)? };

    Ok(object::File::parse(&*buffer)
        .map_err(invalid_data_err)?
        .exports()
        .map_err(invalid_data_err)?
        .into_iter()
        .map(|export| export.name())
        .filter_map(|sym| String::from_utf8(sym.into()).ok())
        .find(|sym| is_derive_registrar_symbol(sym))
        .map(|sym| {
            // From MacOS docs:
            // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/dlsym.3.html
            // Unlike other dyld API's, the symbol name passed to dlsym() must NOT be
            // prepended with an underscore.
            if cfg!(target_os = "macos") && sym.starts_with('_') {
                sym[1..].to_owned()
            } else {
                sym
            }
        }))
}

/// Loads dynamic library in platform dependent manner.
///
/// For unix, you have to use RTLD_DEEPBIND flag to escape problems described
/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample)
/// and [here](https://github.com/rust-lang/rust/issues/60593).
///
/// Usage of RTLD_DEEPBIND
/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample/issues/1)
///
/// It seems that on Windows that behaviour is default, so we do nothing in that case.
#[cfg(windows)]
fn load_library(file: &Path) -> Result<Library, libloading::Error> {
    unsafe { Library::new(file) }
}

#[cfg(unix)]
fn load_library(file: &Path) -> Result<Library, libloading::Error> {
    use libloading::os::unix::Library as UnixLibrary;
    use std::os::raw::c_int;

    const RTLD_NOW: c_int = 0x00002;
    const RTLD_DEEPBIND: c_int = 0x00008;

    unsafe { UnixLibrary::open(Some(file), RTLD_NOW | RTLD_DEEPBIND).map(|lib| lib.into()) }
}

#[derive(Debug)]
pub enum LoadProcMacroDylibError {
    Io(io::Error),
    LibLoading(libloading::Error),
    UnsupportedABI,
}

impl fmt::Display for LoadProcMacroDylibError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Io(e) => e.fmt(f),
            Self::UnsupportedABI => write!(f, "unsupported ABI version"),
            Self::LibLoading(e) => e.fmt(f),
        }
    }
}

impl From<io::Error> for LoadProcMacroDylibError {
    fn from(e: io::Error) -> Self {
        LoadProcMacroDylibError::Io(e)
    }
}

impl From<libloading::Error> for LoadProcMacroDylibError {
    fn from(e: libloading::Error) -> Self {
        LoadProcMacroDylibError::LibLoading(e)
    }
}

struct ProcMacroLibraryLibloading {
    // Hold on to the library so it doesn't unload
    _lib: Library,
    abi: Abi,
}

impl ProcMacroLibraryLibloading {
    fn open(file: &Path) -> Result<Self, LoadProcMacroDylibError> {
        let symbol_name = find_registrar_symbol(file)?.ok_or_else(|| {
            invalid_data_err(format!("Cannot find registrar symbol in file {}", file.display()))
        })?;

        let abs_file: &AbsPath = file.try_into().map_err(|_| {
            invalid_data_err(format!("expected an absolute path, got {}", file.display()))
        })?;
        let version_info = read_dylib_info(&abs_file)?;

        let lib = load_library(file).map_err(invalid_data_err)?;
        let abi = Abi::from_lib(&lib, symbol_name, version_info)?;
        Ok(ProcMacroLibraryLibloading { _lib: lib, abi })
    }
}

pub struct Expander {
    inner: ProcMacroLibraryLibloading,
}

impl Expander {
    pub fn new(lib: &Path) -> Result<Expander, LoadProcMacroDylibError> {
        // Some libraries for dynamic loading require canonicalized path even when it is
        // already absolute
        let lib = lib.canonicalize()?;

        let lib = ensure_file_with_lock_free_access(&lib)?;

        let library = ProcMacroLibraryLibloading::open(lib.as_ref())?;

        Ok(Expander { inner: library })
    }

    pub fn expand(
        &self,
        macro_name: &str,
        macro_body: &tt::Subtree,
        attributes: Option<&tt::Subtree>,
    ) -> Result<tt::Subtree, String> {
        let result = self.inner.abi.expand(macro_name, macro_body, attributes);
        result.map_err(|e| e.as_str().unwrap_or_else(|| "<unknown error>".to_string()))
    }

    pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> {
        self.inner.abi.list_macros()
    }
}

/// Copy the dylib to temp directory to prevent locking in Windows
#[cfg(windows)]
fn ensure_file_with_lock_free_access(path: &Path) -> io::Result<PathBuf> {
    use std::collections::hash_map::RandomState;
    use std::ffi::OsString;
    use std::hash::{BuildHasher, Hasher};

    let mut to = std::env::temp_dir();

    let file_name = path.file_name().ok_or_else(|| {
        io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("File path is invalid: {}", path.display()),
        )
    })?;

    // Generate a unique number by abusing `HashMap`'s hasher.
    // Maybe this will also "inspire" a libs team member to finally put `rand` in libstd.
    let t = RandomState::new().build_hasher().finish();

    let mut unique_name = OsString::from(t.to_string());
    unique_name.push(file_name);

    to.push(unique_name);
    std::fs::copy(path, &to).unwrap();
    Ok(to)
}

#[cfg(unix)]
fn ensure_file_with_lock_free_access(path: &Path) -> io::Result<PathBuf> {
    Ok(path.to_path_buf())
}
<commit_msg>Add a way to disable dll copying for users of proc_macro_srv library<commit_after>//! Handles dynamic library loading for proc macro

use std::{
    convert::TryInto,
    fmt,
    fs::File,
    io,
    path::{Path, PathBuf},
};

use libloading::Library;
use memmap2::Mmap;
use object::Object;
use paths::AbsPath;
use proc_macro_api::{read_dylib_info, ProcMacroKind};

use super::abis::Abi;

const NEW_REGISTRAR_SYMBOL: &str = "_rustc_proc_macro_decls_";

fn invalid_data_err(e: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> io::Error {
    io::Error::new(io::ErrorKind::InvalidData, e)
}

fn is_derive_registrar_symbol(symbol: &str) -> bool {
    symbol.contains(NEW_REGISTRAR_SYMBOL)
}

fn find_registrar_symbol(file: &Path) -> io::Result<Option<String>> {
    let file = File::open(file)?;
    let buffer = unsafe { Mmap::map(&file)? };

    Ok(object::File::parse(&*buffer)
        .map_err(invalid_data_err)?
        .exports()
        .map_err(invalid_data_err)?
        .into_iter()
        .map(|export| export.name())
        .filter_map(|sym| String::from_utf8(sym.into()).ok())
        .find(|sym| is_derive_registrar_symbol(sym))
        .map(|sym| {
            // From MacOS docs:
            // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/dlsym.3.html
            // Unlike other dyld API's, the symbol name passed to dlsym() must NOT be
            // prepended with an underscore.
            if cfg!(target_os = "macos") && sym.starts_with('_') {
                sym[1..].to_owned()
            } else {
                sym
            }
        }))
}

/// Loads dynamic library in platform dependent manner.
///
/// For unix, you have to use RTLD_DEEPBIND flag to escape problems described
/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample)
/// and [here](https://github.com/rust-lang/rust/issues/60593).
///
/// Usage of RTLD_DEEPBIND
/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample/issues/1)
///
/// It seems that on Windows that behaviour is default, so we do nothing in that case.
#[cfg(windows)]
fn load_library(file: &Path) -> Result<Library, libloading::Error> {
    unsafe { Library::new(file) }
}

#[cfg(unix)]
fn load_library(file: &Path) -> Result<Library, libloading::Error> {
    use libloading::os::unix::Library as UnixLibrary;
    use std::os::raw::c_int;

    const RTLD_NOW: c_int = 0x00002;
    const RTLD_DEEPBIND: c_int = 0x00008;

    unsafe { UnixLibrary::open(Some(file), RTLD_NOW | RTLD_DEEPBIND).map(|lib| lib.into()) }
}

#[derive(Debug)]
pub enum LoadProcMacroDylibError {
    Io(io::Error),
    LibLoading(libloading::Error),
    UnsupportedABI,
}

impl fmt::Display for LoadProcMacroDylibError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Io(e) => e.fmt(f),
            Self::UnsupportedABI => write!(f, "unsupported ABI version"),
            Self::LibLoading(e) => e.fmt(f),
        }
    }
}

impl From<io::Error> for LoadProcMacroDylibError {
    fn from(e: io::Error) -> Self {
        LoadProcMacroDylibError::Io(e)
    }
}

impl From<libloading::Error> for LoadProcMacroDylibError {
    fn from(e: libloading::Error) -> Self {
        LoadProcMacroDylibError::LibLoading(e)
    }
}

struct ProcMacroLibraryLibloading {
    // Hold on to the library so it doesn't unload
    _lib: Library,
    abi: Abi,
}

impl ProcMacroLibraryLibloading {
    fn open(file: &Path) -> Result<Self, LoadProcMacroDylibError> {
        let symbol_name = find_registrar_symbol(file)?.ok_or_else(|| {
            invalid_data_err(format!("Cannot find registrar symbol in file {}", file.display()))
        })?;

        let abs_file: &AbsPath = file.try_into().map_err(|_| {
            invalid_data_err(format!("expected an absolute path, got {}", file.display()))
        })?;
        let version_info = read_dylib_info(&abs_file)?;

        let lib = load_library(file).map_err(invalid_data_err)?;
        let abi = Abi::from_lib(&lib, symbol_name, version_info)?;
        Ok(ProcMacroLibraryLibloading { _lib: lib, abi })
    }
}

pub struct Expander {
    inner: ProcMacroLibraryLibloading,
}

impl Expander {
    pub fn new(lib: &Path) -> Result<Expander, LoadProcMacroDylibError> {
        // Some libraries for dynamic loading require canonicalized path even when it is
        // already absolute
        let lib = lib.canonicalize()?;

        let lib = ensure_file_with_lock_free_access(&lib)?;

        let library = ProcMacroLibraryLibloading::open(lib.as_ref())?;

        Ok(Expander { inner: library })
    }

    pub fn expand(
        &self,
        macro_name: &str,
        macro_body: &tt::Subtree,
        attributes: Option<&tt::Subtree>,
    ) -> Result<tt::Subtree, String> {
        let result = self.inner.abi.expand(macro_name, macro_body, attributes);
        result.map_err(|e| e.as_str().unwrap_or_else(|| "<unknown error>".to_string()))
    }

    pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> {
        self.inner.abi.list_macros()
    }
}

/// Copy the dylib to temp directory to prevent locking in Windows
#[cfg(windows)]
fn ensure_file_with_lock_free_access(path: &Path) -> io::Result<PathBuf> {
    use std::collections::hash_map::RandomState;
    use std::ffi::OsString;
    use std::hash::{BuildHasher, Hasher};

    if std::env::var("RA_DONT_COPY_PROC_MACRO_DLL").is_ok() {
        return Ok(path.to_path_buf());
    }

    let mut to = std::env::temp_dir();

    let file_name = path.file_name().ok_or_else(|| {
        io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("File path is invalid: {}", path.display()),
        )
    })?;

    // Generate a unique number by abusing `HashMap`'s hasher.
    // Maybe this will also "inspire" a libs team member to finally put `rand` in libstd.
    let t = RandomState::new().build_hasher().finish();

    let mut unique_name = OsString::from(t.to_string());
    unique_name.push(file_name);

    to.push(unique_name);
    std::fs::copy(path, &to).unwrap();
    Ok(to)
}

#[cfg(unix)]
fn ensure_file_with_lock_free_access(path: &Path) -> io::Result<PathBuf> {
    Ok(path.to_path_buf())
}
<|endoftext|>