<commit_before>// SPDX-License-Identifier: MIT

use std::collections::HashMap;
// use std::convert::TryFrom;

use clap::{Arg, App};

static DIRECTIONS : [(i64,i64); 8] = [
    (-1,-1), ( 0,-1), ( 1,-1),
    (-1, 0),          ( 1, 0),
    (-1, 1), ( 0, 1), ( 1, 1),
];

#[derive(Copy, Clone)]
pub struct BBox(i64,i64,i64,i64);// xmin, xmax, ymin, ymax
impl BBox {
    pub fn new() -> BBox {
        BBox(0,0,0,0)
    }

    #[inline]
    pub fn xmin(&self) -> i64 { self.0 }
    #[inline]
    pub fn xmax(&self) -> i64 { self.1 }
    #[inline]
    pub fn ymin(&self) -> i64 { self.2 }
    #[inline]
    pub fn ymax(&self) -> i64 { self.3 }

    #[inline]
    pub fn in_bounds(&self, x: i64, y: i64) -> bool {
        x >= self.0 && x <= self.1 && y >= self.2 && y <= self.3
    }

    #[inline]
    pub fn update(&mut self, x: i64, y: i64) {
        if x < self.0 { self.0 = x; }
        if x > self.1 { self.1 = x; }
        if y < self.2 { self.2 = y; }
        if y > self.3 { self.3 = y; }
    }
}
impl std::fmt::Display for BBox {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "BBox: {}, {}, {}, {}", self.0, self.1, self.2, self.3)
    }
}

#[derive(Clone)]
pub struct Floorplan {
    pub map: HashMap<(i64, i64), char>,
    pub bbox: BBox,
}
impl Floorplan {
    pub fn new() -> Floorplan {
        Floorplan { map: HashMap::new(), bbox: BBox::new() }
    }

    pub fn load(fname: &str) -> Floorplan {
        let mut plan = Floorplan::new();
        let contents = std::fs::read_to_string(fname)
            .unwrap_or_else(|err| panic!("Error reading {}: {}", fname, err));

        for (j, line) in contents.trim_end_matches('\n').split('\n').enumerate() {
            for (i, ch) in line.chars().enumerate() {
                if ch != '.' {
                    plan.insert((i as i64, j as i64), ch);
                }
                plan.bbox.update(i as i64, j as i64);
            }
        }
        return plan;
    }

    pub fn step1(&mut self) -> bool {
        let mut add = Vec::new();
        let mut rm  = Vec::new();

        for y in self.bbox.ymin()..=self.bbox.ymax() {
            for x in self.bbox.xmin()..=self.bbox.xmax() {
                match (self.at(x, y), self.count_neighbors(x, y)) {
                    ('L', 0)           => { add.push((x,y)); },
                    ('#', n) if n >= 4 => {  rm.push((x,y)); },
                    _ => { },
                }
            }
        }

        if add.is_empty() && rm.is_empty() { return false; }

        for (i, j) in add { self.insert((i, j), '#'); }
        for (i, j) in rm  { self.insert((i, j), 'L'); }
        return true;
    }

    pub fn step2(&mut self) -> bool {
        let mut add = Vec::new();
        let mut rm  = Vec::new();

        for y in self.bbox.ymin()..=self.bbox.ymax() {
            for x in self.bbox.xmin()..=self.bbox.xmax() {
                match (self.at(x, y), self.count_visible(x, y)) {
                    ('L', 0)           => { add.push((x,y)); },
                    ('#', n) if n >= 5 => {  rm.push((x,y)); },
                    _ => { },
                }
            }
        }

        if add.is_empty() && rm.is_empty() { return false; }

        for (i, j) in add { self.insert((i, j), '#'); }
        for (i, j) in rm  { self.insert((i, j), 'L'); }
        return true;
    }

    #[inline]
    pub fn count_neighbors(&self, x: i64, y: i64) -> u8 {
        let mut seated = 0;
        for (dx, dy) in DIRECTIONS.iter() {
            if '#' == self.at(x+dx, y+dy) { seated += 1; }
        }
        return seated;
    }

    #[inline]
    pub fn count_visible(&self, x: i64, y: i64) -> u8 {
        let mut seated = 0;
        for (dx, dy) in DIRECTIONS.iter() {
            let (mut x, mut y) = (x+dx, y+dy);
            while self.bbox.in_bounds(x, y) {
                match self.at(x, y) {
                    '#' => { seated += 1; break; },
                    'L' => { break; },
                    _   => { },
                }
                x += dx; y += dy;
            }
        }
        return seated;
    }

    #[inline]
    pub fn count(&self, ch: &char) -> u64 {
        let mut n = 0;
        for y in self.bbox.ymin()..=self.bbox.ymax() {
            for x in self.bbox.xmin()..=self.bbox.xmax() {
                match self.map.get(&(x,y)) {
                    Some(x) if x == ch => { n += 1; },
                    _ => { },
                }
            }
        }
        return n;
    }

    #[inline]
    pub fn at(&self, x: i64, y: i64) -> char {
        match self.map.get(&(x,y)) {
            Some(x) => *x,
            None    => '.',
        }
    }
}
impl std::ops::Deref for Floorplan {
    type Target = HashMap<(i64, i64), char>;
    fn deref(&self) -> &Self::Target { &self.map }
}
impl std::ops::DerefMut for Floorplan {
    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.map }
}
impl std::fmt::Display for Floorplan {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        for y in self.bbox.ymin()..=self.bbox.ymax() {
            for x in self.bbox.xmin()..=self.bbox.xmax() {
                write!(f, "{}", self.at(x, y))?;
            }
            write!(f, "{}", "\n")?;
        }
        Ok(())
    }
}

fn main() {
    let matches = App::new("Advent of code 2020, Day 11 Solution")
        .arg(Arg::with_name("FILE").help("Input file to process").index(1))
        .get_matches();
    let fname = matches.value_of("FILE").unwrap_or("11.in");
    let mut plan = Floorplan::load(fname);
//     println!("{}", plan);
    while plan.step1() { }
    println!("Part 1: {} occupied seats", plan.count(&'#'));
//     println!("{}", plan);

    let mut plan = Floorplan::load(fname);
//     println!("{}", plan);
    while plan.step2() { }
    println!("Part 2: {} occupied seats", plan.count(&'#'));
//     println!("{}", plan);
}
<commit_msg>Day 11 tests<commit_after>// SPDX-License-Identifier: MIT

use std::collections::HashMap;
// use std::convert::TryFrom;

use clap::{Arg, App};

static DIRECTIONS : [(i64,i64); 8] = [
    (-1,-1), ( 0,-1), ( 1,-1),
    (-1, 0),          ( 1, 0),
    (-1, 1), ( 0, 1), ( 1, 1),
];

#[derive(Copy, Clone)]
pub struct BBox(i64,i64,i64,i64);// xmin, xmax, ymin, ymax
impl BBox {
    pub fn new() -> BBox {
        BBox(0,0,0,0)
    }

    #[inline]
    pub fn xmin(&self) -> i64 { self.0 }
    #[inline]
    pub fn xmax(&self) -> i64 { self.1 }
    #[inline]
    pub fn ymin(&self) -> i64 { self.2 }
    #[inline]
    pub fn ymax(&self) -> i64 { self.3 }

    #[inline]
    pub fn in_bounds(&self, x: i64, y: i64) -> bool {
        x >= self.0 && x <= self.1 && y >= self.2 && y <= self.3
    }

    #[inline]
    pub fn update(&mut self, x: i64, y: i64) {
        if x < self.0 { self.0 = x; }
        if x > self.1 { self.1 = x; }
        if y < self.2 { self.2 = y; }
        if y > self.3 { self.3 = y; }
    }
}
impl std::fmt::Display for BBox {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "BBox: {}, {}, {}, {}", self.0, self.1, self.2, self.3)
    }
}

#[derive(Clone)]
pub struct Floorplan {
    pub map: HashMap<(i64, i64), char>,
    pub bbox: BBox,
}
impl Floorplan {
    pub fn new() -> Floorplan {
        Floorplan { map: HashMap::new(), bbox: BBox::new() }
    }

    pub fn load(fname: &str) -> Floorplan {
        let mut plan = Floorplan::new();
        let contents = std::fs::read_to_string(fname)
            .unwrap_or_else(|err| panic!("Error reading {}: {}", fname, err));

        for (j, line) in contents.trim_end_matches('\n').split('\n').enumerate() {
            for (i, ch) in line.chars().enumerate() {
                if ch != '.' {
                    plan.insert((i as i64, j as i64), ch);
                }
                plan.bbox.update(i as i64, j as i64);
            }
        }
        return plan;
    }

    pub fn step1(&mut self) -> bool {
        let mut add = Vec::new();
        let mut rm  = Vec::new();

        for y in self.bbox.ymin()..=self.bbox.ymax() {
            for x in self.bbox.xmin()..=self.bbox.xmax() {
                match (self.at(x, y), self.count_neighbors(x, y)) {
                    ('L', 0)           => { add.push((x,y)); },
                    ('#', n) if n >= 4 => {  rm.push((x,y)); },
                    _ => { },
                }
            }
        }

        if add.is_empty() && rm.is_empty() { return false; }

        for (i, j) in add { self.insert((i, j), '#'); }
        for (i, j) in rm  { self.insert((i, j), 'L'); }
        return true;
    }

    pub fn step2(&mut self) -> bool {
        let mut add = Vec::new();
        let mut rm  = Vec::new();

        for y in self.bbox.ymin()..=self.bbox.ymax() {
            for x in self.bbox.xmin()..=self.bbox.xmax() {
                match (self.at(x, y), self.count_visible(x, y)) {
                    ('L', 0)           => { add.push((x,y)); },
                    ('#', n) if n >= 5 => {  rm.push((x,y)); },
                    _ => { },
                }
            }
        }

        if add.is_empty() && rm.is_empty() { return false; }

        for (i, j) in add { self.insert((i, j), '#'); }
        for (i, j) in rm  { self.insert((i, j), 'L'); }
        return true;
    }

    #[inline]
    pub fn count_neighbors(&self, x: i64, y: i64) -> u8 {
        let mut seated = 0;
        for (dx, dy) in DIRECTIONS.iter() {
            if '#' == self.at(x+dx, y+dy) { seated += 1; }
        }
        return seated;
    }

    #[inline]
    pub fn count_visible(&self, x: i64, y: i64) -> u8 {
        let mut seated = 0;
        for (dx, dy) in DIRECTIONS.iter() {
            let (mut x, mut y) = (x+dx, y+dy);
            while self.bbox.in_bounds(x, y) {
                match self.at(x, y) {
                    '#' => { seated += 1; break; },
                    'L' => { break; },
                    _   => { },
                }
                x += dx; y += dy;
            }
        }
        return seated;
    }

    #[inline]
    pub fn count(&self, ch: &char) -> u64 {
        let mut n = 0;
        for y in self.bbox.ymin()..=self.bbox.ymax() {
            for x in self.bbox.xmin()..=self.bbox.xmax() {
                match self.map.get(&(x,y)) {
                    Some(x) if x == ch => { n += 1; },
                    _ => { },
                }
            }
        }
        return n;
    }

    #[inline]
    pub fn at(&self, x: i64, y: i64) -> char {
        match self.map.get(&(x,y)) {
            Some(x) => *x,
            None    => '.',
        }
    }
}
impl std::ops::Deref for Floorplan {
    type Target = HashMap<(i64, i64), char>;
    fn deref(&self) -> &Self::Target { &self.map }
}
impl std::ops::DerefMut for Floorplan {
    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.map }
}
impl std::fmt::Display for Floorplan {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        for y in self.bbox.ymin()..=self.bbox.ymax() {
            for x in self.bbox.xmin()..=self.bbox.xmax() {
                write!(f, "{}", self.at(x, y))?;
            }
            write!(f, "{}", "\n")?;
        }
        Ok(())
    }
}

fn main() {
    let matches = App::new("Advent of code 2020, Day 11 Solution")
        .arg(Arg::with_name("FILE").help("Input file to process").index(1))
        .get_matches();
    let fname = matches.value_of("FILE").unwrap_or("11.in");
    let mut plan = Floorplan::load(fname);
//     println!("{}", plan);
    while plan.step1() { }
    println!("Part 1: {} occupied seats", plan.count(&'#'));
//     println!("{}", plan);

    let mut plan = Floorplan::load(fname);
//     println!("{}", plan);
    while plan.step2() { }
    println!("Part 2: {} occupied seats", plan.count(&'#'));
//     println!("{}", plan);
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test1() {
        let mut plan = Floorplan::load("11.in");
        while plan.step1() { }
        assert_eq!(plan.count(&'#'), 2476);
    }

    #[test]
    fn test2() {
        let mut plan = Floorplan::load("11.in");
        while plan.step2() { }
        assert_eq!(plan.count(&'#'), 2257);
    }
}

<|endoftext|>


<commit_before>use crate::attr::Display;
use proc_macro2::TokenStream;
use quote::quote_spanned;
use syn::{Ident, LitStr};

impl Display<'_> {
    // Transform `"error {var}"` to `"error {}", var`.
    pub fn expand_shorthand(&mut self) {
        if !self.args.is_empty() {
            return;
        }

        let span = self.fmt.span();
        let fmt = self.fmt.value();
        let mut read = fmt.as_str();
        let mut out = String::new();
        let mut args = TokenStream::new();

        while let Some(brace) = read.find('{') {
            out += &read[..=brace];
            read = &read[brace + 1..];
            if read.starts_with('{') {
                out.push('{');
                read = &read[1..];
                continue;
            }
            let next = match read.chars().next() {
                Some(next) => next,
                None => return,
            };
            let var = match next {
                '0'..='9' => take_int(&mut read),
                'a'..='z' | 'A'..='Z' | '_' => take_ident(&mut read),
                _ => return,
            };
            let ident = Ident::new(&var, span);
            args.extend(quote_spanned!(span=> , #ident));
        }

        out += read;
        self.fmt = LitStr::new(&out, self.fmt.span());
        self.args = args;
        self.was_shorthand = true;
    }
}

fn take_int(read: &mut &str) -> String {
    let mut int = String::new();
    int.push('_');
    for (i, ch) in read.char_indices() {
        match ch {
            '0'..='9' => int.push(ch),
            _ => {
                *read = &read[i..];
                break;
            }
        }
    }
    int
}

fn take_ident(read: &mut &str) -> String {
    let mut ident = String::new();
    for (i, ch) in read.char_indices() {
        match ch {
            'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => ident.push(ch),
            _ => {
                *read = &read[i..];
                break;
            }
        }
    }
    ident
}

#[cfg(test)]
mod tests {
    use super::*;
    use proc_macro2::Span;

    fn assert(input: &str, fmt: &str, args: &str) {
        let mut display = Display {
            fmt: LitStr::new(input, Span::call_site()),
            args: TokenStream::new(),
        };
        display.expand_shorthand();
        assert_eq!(fmt, display.fmt.value());
        assert_eq!(args, display.args.to_string());
    }

    #[test]
    fn test_expand() {
        assert("error {var}", "error {}", ", var");
        assert("fn main() {{ }}", "fn main() {{ }}", "");
        assert(
            "{v} {v:?} {0} {0:?}",
            "{} {:?} {} {:?}",
            ", v , v , _0 , _0",
        );
    }
}
<commit_msg>Fill in missing fields of thiserror-impl unit test<commit_after>use crate::attr::Display;
use proc_macro2::TokenStream;
use quote::quote_spanned;
use syn::{Ident, LitStr};

impl Display<'_> {
    // Transform `"error {var}"` to `"error {}", var`.
    pub fn expand_shorthand(&mut self) {
        if !self.args.is_empty() {
            return;
        }

        let span = self.fmt.span();
        let fmt = self.fmt.value();
        let mut read = fmt.as_str();
        let mut out = String::new();
        let mut args = TokenStream::new();

        while let Some(brace) = read.find('{') {
            out += &read[..=brace];
            read = &read[brace + 1..];
            if read.starts_with('{') {
                out.push('{');
                read = &read[1..];
                continue;
            }
            let next = match read.chars().next() {
                Some(next) => next,
                None => return,
            };
            let var = match next {
                '0'..='9' => take_int(&mut read),
                'a'..='z' | 'A'..='Z' | '_' => take_ident(&mut read),
                _ => return,
            };
            let ident = Ident::new(&var, span);
            args.extend(quote_spanned!(span=> , #ident));
        }

        out += read;
        self.fmt = LitStr::new(&out, self.fmt.span());
        self.args = args;
        self.was_shorthand = true;
    }
}

fn take_int(read: &mut &str) -> String {
    let mut int = String::new();
    int.push('_');
    for (i, ch) in read.char_indices() {
        match ch {
            '0'..='9' => int.push(ch),
            _ => {
                *read = &read[i..];
                break;
            }
        }
    }
    int
}

fn take_ident(read: &mut &str) -> String {
    let mut ident = String::new();
    for (i, ch) in read.char_indices() {
        match ch {
            'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => ident.push(ch),
            _ => {
                *read = &read[i..];
                break;
            }
        }
    }
    ident
}

#[cfg(test)]
mod tests {
    use super::*;
    use proc_macro2::Span;
    use syn::parse_quote;

    fn assert(input: &str, fmt: &str, args: &str) {
        let mut display = Display {
            original: &parse_quote!(#[error]),
            fmt: LitStr::new(input, Span::call_site()),
            args: TokenStream::new(),
            was_shorthand: false,
        };
        display.expand_shorthand();
        assert_eq!(fmt, display.fmt.value());
        assert_eq!(args, display.args.to_string());
    }

    #[test]
    fn test_expand() {
        assert("error {var}", "error {}", ", var");
        assert("fn main() {{ }}", "fn main() {{ }}", "");
        assert(
            "{v} {v:?} {0} {0:?}",
            "{} {:?} {} {:?}",
            ", v , v , _0 , _0",
        );
    }
}
<|endoftext|>


<commit_before>#![recursion_limit = "1024"]
extern crate proc_macro;
#[macro_use]
extern crate quote;
extern crate syn;

#[cfg(feature = "interpolate-folder-path")]
extern crate shellexpand;
extern crate walkdir;

use proc_macro::TokenStream;
use quote::Tokens;
use std::path::Path;
use syn::*;

#[cfg(all(debug_assertions, not(feature = "debug-embed")))]
fn generate_assets(ident: &syn::Ident, folder_path: String) -> quote::Tokens {
  quote! {
      impl #ident {
          pub fn get(file_path: &str) -> Option<std::borrow::Cow<'static, [u8]>> {
              use std::fs::File;
              use std::io::Read;
              use std::path::Path;

              let file_path = Path::new(#folder_path).join(file_path);
              let mut file = match File::open(file_path) {
                  Ok(mut file) => file,
                  Err(_e) => {
                      return None
                  }
              };
              let mut data: Vec<u8> = Vec::new();
              match file.read_to_end(&mut data) {
                  Ok(_) => Some(std::borrow::Cow::from(data)),
                  Err(_e) =>  {
                      return None
                  }
              }
          }

          pub fn iter() -> impl Iterator<Item = std::borrow::Cow<'static, str>> {
              use std::path::Path;
              rust_embed::utils::get_files(String::from(#folder_path)).map(|e| std::borrow::Cow::from(e.rel_path))
          }
      }
      impl rust_embed::RustEmbed for #ident {
        fn get(file_path: &str) -> Option<std::borrow::Cow<'static, [u8]>> {
          #ident::get(file_path)
        }
        fn iter() -> rust_embed::Filenames {
          // the return type of iter() is unnamable, so we have to box it
          rust_embed::Filenames::Dynamic(Box::new(#ident::iter()))
        }
      }
  }
}

#[cfg(any(not(debug_assertions), feature = "debug-embed"))]
fn generate_assets(ident: &syn::Ident, folder_path: String) -> quote::Tokens {
  extern crate rust_embed_utils;

  let mut match_values = Vec::<Tokens>::new();
  let mut list_values = Vec::<String>::new();

  for rust_embed_utils::FileEntry { rel_path, full_canonical_path } in rust_embed_utils::get_files(folder_path) {
    match_values.push(quote! {
      #rel_path => {
          let bytes = &include_bytes!(#full_canonical_path)[..];
          Some(std::borrow::Cow::from(bytes))
      },
    });
    list_values.push(rel_path);
  }

  let array_len = list_values.len();

  quote! {
      impl #ident {
          pub fn get(file_path: &str) -> Option<std::borrow::Cow<'static, [u8]>> {
              match file_path {
                  #(#match_values)*
                  _ => None,
              }
          }

          fn names() -> std::slice::Iter<'static, &'static str> {
            const items: [&str; #array_len] = [#(#list_values),*];
            items.iter()
          }
          pub fn iter() -> impl Iterator<Item = std::borrow::Cow<'static, str>> {
              Self::names().map(|x| std::borrow::Cow::from(*x))
          }
      }
      impl rust_embed::RustEmbed for #ident {
        fn get(file_path: &str) -> Option<std::borrow::Cow<'static, [u8]>> {
          #ident::get(file_path)
        }
        fn iter() -> rust_embed::Filenames {
          rust_embed::Filenames::Embedded(#ident::names())
        }
      }
  }
}

fn impl_rust_embed(ast: &syn::DeriveInput) -> Tokens {
  match ast.body {
    Body::Enum(_) => panic!("RustEmbed cannot be derived for enums"),
    Body::Struct(ref data) => match data {
      &VariantData::Unit => {},
      _ => panic!("RustEmbed can only be derived for unit structs")
    },
  };

  let attribute = ast.attrs.iter().map(|attr| &attr.value).find(|value| value.name() == "folder");
  let literal_value = match attribute {
    Some(&MetaItem::NameValue(_, ref literal)) => literal,
    _ => panic!("#[derive(RustEmbed)] should contain one attribute like this #[folder = \"examples/public/\"]"),
  };
  let folder_path = match literal_value {
    &Lit::Str(ref val, _) => val.clone(),
    _ => {
      panic!("#[derive(RustEmbed)] attribute value must be a string literal");
    }
  };

  #[cfg(feature = "interpolate-folder-path")]
  let folder_path = shellexpand::full(&folder_path).unwrap().to_string();

  if !Path::new(&folder_path).exists() {
    let mut message = format!(
      "#[derive(RustEmbed)] folder '{}' does not exist. cwd: '{}'",
      folder_path,
      std::env::current_dir().unwrap().to_str().unwrap()
    );

    // Add a message about the interpolate-folder-path feature if the path may
    // include a variable
    if folder_path.contains("$") && cfg!(not(feature = "interpolate-folder-path")) {
      message += "\nA variable has been detected. RustEmbed can expand variables \
                  when the `interpolate-folder-path` feature is enabled.";
    }

    panic!(message);
  };

  generate_assets(&ast.ident, folder_path)
}

#[proc_macro_derive(RustEmbed, attributes(folder))]
pub fn derive_input_object(input: TokenStream) -> TokenStream {
  let s = input.to_string();
  let ast = syn::parse_derive_input(&s).unwrap();
  let gen = impl_rust_embed(&ast);
  gen.parse().unwrap()
}
<commit_msg>Run rustfmt<commit_after>#![recursion_limit = "1024"]
extern crate proc_macro;
#[macro_use]
extern crate quote;
extern crate syn;

#[cfg(feature = "interpolate-folder-path")]
extern crate shellexpand;
extern crate walkdir;

use proc_macro::TokenStream;
use quote::Tokens;
use std::path::Path;
use syn::*;

#[cfg(all(debug_assertions, not(feature = "debug-embed")))]
fn generate_assets(ident: &syn::Ident, folder_path: String) -> quote::Tokens {
  quote! {
      impl #ident {
          pub fn get(file_path: &str) -> Option<std::borrow::Cow<'static, [u8]>> {
              use std::fs::File;
              use std::io::Read;
              use std::path::Path;

              let file_path = Path::new(#folder_path).join(file_path);
              let mut file = match File::open(file_path) {
                  Ok(mut file) => file,
                  Err(_e) => {
                      return None
                  }
              };
              let mut data: Vec<u8> = Vec::new();
              match file.read_to_end(&mut data) {
                  Ok(_) => Some(std::borrow::Cow::from(data)),
                  Err(_e) =>  {
                      return None
                  }
              }
          }

          pub fn iter() -> impl Iterator<Item = std::borrow::Cow<'static, str>> {
              use std::path::Path;
              rust_embed::utils::get_files(String::from(#folder_path)).map(|e| std::borrow::Cow::from(e.rel_path))
          }
      }
      impl rust_embed::RustEmbed for #ident {
        fn get(file_path: &str) -> Option<std::borrow::Cow<'static, [u8]>> {
          #ident::get(file_path)
        }
        fn iter() -> rust_embed::Filenames {
          // the return type of iter() is unnamable, so we have to box it
          rust_embed::Filenames::Dynamic(Box::new(#ident::iter()))
        }
      }
  }
}

#[cfg(any(not(debug_assertions), feature = "debug-embed"))]
fn generate_assets(ident: &syn::Ident, folder_path: String) -> quote::Tokens {
  extern crate rust_embed_utils;

  let mut match_values = Vec::<Tokens>::new();
  let mut list_values = Vec::<String>::new();

  for rust_embed_utils::FileEntry { rel_path, full_canonical_path } in rust_embed_utils::get_files(folder_path) {
    match_values.push(quote! {
      #rel_path => {
          let bytes = &include_bytes!(#full_canonical_path)[..];
          Some(std::borrow::Cow::from(bytes))
      },
    });
    list_values.push(rel_path);
  }

  let array_len = list_values.len();

  quote! {
      impl #ident {
          pub fn get(file_path: &str) -> Option<std::borrow::Cow<'static, [u8]>> {
              match file_path {
                  #(#match_values)*
                  _ => None,
              }
          }

          fn names() -> std::slice::Iter<'static, &'static str> {
            const items: [&str; #array_len] = [#(#list_values),*];
            items.iter()
          }
          pub fn iter() -> impl Iterator<Item = std::borrow::Cow<'static, str>> {
              Self::names().map(|x| std::borrow::Cow::from(*x))
          }
      }
      impl rust_embed::RustEmbed for #ident {
        fn get(file_path: &str) -> Option<std::borrow::Cow<'static, [u8]>> {
          #ident::get(file_path)
        }
        fn iter() -> rust_embed::Filenames {
          rust_embed::Filenames::Embedded(#ident::names())
        }
      }
  }
}

fn impl_rust_embed(ast: &syn::DeriveInput) -> Tokens {
  match ast.body {
    Body::Enum(_) => panic!("RustEmbed cannot be derived for enums"),
    Body::Struct(ref data) => match data {
      &VariantData::Unit => {}
      _ => panic!("RustEmbed can only be derived for unit structs"),
    },
  };

  let attribute = ast.attrs.iter().map(|attr| &attr.value).find(|value| value.name() == "folder");
  let literal_value = match attribute {
    Some(&MetaItem::NameValue(_, ref literal)) => literal,
    _ => panic!("#[derive(RustEmbed)] should contain one attribute like this #[folder = \"examples/public/\"]"),
  };
  let folder_path = match literal_value {
    &Lit::Str(ref val, _) => val.clone(),
    _ => {
      panic!("#[derive(RustEmbed)] attribute value must be a string literal");
    }
  };

  #[cfg(feature = "interpolate-folder-path")]
  let folder_path = shellexpand::full(&folder_path).unwrap().to_string();

  if !Path::new(&folder_path).exists() {
    let mut message = format!(
      "#[derive(RustEmbed)] folder '{}' does not exist. cwd: '{}'",
      folder_path,
      std::env::current_dir().unwrap().to_str().unwrap()
    );

    // Add a message about the interpolate-folder-path feature if the path may
    // include a variable
    if folder_path.contains("$") && cfg!(not(feature = "interpolate-folder-path")) {
      message += "\nA variable has been detected. RustEmbed can expand variables \
                  when the `interpolate-folder-path` feature is enabled.";
    }

    panic!(message);
  };

  generate_assets(&ast.ident, folder_path)
}

#[proc_macro_derive(RustEmbed, attributes(folder))]
pub fn derive_input_object(input: TokenStream) -> TokenStream {
  let s = input.to_string();
  let ast = syn::parse_derive_input(&s).unwrap();
  let gen = impl_rust_embed(&ast);
  gen.parse().unwrap()
}
<|endoftext|>


<commit_before>#![allow(
    clippy::blocks_in_if_conditions,
    clippy::cast_lossless,
    clippy::cast_possible_truncation,
    clippy::manual_map,
    clippy::map_unwrap_or,
    clippy::needless_pass_by_value,
    clippy::option_if_let_else,
    clippy::range_plus_one,
    clippy::single_match_else,
    clippy::too_many_lines
)]

extern crate proc_macro;

mod ast;
mod attr;
mod expand;
mod fmt;
mod generics;
mod prop;
mod valid;

use proc_macro::TokenStream;
use syn::{parse_macro_input, DeriveInput};

#[proc_macro_derive(Error, attributes(backtrace, error, from, source))]
pub fn derive_error(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    expand::derive(&input)
        .unwrap_or_else(|err| err.to_compile_error())
        .into()
}
<commit_msg>Ignore wrong_self_convention clippy lint<commit_after>#![allow(
    clippy::blocks_in_if_conditions,
    clippy::cast_lossless,
    clippy::cast_possible_truncation,
    clippy::manual_map,
    clippy::map_unwrap_or,
    clippy::needless_pass_by_value,
    clippy::option_if_let_else,
    clippy::range_plus_one,
    clippy::single_match_else,
    clippy::too_many_lines,
    clippy::wrong_self_convention
)]

extern crate proc_macro;

mod ast;
mod attr;
mod expand;
mod fmt;
mod generics;
mod prop;
mod valid;

use proc_macro::TokenStream;
use syn::{parse_macro_input, DeriveInput};

#[proc_macro_derive(Error, attributes(backtrace, error, from, source))]
pub fn derive_error(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    expand::derive(&input)
        .unwrap_or_else(|err| err.to_compile_error())
        .into()
}
<|endoftext|>


<commit_before>use id_allocator::IdAllocator;
use in_progress_terrain::InProgressTerrain;
use physics::Physics;
use state::EntityId;
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry;
use std::rc::Rc;
use stopwatch::TimerSet;
use terrain::Terrain;
use terrain_block::BlockPosition;
use terrain_vram_buffers::TerrainVRAMBuffers;
use yaglw::gl_context::{GLContext, GLContextExistence};
use yaglw::shader::Shader;
use yaglw::texture::TextureUnit;

/// These are used to identify the owners of terrain load operations.
#[deriving(Copy, Clone, Show, PartialEq, Eq, Hash, Default)]
pub struct OwnerId(u32);

impl Add<u32, OwnerId> for OwnerId {
  fn add(self, rhs: u32) -> OwnerId {
    let OwnerId(id) = self;
    OwnerId(id + rhs)
  }
}

/// Load and unload TerrainBlocks from the game.
pub trait TerrainGameLoader {
  /// Ensure a `TerrainBlock` is loaded.
  fn load(
    &mut self,
    timers: &TimerSet,
    gl: &mut GLContext,
    id_allocator: &mut IdAllocator<EntityId>,
    physics: &mut Physics,
    block_position: &BlockPosition,
    lod: uint,
    owner: OwnerId,
  );

  /// Release a request for a `TerrainBlock`.
  fn unload(
    &mut self,
    timers: &TimerSet,
    gl: &mut GLContext,
    physics: &mut Physics,
    block_position: &BlockPosition,
    owner: OwnerId,
  );

  /// If the block is not already loaded, insert a solid block as a placeholder.
  /// Returns true if the block is not already loaded.
  fn insert_placeholder(
    &mut self,
    id_allocator: &mut IdAllocator<EntityId>,
    physics: &mut Physics,
    block_position: &BlockPosition,
    owner: OwnerId,
  );

  /// Remove a placeholder that was inserted by insert_placeholder.
  /// Returns true if a placeholder was removed.
  fn remove_placeholder(
    &mut self,
    physics: &mut Physics,
    block_position: &BlockPosition,
    owner: OwnerId,
  );
}

struct BlockLoadState {
  pub owners: HashSet<OwnerId>,
  /// If this is None, only a placeholder is loaded.
  pub loaded_lod: Option<uint>,
}

pub struct Default<'a> {
  pub terrain: Terrain,
  pub terrain_vram_buffers: TerrainVRAMBuffers<'a>,
  pub in_progress_terrain: InProgressTerrain,
  // The blocks that are currently loaded, and their owners and
  pub loaded: HashMap<BlockPosition, BlockLoadState>,
}

impl<'a> Default<'a> {
  pub fn new(
    gl: &'a GLContextExistence,
    gl_context: &mut GLContext,
    shader: Rc<RefCell<Shader>>,
    texture_unit_alloc: &mut IdAllocator<TextureUnit>,
  ) -> Default<'a> {
    let terrain_vram_buffers = TerrainVRAMBuffers::new(gl, gl_context);
    terrain_vram_buffers.bind_glsl_uniforms(gl_context, texture_unit_alloc, shader.clone());

    Default {
      terrain: Terrain::new(),
      terrain_vram_buffers: terrain_vram_buffers,
      in_progress_terrain: InProgressTerrain::new(),
      loaded: HashMap::new(),
    }
  }
}

impl<'a> TerrainGameLoader for Default<'a> {
  fn load(
    &mut self,
    timers: &TimerSet,
    gl: &mut GLContext,
    id_allocator: &mut IdAllocator<EntityId>,
    physics: &mut Physics,
    block_position: &BlockPosition,
    lod: uint,
    owner: OwnerId,
  ) {
    match self.loaded.entry(*block_position) {
      Entry::Occupied(mut entry) => {
        let block_load_state = entry.get_mut();
        let already_loaded = block_load_state.loaded_lod.is_some();
        block_load_state.owners.insert(owner);
        if already_loaded {
          return;
        }
        block_load_state.loaded_lod = Some(lod);
      },
      Entry::Vacant(entry) => {
        let mut owners = HashSet::new();
        owners.insert(owner);
        entry.set(BlockLoadState {
          owners: owners,
          loaded_lod: Some(lod),
        });
      },
    }

    timers.time("terrain_game_loader.load", || {
      let block = unsafe {
        self.terrain.load(timers, id_allocator, block_position, lod)
      };

      timers.time("terrain_game_loader.load.physics", || {
        for (&id, bounds) in block.bounds.iter() {
          physics.insert_terrain(id, bounds.clone());
        }
      });

      let terrain_vram_buffers = &mut self.terrain_vram_buffers;
      timers.time("terrain_game_loader.load.gpu", || {
        terrain_vram_buffers.push(
          gl,
          block.vertex_coordinates.as_slice(),
          block.normals.as_slice(),
          block.typs.as_slice(),
          block.ids.as_slice(),
        );
      });

      self.in_progress_terrain.remove(physics, block_position);
    });
  }

  fn unload(
    &mut self,
    timers: &TimerSet,
    gl: &mut GLContext,
    physics: &mut Physics,
    block_position: &BlockPosition,
    owner: OwnerId,
  ) {
    let loaded_lod;
    match self.loaded.entry(*block_position) {
      Entry::Occupied(mut entry) => {
        {
          let block_load_state = entry.get_mut();
          match block_load_state.loaded_lod {
            None => return,
            Some(lod) => loaded_lod = lod,
          };
          let should_unload =
            block_load_state.owners.remove(&owner)
            && block_load_state.owners.is_empty();
          if !should_unload {
            return;
          }
        }
        entry.take();
      },
      Entry::Vacant(_) => {
        return;
      },
    };

    timers.time("terrain_game_loader.unload", || {
      let lods =
        self.terrain.all_blocks.get(block_position)
        .unwrap()
        .lods
        .as_slice();
      let block = lods[loaded_lod].as_ref().unwrap();
      for id in block.ids.iter() {
        physics.remove_terrain(*id);
        self.terrain_vram_buffers.swap_remove(gl, *id);
      }
    });
  }

  /// Note that we want a specific `TerrainBlock`.
  fn insert_placeholder(
    &mut self,
    id_allocator: &mut IdAllocator<EntityId>,
    physics: &mut Physics,
    block_position: &BlockPosition,
    owner: OwnerId,
  ) {
    match self.loaded.entry(*block_position) {
      Entry::Occupied(mut entry) => {
        let block_load_state = entry.get_mut();
        block_load_state.owners.insert(owner);
      },
      Entry::Vacant(entry) => {
        let mut owners = HashSet::new();
        owners.insert(owner);
        entry.set(BlockLoadState {
          owners: owners,
          loaded_lod: None,
        });
        assert!(self.in_progress_terrain.insert(id_allocator, physics, block_position));
      },
    }
  }

  fn remove_placeholder(
    &mut self,
    physics: &mut Physics,
    block_position: &BlockPosition,
    owner: OwnerId,
  ) {
    match self.loaded.entry(*block_position) {
      Entry::Occupied(mut entry) => {
        {
          let block_load_state = entry.get_mut();
          let should_unload =
            block_load_state.loaded_lod.is_none()
            && block_load_state.owners.remove(&owner)
            && block_load_state.owners.is_empty();
          if !should_unload {
            return;
          }
        }
        entry.take();
      },
      Entry::Vacant(_) => {
        return;
      },
    };

    assert!(self.in_progress_terrain.remove(physics, block_position));
  }
}
<commit_msg>Re-load a terrain block if it's requested at a new LOD.<commit_after>use id_allocator::IdAllocator;
use in_progress_terrain::InProgressTerrain;
use physics::Physics;
use state::EntityId;
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry;
use std::rc::Rc;
use stopwatch::TimerSet;
use terrain::Terrain;
use terrain_block::BlockPosition;
use terrain_vram_buffers::TerrainVRAMBuffers;
use yaglw::gl_context::{GLContext, GLContextExistence};
use yaglw::shader::Shader;
use yaglw::texture::TextureUnit;

/// These are used to identify the owners of terrain load operations.
#[deriving(Copy, Clone, Show, PartialEq, Eq, Hash, Default)]
pub struct OwnerId(u32);

impl Add<u32, OwnerId> for OwnerId {
  fn add(self, rhs: u32) -> OwnerId {
    let OwnerId(id) = self;
    OwnerId(id + rhs)
  }
}

/// Load and unload TerrainBlocks from the game.
pub trait TerrainGameLoader {
  /// Ensure a `TerrainBlock` is loaded.
  fn load(
    &mut self,
    timers: &TimerSet,
    gl: &mut GLContext,
    id_allocator: &mut IdAllocator<EntityId>,
    physics: &mut Physics,
    block_position: &BlockPosition,
    lod: uint,
    owner: OwnerId,
  );

  /// Release a request for a `TerrainBlock`.
  fn unload(
    &mut self,
    timers: &TimerSet,
    gl: &mut GLContext,
    physics: &mut Physics,
    block_position: &BlockPosition,
    owner: OwnerId,
  );

  /// If the block is not already loaded, insert a solid block as a placeholder.
  /// Returns true if the block is not already loaded.
  fn insert_placeholder(
    &mut self,
    id_allocator: &mut IdAllocator<EntityId>,
    physics: &mut Physics,
    block_position: &BlockPosition,
    owner: OwnerId,
  );

  /// Remove a placeholder that was inserted by insert_placeholder.
  /// Returns true if a placeholder was removed.
  fn remove_placeholder(
    &mut self,
    physics: &mut Physics,
    block_position: &BlockPosition,
    owner: OwnerId,
  );
}

struct BlockLoadState {
  pub owners: HashSet<OwnerId>,
  /// If this is None, only a placeholder is loaded.
  pub loaded_lod: Option<uint>,
}

pub struct Default<'a> {
  pub terrain: Terrain,
  pub terrain_vram_buffers: TerrainVRAMBuffers<'a>,
  pub in_progress_terrain: InProgressTerrain,
  // The blocks that are currently loaded, and their owners and
  pub loaded: HashMap<BlockPosition, BlockLoadState>,
}

impl<'a> Default<'a> {
  pub fn new(
    gl: &'a GLContextExistence,
    gl_context: &mut GLContext,
    shader: Rc<RefCell<Shader>>,
    texture_unit_alloc: &mut IdAllocator<TextureUnit>,
  ) -> Default<'a> {
    let terrain_vram_buffers = TerrainVRAMBuffers::new(gl, gl_context);
    terrain_vram_buffers.bind_glsl_uniforms(gl_context, texture_unit_alloc, shader.clone());

    Default {
      terrain: Terrain::new(),
      terrain_vram_buffers: terrain_vram_buffers,
      in_progress_terrain: InProgressTerrain::new(),
      loaded: HashMap::new(),
    }
  }

  fn unload_internal(
    &mut self,
    timers: &TimerSet,
    gl: &mut GLContext,
    physics: &mut Physics,
    block_position: &BlockPosition,
    loaded_lod: uint,
  ) {
    timers.time("terrain_game_loader.unload", || {
      let lods =
        self.terrain.all_blocks.get(block_position)
        .unwrap()
        .lods
        .as_slice();
      let block = lods[loaded_lod].as_ref().unwrap();
      for id in block.ids.iter() {
        physics.remove_terrain(*id);
        self.terrain_vram_buffers.swap_remove(gl, *id);
      }
    });
  }
}

impl<'a> TerrainGameLoader for Default<'a> {
  fn load(
    &mut self,
    timers: &TimerSet,
    gl: &mut GLContext,
    id_allocator: &mut IdAllocator<EntityId>,
    physics: &mut Physics,
    block_position: &BlockPosition,
    lod: uint,
    owner: OwnerId,
  ) {
    let mut loaded_lod = None;
    match self.loaded.entry(*block_position) {
      Entry::Occupied(mut entry) => {
        let block_load_state = entry.get_mut();
        block_load_state.owners.insert(owner);
        match block_load_state.loaded_lod {
          None => {},
          Some(loaded_lod) => {
            if loaded_lod == lod {
              // Already loaded at the right LOD.
              return;
            }
          }
        }
        loaded_lod = block_load_state.loaded_lod;
        block_load_state.loaded_lod = Some(lod);
      },
      Entry::Vacant(entry) => {
        let mut owners = HashSet::new();
        owners.insert(owner);
        entry.set(BlockLoadState {
          owners: owners,
          loaded_lod: Some(lod),
        });
      },
    }

    // It's loaded, but at the wrong LOD.
    loaded_lod.map(
      |loaded_lod|
        self.unload_internal(timers, gl, physics, block_position, loaded_lod)
    );

    timers.time("terrain_game_loader.load", || {
      let block = unsafe {
        self.terrain.load(timers, id_allocator, block_position, lod)
      };

      timers.time("terrain_game_loader.load.physics", || {
        for (&id, bounds) in block.bounds.iter() {
          physics.insert_terrain(id, bounds.clone());
        }
      });

      let terrain_vram_buffers = &mut self.terrain_vram_buffers;
      timers.time("terrain_game_loader.load.gpu", || {
        terrain_vram_buffers.push(
          gl,
          block.vertex_coordinates.as_slice(),
          block.normals.as_slice(),
          block.typs.as_slice(),
          block.ids.as_slice(),
        );
      });

      self.in_progress_terrain.remove(physics, block_position);
    });
  }

  fn unload(
    &mut self,
    timers: &TimerSet,
    gl: &mut GLContext,
    physics: &mut Physics,
    block_position: &BlockPosition,
    owner: OwnerId,
  ) {
    let loaded_lod;
    match self.loaded.entry(*block_position) {
      Entry::Occupied(mut entry) => {
        {
          let block_load_state = entry.get_mut();
          match block_load_state.loaded_lod {
            None => return,
            Some(lod) => loaded_lod = lod,
          };
          let should_unload =
            block_load_state.owners.remove(&owner)
            && block_load_state.owners.is_empty();
          if !should_unload {
            return;
          }
        }
        entry.take();
      },
      Entry::Vacant(_) => {
        return;
      },
    };

    self.unload_internal(timers, gl, physics, block_position, loaded_lod);
  }

  /// Note that we want a specific `TerrainBlock`.
  fn insert_placeholder(
    &mut self,
    id_allocator: &mut IdAllocator<EntityId>,
    physics: &mut Physics,
    block_position: &BlockPosition,
    owner: OwnerId,
  ) {
    match self.loaded.entry(*block_position) {
      Entry::Occupied(mut entry) => {
        let block_load_state = entry.get_mut();
        block_load_state.owners.insert(owner);
      },
      Entry::Vacant(entry) => {
        let mut owners = HashSet::new();
        owners.insert(owner);
        entry.set(BlockLoadState {
          owners: owners,
          loaded_lod: None,
        });
        assert!(self.in_progress_terrain.insert(id_allocator, physics, block_position));
      },
    }
  }

  fn remove_placeholder(
    &mut self,
    physics: &mut Physics,
    block_position: &BlockPosition,
    owner: OwnerId,
  ) {
    match self.loaded.entry(*block_position) {
      Entry::Occupied(mut entry) => {
        {
          let block_load_state = entry.get_mut();
          let should_unload =
            block_load_state.loaded_lod.is_none()
            && block_load_state.owners.remove(&owner)
            && block_load_state.owners.is_empty();
          if !should_unload {
            return;
          }
        }
        entry.take();
      },
      Entry::Vacant(_) => {
        return;
      },
    };

    assert!(self.in_progress_terrain.remove(physics, block_position));
  }
}
<|endoftext|>


<commit_before>extern crate cairo;

extern crate gstreamer as gst;
use gstreamer::{ElementExtManual, QueryView};

extern crate gtk;
use gtk::{Inhibit, WidgetExt};

#[cfg(feature = "profiling-audio-draw")]
use chrono::Utc;

use std::boxed::Box;

use std::rc::Rc;
use std::cell::RefCell;

use std::sync::{Arc, Mutex};

use ::media::{Context, SamplesExtractor};

use super::WaveformBuffer;

pub struct AudioController {
    container: gtk::Container,
    pub drawingarea: gtk::DrawingArea,

    audio_sink: Option<gst::Element>,
    position_query: gst::Query,

    is_active: bool,
    position: u64,
    samples_extractor_mtx: Arc<Mutex<Box<SamplesExtractor>>>,
}

impl AudioController {
    pub fn new(builder: &gtk::Builder) -> Rc<RefCell<Self>> {
        let this = Rc::new(RefCell::new(AudioController {
            container: builder.get_object("audio-container").unwrap(),
            drawingarea: builder.get_object("audio-drawingarea").unwrap(),

            audio_sink: None,
            position_query: gst::Query::new_position(gst::Format::Time),

            is_active: false,
            position: 0,
            samples_extractor_mtx: Arc::new(Mutex::new(Box::new(WaveformBuffer::new()))),
        }));

        {
            let this_ref = this.borrow();
            let this_rc = this.clone();
            this_ref.drawingarea.connect_draw(move |drawing_area, cairo_ctx| {
                this_rc.borrow_mut()
                    .draw(drawing_area, cairo_ctx).into()
            });
        }

        this
    }

    pub fn cleanup(&mut self) {
        self.is_active = false;
        // force redraw to purge the double buffer
        self.drawingarea.queue_draw();
    }

    pub fn new_media(&mut self, context: &Context) {
        let has_audio = context.info.lock()
                .expect("Failed to lock media info while initializing audio controller")
                .audio_best
                .is_some();

        if has_audio {
            self.audio_sink = context.get_audio_sink();

            self.is_active = true;
            self.position = 0;
            self.samples_extractor_mtx = context.samples_extractor_mtx.clone();

            self.container.show();
        } else {
            self.container.hide();
        }
    }

    fn draw(&mut self, drawing_area: &gtk::DrawingArea, cr: &cairo::Context) -> Inhibit {
        if !self.is_active {
            return Inhibit(false);
        }

        #[cfg(feature = "profiling-audio-draw")]
        let before_init = Utc::now();

        let allocation = drawing_area.get_allocation();
        if allocation.width.is_negative() {
            return Inhibit(false);
        }

        let requested_duration = 2_000_000_000u64; // 2s

        self.audio_sink.as_ref()
            .expect("No audio ref in AudioController::draw")
            .query(self.position_query.get_mut().unwrap());
        let position = match self.position_query.view() {
            QueryView::Position(ref position) => position.get().1 as u64,
            _ => unreachable!(),
        };

        #[cfg(feature = "profiling-audio-draw")]
        let before_lock = Utc::now();
        #[cfg(feature = "profiling-audio-draw")]
        let mut _before_cndt = Utc::now();
        #[cfg(feature = "profiling-audio-draw")]
        let mut _before_image = Utc::now();

        let current_x = {
            let waveform_buffer_grd = &mut *self.samples_extractor_mtx.lock()
                .expect("Couldn't lock waveform buffer in audio controller draw");
            let waveform_buffer = waveform_buffer_grd
                .as_mut_any().downcast_mut::<WaveformBuffer>()
                .expect("SamplesExtratctor is not a waveform buffer in audio controller draw");

            #[cfg(feature = "profiling-audio-draw")]
            let _before_cndt = Utc::now();

            waveform_buffer.update_conditions(
                    position,
                    requested_duration,
                    allocation.width,
                    allocation.height,
                );

            #[cfg(feature = "profiling-audio-draw")]
            let _before_image = Utc::now();

            let image = match waveform_buffer.image_surface.as_ref() {
                Some(image) => image,
                None => return Inhibit(false),
            };

            cr.set_source_surface(image, -(waveform_buffer.x_offset as f64), 0f64);
            cr.paint();

            waveform_buffer.current_x
        };

        #[cfg(feature = "profiling-audio-draw")]
        let before_pos = Utc::now();

        // draw current pos
        cr.scale(1f64, allocation.height as f64);
        cr.set_source_rgb(1f64, 1f64, 0f64);
        cr.set_line_width(1f64);
        let current_pos = current_x as f64;
        cr.move_to(current_pos, 0f64);
        cr.line_to(current_pos, 1f64);
        cr.stroke();

        #[cfg(feature = "profiling-audio-draw")]
        let end = Utc::now();

        #[cfg(feature = "profiling-audio-draw")]
        println!("audio-draw,{},{},{},{},{},{},{}",
            before_init.time().format("%H:%M:%S%.6f"),
            before_lock.time().format("%H:%M:%S%.6f"),
            _before_cndt.time().format("%H:%M:%S%.6f"),
            _before_image.time().format("%H:%M:%S%.6f"),
            before_pos.time().format("%H:%M:%S%.6f"),
            end.time().format("%H:%M:%S%.6f"),
            position,
        );

       Inhibit(true)
    }
}
<commit_msg>AudioController draw: get position as close as possible to rendering (#25)<commit_after>extern crate cairo;

extern crate gstreamer as gst;
use gstreamer::{ElementExtManual, QueryView};

extern crate gtk;
use gtk::{Inhibit, WidgetExt};

#[cfg(feature = "profiling-audio-draw")]
use chrono::Utc;

use std::boxed::Box;

use std::rc::Rc;
use std::cell::RefCell;

use std::sync::{Arc, Mutex};

use ::media::{Context, SamplesExtractor};

use super::WaveformBuffer;

pub struct AudioController {
    container: gtk::Container,
    pub drawingarea: gtk::DrawingArea,

    audio_sink: Option<gst::Element>,
    position_query: gst::Query,

    is_active: bool,
    position: u64,
    samples_extractor_mtx: Arc<Mutex<Box<SamplesExtractor>>>,
}

impl AudioController {
    pub fn new(builder: &gtk::Builder) -> Rc<RefCell<Self>> {
        let this = Rc::new(RefCell::new(AudioController {
            container: builder.get_object("audio-container").unwrap(),
            drawingarea: builder.get_object("audio-drawingarea").unwrap(),

            audio_sink: None,
            position_query: gst::Query::new_position(gst::Format::Time),

            is_active: false,
            position: 0,
            samples_extractor_mtx: Arc::new(Mutex::new(Box::new(WaveformBuffer::new()))),
        }));

        {
            let this_ref = this.borrow();
            let this_rc = this.clone();
            this_ref.drawingarea.connect_draw(move |drawing_area, cairo_ctx| {
                this_rc.borrow_mut()
                    .draw(drawing_area, cairo_ctx).into()
            });
        }

        this
    }

    pub fn cleanup(&mut self) {
        self.is_active = false;
        // force redraw to purge the double buffer
        self.drawingarea.queue_draw();
    }

    pub fn new_media(&mut self, context: &Context) {
        let has_audio = context.info.lock()
                .expect("Failed to lock media info while initializing audio controller")
                .audio_best
                .is_some();

        if has_audio {
            self.audio_sink = context.get_audio_sink();

            self.is_active = true;
            self.position = 0;
            self.samples_extractor_mtx = context.samples_extractor_mtx.clone();

            self.container.show();
        } else {
            self.container.hide();
        }
    }

    fn draw(&mut self, drawing_area: &gtk::DrawingArea, cr: &cairo::Context) -> Inhibit {
        if !self.is_active {
            return Inhibit(false);
        }

        #[cfg(feature = "profiling-audio-draw")]
        let before_init = Utc::now();

        let allocation = drawing_area.get_allocation();
        if allocation.width.is_negative() {
            return Inhibit(false);
        }

        let requested_duration = 2_000_000_000u64; // 2s

        let audio_sink = self.audio_sink.as_ref()
            .expect("No audio ref in AudioController::draw");

        #[allow(unused_assignments)]
        let mut position = 0;

        #[cfg(feature = "profiling-audio-draw")]
        let before_lock = Utc::now();
        #[cfg(feature = "profiling-audio-draw")]
        let mut _before_cndt = Utc::now();
        #[cfg(feature = "profiling-audio-draw")]
        let mut _before_image = Utc::now();

        let current_x = {
            let waveform_buffer_grd = &mut *self.samples_extractor_mtx.lock()
                .expect("Couldn't lock waveform buffer in audio controller draw");
            let waveform_buffer = waveform_buffer_grd
                .as_mut_any().downcast_mut::<WaveformBuffer>()
                .expect("SamplesExtratctor is not a waveform buffer in audio controller draw");

            #[cfg(feature = "profiling-audio-draw")]
            let _before_cndt = Utc::now();

            audio_sink.query(self.position_query.get_mut().unwrap());
            position = match self.position_query.view() {
                QueryView::Position(ref position) => position.get().1 as u64,
                _ => unreachable!(),
            };

            waveform_buffer.update_conditions(
                    position,
                    requested_duration,
                    allocation.width,
                    allocation.height,
                );

            #[cfg(feature = "profiling-audio-draw")]
            let _before_image = Utc::now();

            let image = match waveform_buffer.image_surface.as_ref() {
                Some(image) => image,
                None => return Inhibit(false),
            };

            cr.set_source_surface(image, -(waveform_buffer.x_offset as f64), 0f64);
            cr.paint();

            waveform_buffer.current_x
        };

        #[cfg(feature = "profiling-audio-draw")]
        let before_pos = Utc::now();

        // draw current pos
        cr.scale(1f64, allocation.height as f64);
        cr.set_source_rgb(1f64, 1f64, 0f64);
        cr.set_line_width(1f64);
        let current_pos = current_x as f64;
        cr.move_to(current_pos, 0f64);
        cr.line_to(current_pos, 1f64);
        cr.stroke();

        #[cfg(feature = "profiling-audio-draw")]
        let end = Utc::now();

        #[cfg(feature = "profiling-audio-draw")]
        println!("audio-draw,{},{},{},{},{},{},{}",
            before_init.time().format("%H:%M:%S%.6f"),
            before_lock.time().format("%H:%M:%S%.6f"),
            _before_cndt.time().format("%H:%M:%S%.6f"),
            _before_image.time().format("%H:%M:%S%.6f"),
            before_pos.time().format("%H:%M:%S%.6f"),
            end.time().format("%H:%M:%S%.6f"),
            position,
        );

       Inhibit(true)
    }
}
<|endoftext|>


<commit_before>use super::*;

#[test]
fn test_extract_gdb_version() {
    macro_rules! test { ($($expectation:tt: $input:tt,)*) => {{$(
        assert_eq!(extract_gdb_version($input), Some($expectation));
    )*}}}

    test! {
        7000001: "GNU gdb (GDB) CentOS (7.0.1-45.el5.centos)",

        7002000: "GNU gdb (GDB) Red Hat Enterprise Linux (7.2-90.el6)",

        7004000: "GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04",
        7004001: "GNU gdb (GDB) 7.4.1-debian",

        7006001: "GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-80.el7",

        7007001: "GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1",
        7007001: "GNU gdb (Debian 7.7.1+dfsg-5) 7.7.1",
        7007001: "GNU gdb (GDB) Fedora 7.7.1-21.fc20",

        7008000: "GNU gdb (GDB; openSUSE 13.2) 7.8",
        7009001: "GNU gdb (GDB) Fedora 7.9.1-20.fc22",
        7010001: "GNU gdb (GDB) Fedora 7.10.1-31.fc23",

        7011000: "GNU gdb (Ubuntu 7.11-0ubuntu1) 7.11",
        7011001: "GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1",
        7011001: "GNU gdb (Debian 7.11.1-2) 7.11.1",
        7011001: "GNU gdb (GDB) Fedora 7.11.1-86.fc24",
        7011001: "GNU gdb (GDB; openSUSE Leap 42.1) 7.11.1",
        7011001: "GNU gdb (GDB; openSUSE Tumbleweed) 7.11.1",

        7011090: "7.11.90",
        7011090: "GNU gdb (Ubuntu 7.11.90.20161005-0ubuntu1) 7.11.90.20161005-git",

        7012000: "7.12",
        7012000: "GNU gdb (GDB) 7.12",
        7012000: "GNU gdb (GDB) 7.12.20161027-git",
        7012050: "GNU gdb (GDB) 7.12.50.20161027-git",
    }
}

#[test]
fn is_test_test() {
    assert_eq!(true, is_test(&OsString::from("a_test.rs")));
    assert_eq!(false, is_test(&OsString::from(".a_test.rs")));
    assert_eq!(false, is_test(&OsString::from("a_cat.gif")));
    assert_eq!(false, is_test(&OsString::from("#a_dog_gif")));
    assert_eq!(false, is_test(&OsString::from("~a_temp_file")));
}
<commit_msg>Fix compiletest version-parsing tests<commit_after>use super::*;

#[test]
fn test_extract_gdb_version() {
    macro_rules! test { ($($expectation:tt: $input:tt,)*) => {{$(
        assert_eq!(extract_gdb_version($input), Some($expectation));
    )*}}}

    test! {
        7000001: "GNU gdb (GDB) CentOS 7.0.1-45.el5.centos",

        7002000: "GNU gdb (GDB) Red Hat Enterprise Linux 7.2-90.el6",

        7004000: "GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04",
        7004001: "GNU gdb (GDB) 7.4.1-debian",

        7006001: "GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-80.el7",

        7007001: "GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1",
        7007001: "GNU gdb (Debian 7.7.1+dfsg-5) 7.7.1",
        7007001: "GNU gdb (GDB) Fedora 7.7.1-21.fc20",

        7008000: "GNU gdb (GDB; openSUSE 13.2) 7.8",
        7009001: "GNU gdb (GDB) Fedora 7.9.1-20.fc22",
        7010001: "GNU gdb (GDB) Fedora 7.10.1-31.fc23",

        7011000: "GNU gdb (Ubuntu 7.11-0ubuntu1) 7.11",
        7011001: "GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1",
        7011001: "GNU gdb (Debian 7.11.1-2) 7.11.1",
        7011001: "GNU gdb (GDB) Fedora 7.11.1-86.fc24",
        7011001: "GNU gdb (GDB; openSUSE Leap 42.1) 7.11.1",
        7011001: "GNU gdb (GDB; openSUSE Tumbleweed) 7.11.1",

        7011090: "7.11.90",
        7011090: "GNU gdb (Ubuntu 7.11.90.20161005-0ubuntu1) 7.11.90.20161005-git",

        7012000: "7.12",
        7012000: "GNU gdb (GDB) 7.12",
        7012000: "GNU gdb (GDB) 7.12.20161027-git",
        7012050: "GNU gdb (GDB) 7.12.50.20161027-git",
    }
}

#[test]
fn is_test_test() {
    assert_eq!(true, is_test(&OsString::from("a_test.rs")));
    assert_eq!(false, is_test(&OsString::from(".a_test.rs")));
    assert_eq!(false, is_test(&OsString::from("a_cat.gif")));
    assert_eq!(false, is_test(&OsString::from("#a_dog_gif")));
    assert_eq!(false, is_test(&OsString::from("~a_temp_file")));
}
<|endoftext|>


<commit_before>// "Tifflin" Kernel
// - By John Hodge (thePowersGang)
//
// Core/device_manager.rs
// - Core device manager

use _common::*;
use sync::Mutex;
use lib::Queue;

module_define!{DeviceManager, [arch], init}

/// A semi-arbitatry integer denoting how well a driver handles a specific device
pub type DriverHandleLevel = u32;

/// IO range binding
pub enum IOBinding
{
	/// Memory-mapped IO space
	Memory(::memory::virt::AllocHandle),
	/// x86 IO bus (Base and offset)
	IO(u16,u16),
}

/// Interface a bus manager instance
pub trait BusManager:
	Send + Sync
{
	/// Returns the textual name of the bus type (e.g. "pci")
	fn bus_type(&self) -> &str;
	/// Returns a list of valid attributes for BusDevice::get_attr
	fn get_attr_names(&self) -> &[&str];
}

/// Interface to a device on a bus
pub trait BusDevice:
	Send
{
	/// Returns the device's address on the parent bus
	fn addr(&self) -> u32;
	/// Retrurns the specified attribute (or 0, if invalid)
	fn get_attr(&self, name: &str) -> u32;
	/// Set the power state of this device
	fn set_power(&mut self, state: bool);	// TODO: Power state enum for Off,Standby,Low,On
	/// Bind to the specified IO block (meaning of `block_id` depends on the bus)
	fn bind_io(&mut self, block_id: usize) -> IOBinding;
	/// Obtain the specified interrupt vector
	fn get_irq(&mut self, idx: usize) -> u32;
}

// TODO: Change this to instead be a structure with a bound Fn reference
// - Structure defines bus type and a set of attribute names/values/masks
/// Abstract driver for a device (creates instances when passed a device)
pub trait Driver:
	Send + Sync
{
	/// Driver's name
	fn name(&self) -> &str;
	/// Bus type the driver binds against (matches value from `BusManager::bus_type`)
	fn bus_type(&self) -> &str;
	/// Return the handling level of this driver for the specified device
	fn handles(&self, bus_dev: &BusDevice) -> DriverHandleLevel;
	/// Requests that the driver bind itself to the specified device
	fn bind(&self, bus_dev: &mut BusDevice) -> Box<DriverInstance>;
}

/// Driver instance (maps directly to a device)
pub trait DriverInstance:
	Send
{
}

/// Internal representation of a device on a bus
struct Device
{
	bus_dev: Box<BusDevice>,
	driver: Option<(Box<DriverInstance>, DriverHandleLevel)>,
	//attribs: Vec<u32>,
}

/// Internal representation of a bus
struct Bus
{
	manager: &'static BusManager,
	devices: Vec<Device>,
}

/// List of registered busses on the system
#[allow(non_upper_case_globals)]
static s_root_busses: Mutex<Queue<Bus>> = mutex_init!(queue_init!());

/// List of registered drivers
#[allow(non_upper_case_globals)]
static s_driver_list: Mutex<Queue<&'static Driver>> = mutex_init!( queue_init!() );

fn init()
{
	// Do nothing!
}

/// Register a bus with the device manager
///
/// Creates a new internal representation of the bus, containg the passed set of devices.
pub fn register_bus(manager: &'static BusManager, devices: Vec<Box<BusDevice>>)
{
	let bus = Bus {
		manager: manager,
		// For each device, locate a driver
		devices: devices.into_iter().map(|mut d| Device {
			driver: find_driver(manager, &mut *d),
			//attribs: Vec::new(),
			bus_dev: d,
			}).collect(),
		};
	s_root_busses.lock().push(bus);
}

/// Registers a driver with the device manger
pub fn register_driver(driver: &'static Driver)
{
	s_driver_list.lock().push(driver);
	log_debug!("Registering driver {}", driver.name());
	// Iterate known devices and spin up instances if needed
	for bus in s_root_busses.lock().iter_mut()
	{
		log_trace!("bus type {}", bus.manager.bus_type());
		for dev in bus.devices.iter_mut()
		{
			let rank = driver.handles(&*dev.bus_dev);
			log_debug!("rank = {:?}", rank);
			if rank == 0
			{
				// SKIP!
			}
			else if dev.driver.is_some()
			{
				let bind = dev.driver.as_ref().unwrap();
				let cur_rank = bind.1;
				if cur_rank > rank
				{
					// Existing driver is better
				}
				else if cur_rank == rank
				{
					// Fight!
				}
				else
				{
					// New driver is better
					panic!("TODO: Unbind driver and bind in new one");
				}
			}
			else
			{
				// Bind new driver
				dev.driver = Some( (driver.bind(&mut *dev.bus_dev), rank) );
			}
		}
	}
}

/**
 * Locate the best registered driver for this device and instanciate it
 */
fn find_driver(bus: &BusManager, bus_dev: &mut BusDevice) -> Option<(Box<DriverInstance>,DriverHandleLevel)>
{
	log_debug!("Finding driver for {}:{:x}", bus.bus_type(), bus_dev.addr());
	let mut best_ranking = 0;
	let mut best_driver = None;
	for driver in s_driver_list.lock().iter()
	{
		if bus.bus_type() == driver.bus_type()
		{
			let ranking = driver.handles(bus_dev);
			if ranking == 0
			{
				// Doesn't handle this device
			}
			else if ranking > best_ranking
			{
				// Best so far
				best_driver = Some( *driver );
				best_ranking = ranking;
			}
			else if ranking == best_ranking
			{
				// A tie, this is not very good
				//log_warning!("Tie for device {}:{:x} between {} and {}",
				//	bus.bus_type(), bus_dev.addr(), driver, best_driver.unwrap());
			}
			else
			{
				// Not as good as current, move along
			}
		}
	}
	best_driver.map(|d| (d.bind(bus_dev), best_ranking))
}

impl IOBinding
{
	/// Returns the x86 IO space base
	pub fn io_base(&self) -> u16 {
		match *self
		{
		IOBinding::IO(base, _size) => base,
		IOBinding::Memory(_) => panic!("Called IOBinding::io_base on IOBinding::Memory"),
		}
	}
	/// Writes a single u8 to the binding
	pub unsafe fn write_8(&self, ofs: usize, val: u8)
	{
		match *self
		{
		IOBinding::IO(base, s) => {
			assert!( ofs < s as usize );
			::arch::x86_io::outb(base + ofs as u16, val);
			},
		IOBinding::Memory(ref h) => {
			::core::intrinsics::volatile_store( h.as_int_mut::<u8>(ofs), val );
			//*h.as_mut::<u8>(ofs) = val;
			},
		}
	}
	/// Write a single u32 to the binding
	pub unsafe fn write_32(&self, ofs: usize, val: u32)
	{
		match *self
		{
		IOBinding::IO(base, s) => {
			assert!( ofs < s as usize );
			::arch::x86_io::outl(base + ofs as u16, val);
			},
		IOBinding::Memory(ref h) => {
			::core::intrinsics::volatile_store( h.as_int_mut::<u32>(ofs), val );
			//*h.as_mut::<u32>(ofs) = val;
			},
		}
	}
}

impl ::core::fmt::Debug for IOBinding
{
	fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
		match *self
		{
		IOBinding::IO(b, s) => write!(f, "IO({:#x}+{:#x})", b, s),
		IOBinding::Memory(ref h) => write!(f, "Memory({:?})", h),
		}
	}
}

// vim: ft=rust
<commit_msg>Kernel - Device manager support byte read<commit_after>// "Tifflin" Kernel
// - By John Hodge (thePowersGang)
//
// Core/device_manager.rs
// - Core device manager

use _common::*;
use sync::Mutex;
use lib::Queue;

module_define!{DeviceManager, [arch], init}

/// A semi-arbitatry integer denoting how well a driver handles a specific device
pub type DriverHandleLevel = u32;

/// IO range binding
pub enum IOBinding
{
	/// Memory-mapped IO space
	Memory(::memory::virt::AllocHandle),
	/// x86 IO bus (Base and offset)
	IO(u16,u16),
}

/// Interface a bus manager instance
pub trait BusManager:
	Send + Sync
{
	/// Returns the textual name of the bus type (e.g. "pci")
	fn bus_type(&self) -> &str;
	/// Returns a list of valid attributes for BusDevice::get_attr
	fn get_attr_names(&self) -> &[&str];
}

/// Interface to a device on a bus
pub trait BusDevice:
	Send
{
	/// Returns the device's address on the parent bus
	fn addr(&self) -> u32;
	/// Retrurns the specified attribute (or 0, if invalid)
	fn get_attr(&self, name: &str) -> u32;
	/// Set the power state of this device
	fn set_power(&mut self, state: bool);	// TODO: Power state enum for Off,Standby,Low,On
	/// Bind to the specified IO block (meaning of `block_id` depends on the bus)
	fn bind_io(&mut self, block_id: usize) -> IOBinding;
	/// Obtain the specified interrupt vector
	fn get_irq(&mut self, idx: usize) -> u32;
}

// TODO: Change this to instead be a structure with a bound Fn reference
// - Structure defines bus type and a set of attribute names/values/masks
/// Abstract driver for a device (creates instances when passed a device)
pub trait Driver:
	Send + Sync
{
	/// Driver's name
	fn name(&self) -> &str;
	/// Bus type the driver binds against (matches value from `BusManager::bus_type`)
	fn bus_type(&self) -> &str;
	/// Return the handling level of this driver for the specified device
	fn handles(&self, bus_dev: &BusDevice) -> DriverHandleLevel;
	/// Requests that the driver bind itself to the specified device
	fn bind(&self, bus_dev: &mut BusDevice) -> Box<DriverInstance>;
}

/// Driver instance (maps directly to a device)
pub trait DriverInstance:
	Send
{
}

/// Internal representation of a device on a bus
struct Device
{
	bus_dev: Box<BusDevice>,
	driver: Option<(Box<DriverInstance>, DriverHandleLevel)>,
	//attribs: Vec<u32>,
}

/// Internal representation of a bus
struct Bus
{
	manager: &'static BusManager,
	devices: Vec<Device>,
}

/// List of registered busses on the system
#[allow(non_upper_case_globals)]
static s_root_busses: Mutex<Queue<Bus>> = mutex_init!(queue_init!());

/// List of registered drivers
#[allow(non_upper_case_globals)]
static s_driver_list: Mutex<Queue<&'static Driver>> = mutex_init!( queue_init!() );

fn init()
{
	// Do nothing!
}

/// Register a bus with the device manager
///
/// Creates a new internal representation of the bus, containg the passed set of devices.
pub fn register_bus(manager: &'static BusManager, devices: Vec<Box<BusDevice>>)
{
	let bus = Bus {
		manager: manager,
		// For each device, locate a driver
		devices: devices.into_iter().map(|mut d| Device {
			driver: find_driver(manager, &mut *d),
			//attribs: Vec::new(),
			bus_dev: d,
			}).collect(),
		};
	s_root_busses.lock().push(bus);
}

/// Registers a driver with the device manger
pub fn register_driver(driver: &'static Driver)
{
	s_driver_list.lock().push(driver);
	log_debug!("Registering driver {}", driver.name());
	// Iterate known devices and spin up instances if needed
	for bus in s_root_busses.lock().iter_mut()
	{
		log_trace!("bus type {}", bus.manager.bus_type());
		for dev in bus.devices.iter_mut()
		{
			let rank = driver.handles(&*dev.bus_dev);
			log_debug!("rank = {:?}", rank);
			if rank == 0
			{
				// SKIP!
			}
			else if dev.driver.is_some()
			{
				let bind = dev.driver.as_ref().unwrap();
				let cur_rank = bind.1;
				if cur_rank > rank
				{
					// Existing driver is better
				}
				else if cur_rank == rank
				{
					// Fight!
				}
				else
				{
					// New driver is better
					panic!("TODO: Unbind driver and bind in new one");
				}
			}
			else
			{
				// Bind new driver
				dev.driver = Some( (driver.bind(&mut *dev.bus_dev), rank) );
			}
		}
	}
}

/**
 * Locate the best registered driver for this device and instanciate it
 */
fn find_driver(bus: &BusManager, bus_dev: &mut BusDevice) -> Option<(Box<DriverInstance>,DriverHandleLevel)>
{
	log_debug!("Finding driver for {}:{:x}", bus.bus_type(), bus_dev.addr());
	let mut best_ranking = 0;
	let mut best_driver = None;
	for driver in s_driver_list.lock().iter()
	{
		if bus.bus_type() == driver.bus_type()
		{
			let ranking = driver.handles(bus_dev);
			if ranking == 0
			{
				// Doesn't handle this device
			}
			else if ranking > best_ranking
			{
				// Best so far
				best_driver = Some( *driver );
				best_ranking = ranking;
			}
			else if ranking == best_ranking
			{
				// A tie, this is not very good
				//log_warning!("Tie for device {}:{:x} between {} and {}",
				//	bus.bus_type(), bus_dev.addr(), driver, best_driver.unwrap());
			}
			else
			{
				// Not as good as current, move along
			}
		}
	}
	best_driver.map(|d| (d.bind(bus_dev), best_ranking))
}

impl IOBinding
{
	/// Returns the x86 IO space base
	pub fn io_base(&self) -> u16 {
		match *self
		{
		IOBinding::IO(base, _size) => base,
		IOBinding::Memory(_) => panic!("Called IOBinding::io_base on IOBinding::Memory"),
		}
	}
	/// Read a single u8 from the binding
	pub unsafe fn read_8(&self, ofs: usize) -> u8
	{
		match *self
		{
		IOBinding::IO(base, s) => {
			assert!( ofs < s as usize );
			::arch::x86_io::inb(base + ofs as u16)
			},
		IOBinding::Memory(ref h) => {
			::core::intrinsics::volatile_load( h.as_int_mut::<u8>(ofs) )
			},
		}
	}
	/// Writes a single u8 to the binding
	pub unsafe fn write_8(&self, ofs: usize, val: u8)
	{
		match *self
		{
		IOBinding::IO(base, s) => {
			assert!( ofs < s as usize );
			::arch::x86_io::outb(base + ofs as u16, val);
			},
		IOBinding::Memory(ref h) => {
			::core::intrinsics::volatile_store( h.as_int_mut::<u8>(ofs), val );
			//*h.as_mut::<u8>(ofs) = val;
			},
		}
	}
	/// Write a single u32 to the binding
	pub unsafe fn write_32(&self, ofs: usize, val: u32)
	{
		match *self
		{
		IOBinding::IO(base, s) => {
			assert!( ofs < s as usize );
			::arch::x86_io::outl(base + ofs as u16, val);
			},
		IOBinding::Memory(ref h) => {
			::core::intrinsics::volatile_store( h.as_int_mut::<u32>(ofs), val );
			//*h.as_mut::<u32>(ofs) = val;
			},
		}
	}
}

impl ::core::fmt::Debug for IOBinding
{
	fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
		match *self
		{
		IOBinding::IO(b, s) => write!(f, "IO({:#x}+{:#x})", b, s),
		IOBinding::Memory(ref h) => write!(f, "Memory({:?})", h),
		}
	}
}

// vim: ft=rust
<|endoftext|>


<commit_before>// Copyright (c) 2019 Stefan Lankes, RWTH Aachen University
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.

#![allow(dead_code)]
#![allow(unused_imports)]

#[cfg(target_os = "hermit")]
extern crate hermit_sys;
extern crate rand;
extern crate rayon;

mod tests;

use tests::*;

fn test_result<T>(result: Result<(), T>) -> &'static str {
	match result {
		Ok(_) => "ok",
		Err(_) => "failed!",
	}
}

fn main() {
	println!("Test {} ... {}", stringify!(hello), test_result(hello()));
	println!(
		"Test {} ... {}",
		stringify!(print_argv),
		test_result(print_argv())
	);
	println!(
		"Test {} ... {}",
		stringify!(print_env),
		test_result(print_env())
	);
	println!(
		"Test {} ... {}",
		stringify!(read_file),
		test_result(read_file())
	);
	println!(
		"Test {} ... {}",
		stringify!(create_file),
		test_result(create_file())
	);
	println!(
		"Test {} ... {}",
		stringify!(threading),
		test_result(threading())
	);
	/*println!(
		"Test {} ... {}",
		stringify!(random_number),
		test_result(random_number())
	);*/
	println!(
		"Test {} ... {}",
		stringify!(pi_sequential),
		test_result(pi_sequential(5000000))
	);
	println!(
		"Test {} ... {}",
		stringify!(pi_parallel),
		test_result(pi_parallel(2, 5000000))
	);
	println!(
		"Test {} ... {}",
		stringify!(laplace),
		test_result(laplace(128, 128))
	);
	println!(
		"Test {} ... {}",
		stringify!(test_matmul_strassen),
		test_result(test_matmul_strassen())
	);
	println!(
		"Test {} ... {}",
		stringify!(thread_creation),
		test_result(thread_creation())
	);
	println!(
		"Test {} ... {}",
		stringify!(bench_sched_one_thread),
		test_result(bench_sched_one_thread())
	);
	println!(
		"Test {} ... {}",
		stringify!(bench_sched_two_threads),
		test_result(bench_sched_two_threads())
	);
	println!(
		"Test {} ... {}",
		stringify!(test_http_request),
		test_result(test_http_request())
	);
}
<commit_msg>disable temporary laplace test<commit_after>// Copyright (c) 2019 Stefan Lankes, RWTH Aachen University
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.

#![allow(dead_code)]
#![allow(unused_imports)]

#[cfg(target_os = "hermit")]
extern crate hermit_sys;
extern crate rand;
extern crate rayon;

mod tests;

use tests::*;

fn test_result<T>(result: Result<(), T>) -> &'static str {
	match result {
		Ok(_) => "ok",
		Err(_) => "failed!",
	}
}

fn main() {
	println!("Test {} ... {}", stringify!(hello), test_result(hello()));
	println!(
		"Test {} ... {}",
		stringify!(print_argv),
		test_result(print_argv())
	);
	println!(
		"Test {} ... {}",
		stringify!(print_env),
		test_result(print_env())
	);
	println!(
		"Test {} ... {}",
		stringify!(read_file),
		test_result(read_file())
	);
	println!(
		"Test {} ... {}",
		stringify!(create_file),
		test_result(create_file())
	);
	println!(
		"Test {} ... {}",
		stringify!(threading),
		test_result(threading())
	);
	/*println!(
		"Test {} ... {}",
		stringify!(random_number),
		test_result(random_number())
	);*/
	println!(
		"Test {} ... {}",
		stringify!(pi_sequential),
		test_result(pi_sequential(5000000))
	);
	println!(
		"Test {} ... {}",
		stringify!(pi_parallel),
		test_result(pi_parallel(2, 5000000))
	);
	/*println!(
		"Test {} ... {}",
		stringify!(laplace),
		test_result(laplace(128, 128))
	);*/
	println!(
		"Test {} ... {}",
		stringify!(test_matmul_strassen),
		test_result(test_matmul_strassen())
	);
	println!(
		"Test {} ... {}",
		stringify!(thread_creation),
		test_result(thread_creation())
	);
	println!(
		"Test {} ... {}",
		stringify!(bench_sched_one_thread),
		test_result(bench_sched_one_thread())
	);
	println!(
		"Test {} ... {}",
		stringify!(bench_sched_two_threads),
		test_result(bench_sched_two_threads())
	);
	println!(
		"Test {} ... {}",
		stringify!(test_http_request),
		test_result(test_http_request())
	);
}
<|endoftext|>


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

// Code to handle a collection of block devices.

use std::io;
use std::collections::{HashMap, HashSet};
use std::fs::{File, OpenOptions};
use std::path::{Path, PathBuf};
use std::str::FromStr;

use time::Timespec;
use uuid::Uuid;

use devicemapper::{Bytes, Device, Sectors, Segment};

use super::super::consts::IEC;
use super::super::errors::{EngineError, EngineResult, ErrorEnum};
use super::super::types::{DevUuid, PoolUuid};

use super::cleanup::wipe_blockdevs;
use super::blockdev::BlockDev;
use super::device::blkdev_size;
use super::engine::DevOwnership;
use super::metadata::{BDA, MIN_MDA_SECTORS, StaticHeader, validate_mda_size};
use super::range_alloc::RangeAllocator;
use super::serde_structs::{BlockDevSave, Recordable};

const MIN_DEV_SIZE: Bytes = Bytes(IEC::Gi);

/// Resolve a list of Paths of some sort to a set of unique Devices.
/// Return an IOError if there was a problem resolving any particular device.
pub fn resolve_devices(paths: &[&Path]) -> io::Result<HashSet<Device>> {
    paths
        .iter()
        .map(|p| Device::from_str(&p.to_string_lossy()))
        .collect()
}

#[derive(Debug)]
pub struct BlockDevMgr {
    block_devs: Vec<BlockDev>,
}

impl BlockDevMgr {
    pub fn new(block_devs: Vec<BlockDev>) -> BlockDevMgr {
        BlockDevMgr { block_devs: block_devs }
    }

    /// Initialize a new BlockDevMgr with specified pool and devices.
    pub fn initialize(pool_uuid: &PoolUuid,
                      paths: &[&Path],
                      mda_size: Sectors,
                      force: bool)
                      -> EngineResult<BlockDevMgr> {
        let devices = try!(resolve_devices(paths));
        Ok(BlockDevMgr::new(try!(initialize(pool_uuid, devices, mda_size, force))))
    }

    /// Obtain a BlockDev by its Device.
    pub fn get_by_device(&self, device: Device) -> Option<&BlockDev> {
        self.block_devs.iter().find(|d| d.device() == &device)
    }

    // Obtain a BlockDev by its UUID.
    pub fn get_by_uuid(&self, uuid: &DevUuid) -> Option<&BlockDev> {
        self.block_devs.iter().find(|d| d.uuid() == uuid)
    }

    pub fn add(&mut self,
               pool_uuid: &PoolUuid,
               paths: &[&Path],
               force: bool)
               -> EngineResult<Vec<PathBuf>> {
        let devices = try!(resolve_devices(paths));
        let bds = try!(initialize(pool_uuid, devices, MIN_MDA_SECTORS, force));
        let bdev_paths = bds.iter().map(|p| p.devnode.clone()).collect();
        for bd in bds {
            self.block_devs.push(bd);
        }
        Ok(bdev_paths)
    }

    pub fn destroy_all(self) -> EngineResult<()> {
        Ok(try!(wipe_blockdevs(self.block_devs)))
    }

    // Unused space left on blockdevs
    pub fn avail_space(&self) -> Sectors {
        self.block_devs.iter().map(|bd| bd.available()).sum()
    }

    /// If available space is less than size, return None, else return
    /// the segments allocated.
    pub fn alloc_space(&mut self, size: Sectors) -> Option<Vec<Segment>> {
        let mut needed: Sectors = size;
        let mut segs = Vec::new();

        if self.avail_space() < size {
            return None;
        }

        for mut bd in self.block_devs.iter_mut() {
            if needed == Sectors(0) {
                break;
            }

            let (gotten, r_segs) = bd.request_space(needed);
            segs.extend(r_segs);
            needed = needed - gotten;
        }

        assert_eq!(needed, Sectors(0));

        Some(segs)
    }

    pub fn devnodes(&self) -> Vec<PathBuf> {
        self.block_devs
            .iter()
            .map(|d| d.devnode.clone())
            .collect()
    }

    /// Write the given data to all blockdevs marking with specified time.
    /// Return an error if data was not written to any blockdev.
    // TODO: Cap # of blockdevs written to, as described in SWDD
    pub fn save_state(&mut self, time: &Timespec, metadata: &[u8]) -> EngineResult<()> {
        let mut saved = false;
        for mut bd in &mut self.block_devs {
            saved |= bd.save_state(time, metadata).is_ok();
        }
        if saved {
            Ok(())
        } else {
            let err_msg = "Failed to save metadata to even one device in pool";
            Err(EngineError::Engine(ErrorEnum::Error, err_msg.into()))
        }
    }
}

impl Recordable<HashMap<Uuid, BlockDevSave>> for BlockDevMgr {
    fn record(&self) -> EngineResult<HashMap<Uuid, BlockDevSave>> {
        self.block_devs
            .iter()
            .map(|bd| bd.record().and_then(|bdsave| Ok((*bd.uuid(), bdsave))))
            .collect()
    }
}

/// Initialize multiple blockdevs at once. This allows all of them
/// to be checked for usability before writing to any of them.
pub fn initialize(pool_uuid: &PoolUuid,
                  devices: HashSet<Device>,
                  mda_size: Sectors,
                  force: bool)
                  -> EngineResult<Vec<BlockDev>> {

    /// Get device information, returns an error if problem with obtaining
    /// that information.
    /// Returns a tuple with the device's path, its size in bytes,
    /// its ownership as determined by calling determine_ownership(),
    /// and an open File handle, all of which are needed later.
    pub fn dev_info(dev: &Device) -> EngineResult<(PathBuf, Bytes, DevOwnership, File)> {
        let devnode = try!(dev.devnode().ok_or_else(|| {
            EngineError::Engine(ErrorEnum::NotFound,
                                format!("could not get device node from dev {}", dev.dstr()))
        }));

        let mut f = try!(OpenOptions::new().read(true).write(true).open(&devnode));
        let dev_size = try!(blkdev_size(&f));
        let ownership = try!(StaticHeader::determine_ownership(&mut f));

        Ok((devnode, dev_size, ownership, f))
    }

    /// Filter devices for admission to pool based on dev_infos.
    /// If there is an error finding out the info, return that error.
    /// Also, return an error if a device is not appropriate for this pool.
    #[allow(type_complexity)]
    fn filter_devs<I>(dev_infos: I,
                      pool_uuid: &PoolUuid,
                      force: bool)
                      -> EngineResult<Vec<(Device, (PathBuf, Bytes, File))>>
        where I: Iterator<Item = (Device, EngineResult<(PathBuf, Bytes, DevOwnership, File)>)>
    {
        let mut add_devs = Vec::new();
        for (dev, dev_result) in dev_infos {
            let (devnode, dev_size, ownership, f) = try!(dev_result);
            if dev_size < MIN_DEV_SIZE {
                let error_message = format!("{} too small, minimum {} bytes",
                                            devnode.display(),
                                            MIN_DEV_SIZE);
                return Err(EngineError::Engine(ErrorEnum::Invalid, error_message));
            };
            match ownership {
                DevOwnership::Unowned => add_devs.push((dev, (devnode, dev_size, f))),
                DevOwnership::Theirs => {
                    if !force {
                        let err_str = format!("Device {} appears to belong to another application",
                                              devnode.display());
                        return Err(EngineError::Engine(ErrorEnum::Invalid, err_str));
                    } else {
                        add_devs.push((dev, (devnode, dev_size, f)))
                    }
                }
                DevOwnership::Ours(uuid) => {
                    if *pool_uuid != uuid {
                        let error_str = format!("Device {} already belongs to Stratis pool {}",
                                                devnode.display(),
                                                uuid);
                        return Err(EngineError::Engine(ErrorEnum::Invalid, error_str));
                    } else {
                        // Already in this pool (according to its header)
                        // TODO: Check we already know about it
                        // if yes, ignore. If no, add it w/o initializing?
                    }
                }
            }
        }
        Ok(add_devs)
    }

    try!(validate_mda_size(mda_size));

    let dev_infos = devices.into_iter().map(|d: Device| (d, dev_info(&d)));

    let add_devs = try!(filter_devs(dev_infos, pool_uuid, force));

    let mut bds: Vec<BlockDev> = Vec::new();
    for (dev, (devnode, dev_size, mut f)) in add_devs {

        let bda = BDA::initialize(&mut f,
                                  pool_uuid,
                                  &Uuid::new_v4(),
                                  mda_size,
                                  dev_size.sectors());
        if let Ok(bda) = bda {
            let allocator = RangeAllocator::new(bda.dev_size(), &[(Sectors(0), bda.size())])
                .expect("bda.size() < bda.dev_size() and single range");

            bds.push(BlockDev::new(dev, devnode, bda, allocator));
        } else {
            // TODO: check the return values and update state machine on failure
            let _ = BDA::wipe(&mut f);
            let _ = wipe_blockdevs(bds);

            return Err(bda.unwrap_err());
        }
    }
    Ok(bds)
}
<commit_msg>Use information about metadata size to prefilter blockdevs<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// Code to handle a collection of block devices.

use std::io;
use std::collections::{HashMap, HashSet};
use std::fs::{File, OpenOptions};
use std::path::{Path, PathBuf};
use std::str::FromStr;

use time::Timespec;
use uuid::Uuid;

use devicemapper::{Bytes, Device, Sectors, Segment};

use super::super::consts::IEC;
use super::super::errors::{EngineError, EngineResult, ErrorEnum};
use super::super::types::{DevUuid, PoolUuid};

use super::cleanup::wipe_blockdevs;
use super::blockdev::BlockDev;
use super::device::blkdev_size;
use super::engine::DevOwnership;
use super::metadata::{BDA, MIN_MDA_SECTORS, StaticHeader, validate_mda_size};
use super::range_alloc::RangeAllocator;
use super::serde_structs::{BlockDevSave, Recordable};

const MIN_DEV_SIZE: Bytes = Bytes(IEC::Gi);

/// Resolve a list of Paths of some sort to a set of unique Devices.
/// Return an IOError if there was a problem resolving any particular device.
pub fn resolve_devices(paths: &[&Path]) -> io::Result<HashSet<Device>> {
    paths
        .iter()
        .map(|p| Device::from_str(&p.to_string_lossy()))
        .collect()
}

#[derive(Debug)]
pub struct BlockDevMgr {
    block_devs: Vec<BlockDev>,
}

impl BlockDevMgr {
    pub fn new(block_devs: Vec<BlockDev>) -> BlockDevMgr {
        BlockDevMgr { block_devs: block_devs }
    }

    /// Initialize a new BlockDevMgr with specified pool and devices.
    pub fn initialize(pool_uuid: &PoolUuid,
                      paths: &[&Path],
                      mda_size: Sectors,
                      force: bool)
                      -> EngineResult<BlockDevMgr> {
        let devices = try!(resolve_devices(paths));
        Ok(BlockDevMgr::new(try!(initialize(pool_uuid, devices, mda_size, force))))
    }

    /// Obtain a BlockDev by its Device.
    pub fn get_by_device(&self, device: Device) -> Option<&BlockDev> {
        self.block_devs.iter().find(|d| d.device() == &device)
    }

    // Obtain a BlockDev by its UUID.
    pub fn get_by_uuid(&self, uuid: &DevUuid) -> Option<&BlockDev> {
        self.block_devs.iter().find(|d| d.uuid() == uuid)
    }

    pub fn add(&mut self,
               pool_uuid: &PoolUuid,
               paths: &[&Path],
               force: bool)
               -> EngineResult<Vec<PathBuf>> {
        let devices = try!(resolve_devices(paths));
        let bds = try!(initialize(pool_uuid, devices, MIN_MDA_SECTORS, force));
        let bdev_paths = bds.iter().map(|p| p.devnode.clone()).collect();
        for bd in bds {
            self.block_devs.push(bd);
        }
        Ok(bdev_paths)
    }

    pub fn destroy_all(self) -> EngineResult<()> {
        Ok(try!(wipe_blockdevs(self.block_devs)))
    }

    // Unused space left on blockdevs
    pub fn avail_space(&self) -> Sectors {
        self.block_devs.iter().map(|bd| bd.available()).sum()
    }

    /// If available space is less than size, return None, else return
    /// the segments allocated.
    pub fn alloc_space(&mut self, size: Sectors) -> Option<Vec<Segment>> {
        let mut needed: Sectors = size;
        let mut segs = Vec::new();

        if self.avail_space() < size {
            return None;
        }

        for mut bd in self.block_devs.iter_mut() {
            if needed == Sectors(0) {
                break;
            }

            let (gotten, r_segs) = bd.request_space(needed);
            segs.extend(r_segs);
            needed = needed - gotten;
        }

        assert_eq!(needed, Sectors(0));

        Some(segs)
    }

    pub fn devnodes(&self) -> Vec<PathBuf> {
        self.block_devs
            .iter()
            .map(|d| d.devnode.clone())
            .collect()
    }

    /// Write the given data to all blockdevs marking with specified time.
    /// Return an error if data was not written to any blockdev.
    /// Omit blockdevs which do not have sufficient space in BDA to accommodate
    /// metadata.
    // TODO: Cap # of blockdevs written to, as described in SWDD
    pub fn save_state(&mut self, time: &Timespec, metadata: &[u8]) -> EngineResult<()> {
        let data_size = Bytes(metadata.len() as u64).sectors();

        let saved = self.block_devs
            .iter_mut()
            .filter(|b| b.max_metadata_size() >= data_size)
            .fold(false,
                  |acc, mut b| acc | b.save_state(time, metadata).is_ok());

        if saved {
            Ok(())
        } else {
            let err_msg = "Failed to save metadata to even one device in pool";
            Err(EngineError::Engine(ErrorEnum::Error, err_msg.into()))
        }
    }
}

impl Recordable<HashMap<Uuid, BlockDevSave>> for BlockDevMgr {
    fn record(&self) -> EngineResult<HashMap<Uuid, BlockDevSave>> {
        self.block_devs
            .iter()
            .map(|bd| bd.record().and_then(|bdsave| Ok((*bd.uuid(), bdsave))))
            .collect()
    }
}

/// Initialize multiple blockdevs at once. This allows all of them
/// to be checked for usability before writing to any of them.
pub fn initialize(pool_uuid: &PoolUuid,
                  devices: HashSet<Device>,
                  mda_size: Sectors,
                  force: bool)
                  -> EngineResult<Vec<BlockDev>> {

    /// Get device information, returns an error if problem with obtaining
    /// that information.
    /// Returns a tuple with the device's path, its size in bytes,
    /// its ownership as determined by calling determine_ownership(),
    /// and an open File handle, all of which are needed later.
    pub fn dev_info(dev: &Device) -> EngineResult<(PathBuf, Bytes, DevOwnership, File)> {
        let devnode = try!(dev.devnode().ok_or_else(|| {
            EngineError::Engine(ErrorEnum::NotFound,
                                format!("could not get device node from dev {}", dev.dstr()))
        }));

        let mut f = try!(OpenOptions::new().read(true).write(true).open(&devnode));
        let dev_size = try!(blkdev_size(&f));
        let ownership = try!(StaticHeader::determine_ownership(&mut f));

        Ok((devnode, dev_size, ownership, f))
    }

    /// Filter devices for admission to pool based on dev_infos.
    /// If there is an error finding out the info, return that error.
    /// Also, return an error if a device is not appropriate for this pool.
    #[allow(type_complexity)]
    fn filter_devs<I>(dev_infos: I,
                      pool_uuid: &PoolUuid,
                      force: bool)
                      -> EngineResult<Vec<(Device, (PathBuf, Bytes, File))>>
        where I: Iterator<Item = (Device, EngineResult<(PathBuf, Bytes, DevOwnership, File)>)>
    {
        let mut add_devs = Vec::new();
        for (dev, dev_result) in dev_infos {
            let (devnode, dev_size, ownership, f) = try!(dev_result);
            if dev_size < MIN_DEV_SIZE {
                let error_message = format!("{} too small, minimum {} bytes",
                                            devnode.display(),
                                            MIN_DEV_SIZE);
                return Err(EngineError::Engine(ErrorEnum::Invalid, error_message));
            };
            match ownership {
                DevOwnership::Unowned => add_devs.push((dev, (devnode, dev_size, f))),
                DevOwnership::Theirs => {
                    if !force {
                        let err_str = format!("Device {} appears to belong to another application",
                                              devnode.display());
                        return Err(EngineError::Engine(ErrorEnum::Invalid, err_str));
                    } else {
                        add_devs.push((dev, (devnode, dev_size, f)))
                    }
                }
                DevOwnership::Ours(uuid) => {
                    if *pool_uuid != uuid {
                        let error_str = format!("Device {} already belongs to Stratis pool {}",
                                                devnode.display(),
                                                uuid);
                        return Err(EngineError::Engine(ErrorEnum::Invalid, error_str));
                    } else {
                        // Already in this pool (according to its header)
                        // TODO: Check we already know about it
                        // if yes, ignore. If no, add it w/o initializing?
                    }
                }
            }
        }
        Ok(add_devs)
    }

    try!(validate_mda_size(mda_size));

    let dev_infos = devices.into_iter().map(|d: Device| (d, dev_info(&d)));

    let add_devs = try!(filter_devs(dev_infos, pool_uuid, force));

    let mut bds: Vec<BlockDev> = Vec::new();
    for (dev, (devnode, dev_size, mut f)) in add_devs {

        let bda = BDA::initialize(&mut f,
                                  pool_uuid,
                                  &Uuid::new_v4(),
                                  mda_size,
                                  dev_size.sectors());
        if let Ok(bda) = bda {
            let allocator = RangeAllocator::new(bda.dev_size(), &[(Sectors(0), bda.size())])
                .expect("bda.size() < bda.dev_size() and single range");

            bds.push(BlockDev::new(dev, devnode, bda, allocator));
        } else {
            // TODO: check the return values and update state machine on failure
            let _ = BDA::wipe(&mut f);
            let _ = wipe_blockdevs(bds);

            return Err(bda.unwrap_err());
        }
    }
    Ok(bds)
}
<|endoftext|>


<commit_before>//! An immutable, owned value.
//!
//! The purpose of `Frozen` is to make a value immutable for the sake of defensive programming. For example,
//! suppose we have the following:
//!
//! ```rust
//! struct Bar { /* some data */ }
//!
//! struct Foo {
//!     /// Some computed data that should never change after construction.
//!     pub computed: Bar,
//!
//!     /* some other fields */
//! }
//!
//! impl Bar {
//!     /// Mutate the `Bar`.
//!     pub fn mutate(&mut self) { }
//! }
//! ```
//!
//! Now suppose we want to pass around a mutable `Foo` instance but, we want to make sure that
//! `computed` does not change accidentally (e.g. somebody might accidentally call
//! `foo.computed.mutate()`). This is what `Frozen` is for. We can do the following:
//!
//! ```rust
//! use rustc_data_structures::frozen::Frozen;
//!
//! struct Foo {
//!     /// Some computed data that should never change after construction.
//!     pub computed: Frozen<Bar>,
//!
//!     /* some other fields */
//! }
//! ```
//!
//! `Frozen` impls `Deref`, so we can ergonomically call methods on `Bar`, but it doesn't `impl
//! DerefMut`.  Now calling `foo.compute.mutate()` will result in a compile-time error stating that
//! `mutate` requires a mutable reference but we don't have one.

/// An owned immutable value.
#[derive(Debug)]
pub struct Frozen<T>(T);

impl<T> Frozen<T> {
    pub fn freeze(val: T) -> Self {
        Frozen(val)
    }
}

impl<T> std::ops::Deref for Frozen<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.0
    }
}
<commit_msg>update rustdocs for frozen<commit_after>//! An immutable, owned value (except for interior mutability).
//!
//! The purpose of `Frozen` is to make a value immutable for the sake of defensive programming. For example,
//! suppose we have the following:
//!
//! ```rust
//! struct Bar { /* some data */ }
//!
//! struct Foo {
//!     /// Some computed data that should never change after construction.
//!     pub computed: Bar,
//!
//!     /* some other fields */
//! }
//!
//! impl Bar {
//!     /// Mutate the `Bar`.
//!     pub fn mutate(&mut self) { }
//! }
//! ```
//!
//! Now suppose we want to pass around a mutable `Foo` instance but, we want to make sure that
//! `computed` does not change accidentally (e.g. somebody might accidentally call
//! `foo.computed.mutate()`). This is what `Frozen` is for. We can do the following:
//!
//! ```rust
//! use rustc_data_structures::frozen::Frozen;
//!
//! struct Foo {
//!     /// Some computed data that should never change after construction.
//!     pub computed: Frozen<Bar>,
//!
//!     /* some other fields */
//! }
//! ```
//!
//! `Frozen` impls `Deref`, so we can ergonomically call methods on `Bar`, but it doesn't `impl
//! DerefMut`.  Now calling `foo.compute.mutate()` will result in a compile-time error stating that
//! `mutate` requires a mutable reference but we don't have one.
//!
//! # Caveats
//!
//! - `Frozen` doesn't try to defend against interior mutability (e.g. `Frozen<RefCell<Bar>>`).
//! - `Frozen` doesn't pin it's contents (e.g. one could still do `foo.computed =
//!    Frozen::freeze(new_bar)`).

/// An owned immutable value.
#[derive(Debug)]
pub struct Frozen<T>(T);

impl<T> Frozen<T> {
    pub fn freeze(val: T) -> Self {
        Frozen(val)
    }
}

impl<T> std::ops::Deref for Frozen<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.0
    }
}
<|endoftext|>