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

use quote::Tokens;
use syn::{Attribute, Body, Ident, MacroInput, Path, VariantData};
use syn::Body::{Enum, Struct};
use syn::MetaItem::Word;
use syn::Ty;

use string::{snake_to_camel, to_dash_name};

/// Expand the required trais for the derive Setting attribute.
pub fn expand_setting_enum(mut ast: MacroInput) -> Tokens {
    let name = ast.ident.clone();
    let mut default = None;

    let mut variant_names = vec![];
    if let Enum(ref mut variants) = ast.body {
        for variant in variants {
            variant_names.push(variant.ident.clone());
            if !variant.attrs.is_empty() {
                for attribute in &variant.attrs {
                    if let &Attribute { value: Word(ref ident), .. } = attribute {
                        if ident == "default" {
                            default = Some(variant.ident.clone());
                        }
                    }
                }
                variant.attrs.clear();
            }
        }
    }
    let choice_names: Vec<_> = variant_names.iter()
        .map(|name| to_dash_name(&name.to_string()))
        .collect();
    let choice_names1 = &choice_names;
    let choice_names2 = &choice_names;

    let from_str_fn = quote! {
        fn from_str(string: &str) -> Result<Self, Self::Err> {
            match string {
                #(#choice_names1 => Ok(#variant_names),)*
                _ => Err(::mg_settings::error::SettingError::UnknownChoice {
                    actual: string.to_string(),
                    expected: vec![#(#choice_names2),*],
                }),
            }
        }
    };

    let default_impl =
        if let Some(ident) = default {
            quote! {
                impl Default for #name {
                    fn default() -> Self {
                        #ident
                    }
                }
            }
        }
        else {
            quote! {
            }
        };

    quote! {
        #[derive(Clone)]
        #ast

        #default_impl

        impl ::std::str::FromStr for #name {
            type Err = ::mg_settings::error::SettingError;

            #from_str_fn
        }
    }
}

/// Expand the required traits for the derive Settings attribute.
pub fn expand_settings_enum(ast: MacroInput) -> Tokens {
    let name = ast.ident.clone();
    let variant_name = Ident::new(format!("{}Variant", name));
    let variant_enum = to_enums(&ast.ident, &variant_name, &ast.body);
    let settings_impl = to_settings_impl(&name, &variant_name, &ast.body);
    quote! {
        #[derive(Default)]
        #ast

        #variant_enum

        #settings_impl
    }
}

/// Check if a type is a custom type (including enum).
fn is_custom_type(ident: &Ident) -> bool {
    match ident.to_string().as_ref() {
        "bool" | "f64" | "i64" | "String" => false,
        _ => true,
    }
}

/// Create the variant enums for getters and setters.
fn to_enums(name: &Ident, variant_name: &Ident, settings_struct: &Body) -> Tokens {
    if let &Struct(VariantData::Struct(ref strct)) = settings_struct {
        let mut field_names = vec![];
        let mut names = vec![];
        let mut types = vec![];
        for field in strct {
            if let Some(ref ident) = field.ident {
                field_names.push(ident);
                let ident = Ident::new(snake_to_camel(&ident.to_string()));
                names.push(ident);
                types.push(field.ty.clone());
            }
        }
        let names1 = &names;
        quote! {
            #[derive(Clone)]
            pub enum #variant_name {
                #(#names1(#types)),*
            }

            impl #name {
                pub fn new() -> #name {
                    #name::default()
                }
            }
        }
    }
    else {
        panic!("Not a struct");
    }
}

/// Create the impl Settings.
fn to_settings_impl(name: &Ident, variant_name: &Ident, settings_struct: &Body) -> Tokens {
    if let &Struct(VariantData::Struct(ref strct)) = settings_struct {
        let mut names = vec![];
        let mut capitalized_names = vec![];
        let mut original_types = vec![];
        let mut types = vec![];
        for field in strct {
            if let Some(ref ident) = field.ident {
                let ident_string = ident.to_string();
                let ident = Ident::new(ident_string.clone());
                names.push(ident);
                let ident = Ident::new(snake_to_camel(&ident_string));
                capitalized_names.push(
                    quote! {
                        #variant_name::#ident
                    });

                if let Ty::Path(_, Path { ref segments, .. }) = field.ty {
                    original_types.push(&segments[0].ident);
                    types.push(to_value_type(&segments[0].ident));
                }
            }
        }
        let string_names: Vec<_> = names.iter()
            .map(|ident| ident.to_string().replace("_", "-"))
            .collect();
        let string_names = &string_names;
        let capitalized_names = &capitalized_names;
        let names1 = &names;
        let variant_exprs = names.iter().zip(original_types.iter())
            .map(|(name, typ)|
                 if is_custom_type(typ) {
                     quote! {
                         ::std::str::FromStr::from_str(&#name)?
                     }
                 }
                 else {
                     quote! { #name }
                 }
            );
        let names2 = &names;
        let names3 = &names;
        let types1 = &types;
        let type_names = types.iter()
            .map(|ident| value_type_to_type(&ident));

        let to_variant_fn_variant = quote! {
            #(#string_names => {
                if let ::mg_settings::Value::#types1(#names1) = value {
                    Ok(#capitalized_names(#variant_exprs))
                }
                else {
                    Err(::mg_settings::error::SettingError::WrongType {
                        actual: value.to_type().to_string(),
                        expected: #type_names.to_string(),
                    })
                }
            },)*
        };

        let to_variant_fn = quote! {
            fn to_variant(name: &str, value: ::mg_settings::Value) -> Result<Self::Variant, ::mg_settings::error::SettingError> {
                match name {
                    #to_variant_fn_variant
                    _ => Err(::mg_settings::error::SettingError::UnknownSetting(name.to_string())),
                }
            }
        };

        quote! {
            impl ::mg_settings::settings::Settings for #name {
                type Variant = #variant_name;

                #to_variant_fn

                fn set_value(&mut self, value: Self::Variant) {
                    match value {
                        #(#capitalized_names(#names1) => {
                            self.#names2 = #names3
                        }),*
                    }
                }
            }
        }
    }
    else {
        panic!("Not a struct");
    }
}

/// Convert a Rust type to a `Value` type.
fn to_value_type(ident: &Ident) -> Ident {
    let value_type =
        match ident.to_string().as_ref() {
            "bool" => "Bool",
            "f64" => "Float",
            "i64" => "Int",
            _ => "Str",
        };
    Ident::new(value_type)
}

/// Convert a `Value` type to a string representation of the type.
fn value_type_to_type(ident: &Ident) -> &str {
    match ident.to_string().as_ref() {
        "Bool" => "bool",
        "Float" => "float",
        "Int" => "integer",
        "Str" => "string",
        ty => panic!("Unknown Value type {}", ty),
    }
}
<commit_msg>Fixed to use qualified names.<commit_after>/*
 * Copyright (c) 2016 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

use quote::Tokens;
use syn::{Attribute, Body, Ident, MacroInput, Path, VariantData};
use syn::Body::{Enum, Struct};
use syn::MetaItem::Word;
use syn::Ty;

use string::{snake_to_camel, to_dash_name};

/// Expand the required trais for the derive Setting attribute.
pub fn expand_setting_enum(mut ast: MacroInput) -> Tokens {
    let name = ast.ident.clone();
    let mut default = None;

    let mut variant_names = vec![];
    if let Enum(ref mut variants) = ast.body {
        for variant in variants {
            variant_names.push(variant.ident.clone());
            if !variant.attrs.is_empty() {
                for attribute in &variant.attrs {
                    if let &Attribute { value: Word(ref ident), .. } = attribute {
                        if ident == "default" {
                            default = Some(variant.ident.clone());
                        }
                    }
                }
                variant.attrs.clear();
            }
        }
    }
    let choice_names: Vec<_> = variant_names.iter()
        .map(|name| to_dash_name(&name.to_string()))
        .collect();
    let choice_names1 = &choice_names;
    let choice_names2 = &choice_names;

    let qualified_names = variant_names.iter()
        .map(|variant_name| quote! {
            #name::#variant_name
        });

    let from_str_fn = quote! {
        fn from_str(string: &str) -> Result<Self, Self::Err> {
            match string {
                #(#choice_names1 => Ok(#qualified_names),)*
                _ => Err(::mg_settings::error::SettingError::UnknownChoice {
                    actual: string.to_string(),
                    expected: vec![#(#choice_names2),*],
                }),
            }
        }
    };

    let default_impl =
        if let Some(ident) = default {
            quote! {
                impl Default for #name {
                    fn default() -> Self {
                        #ident
                    }
                }
            }
        }
        else {
            quote! {
            }
        };

    quote! {
        #[derive(Clone)]
        #ast

        #default_impl

        impl ::std::str::FromStr for #name {
            type Err = ::mg_settings::error::SettingError;

            #from_str_fn
        }
    }
}

/// Expand the required traits for the derive Settings attribute.
pub fn expand_settings_enum(ast: MacroInput) -> Tokens {
    let name = ast.ident.clone();
    let variant_name = Ident::new(format!("{}Variant", name));
    let variant_enum = to_enums(&ast.ident, &variant_name, &ast.body);
    let settings_impl = to_settings_impl(&name, &variant_name, &ast.body);
    quote! {
        #[derive(Default)]
        #ast

        #variant_enum

        #settings_impl
    }
}

/// Check if a type is a custom type (including enum).
fn is_custom_type(ident: &Ident) -> bool {
    match ident.to_string().as_ref() {
        "bool" | "f64" | "i64" | "String" => false,
        _ => true,
    }
}

/// Create the variant enums for getters and setters.
fn to_enums(name: &Ident, variant_name: &Ident, settings_struct: &Body) -> Tokens {
    if let &Struct(VariantData::Struct(ref strct)) = settings_struct {
        let mut field_names = vec![];
        let mut names = vec![];
        let mut types = vec![];
        for field in strct {
            if let Some(ref ident) = field.ident {
                field_names.push(ident);
                let ident = Ident::new(snake_to_camel(&ident.to_string()));
                names.push(ident);
                types.push(field.ty.clone());
            }
        }
        let names1 = &names;
        quote! {
            #[derive(Clone)]
            pub enum #variant_name {
                #(#names1(#types)),*
            }

            impl #name {
                pub fn new() -> #name {
                    #name::default()
                }
            }
        }
    }
    else {
        panic!("Not a struct");
    }
}

/// Create the impl Settings.
fn to_settings_impl(name: &Ident, variant_name: &Ident, settings_struct: &Body) -> Tokens {
    if let &Struct(VariantData::Struct(ref strct)) = settings_struct {
        let mut names = vec![];
        let mut capitalized_names = vec![];
        let mut original_types = vec![];
        let mut types = vec![];
        for field in strct {
            if let Some(ref ident) = field.ident {
                let ident_string = ident.to_string();
                let ident = Ident::new(ident_string.clone());
                names.push(ident);
                let ident = Ident::new(snake_to_camel(&ident_string));
                capitalized_names.push(
                    quote! {
                        #variant_name::#ident
                    });

                if let Ty::Path(_, Path { ref segments, .. }) = field.ty {
                    original_types.push(&segments[0].ident);
                    types.push(to_value_type(&segments[0].ident));
                }
            }
        }
        let string_names: Vec<_> = names.iter()
            .map(|ident| ident.to_string().replace("_", "-"))
            .collect();
        let string_names = &string_names;
        let capitalized_names = &capitalized_names;
        let names1 = &names;
        let variant_exprs = names.iter().zip(original_types.iter())
            .map(|(name, typ)|
                 if is_custom_type(typ) {
                     quote! {
                         ::std::str::FromStr::from_str(&#name)?
                     }
                 }
                 else {
                     quote! { #name }
                 }
            );
        let names2 = &names;
        let names3 = &names;
        let types1 = &types;
        let type_names = types.iter()
            .map(|ident| value_type_to_type(&ident));

        let to_variant_fn_variant = quote! {
            #(#string_names => {
                if let ::mg_settings::Value::#types1(#names1) = value {
                    Ok(#capitalized_names(#variant_exprs))
                }
                else {
                    Err(::mg_settings::error::SettingError::WrongType {
                        actual: value.to_type().to_string(),
                        expected: #type_names.to_string(),
                    })
                }
            },)*
        };

        let to_variant_fn = quote! {
            fn to_variant(name: &str, value: ::mg_settings::Value) -> Result<Self::Variant, ::mg_settings::error::SettingError> {
                match name {
                    #to_variant_fn_variant
                    _ => Err(::mg_settings::error::SettingError::UnknownSetting(name.to_string())),
                }
            }
        };

        quote! {
            impl ::mg_settings::settings::Settings for #name {
                type Variant = #variant_name;

                #to_variant_fn

                fn set_value(&mut self, value: Self::Variant) {
                    match value {
                        #(#capitalized_names(#names1) => {
                            self.#names2 = #names3
                        }),*
                    }
                }
            }
        }
    }
    else {
        panic!("Not a struct");
    }
}

/// Convert a Rust type to a `Value` type.
fn to_value_type(ident: &Ident) -> Ident {
    let value_type =
        match ident.to_string().as_ref() {
            "bool" => "Bool",
            "f64" => "Float",
            "i64" => "Int",
            _ => "Str",
        };
    Ident::new(value_type)
}

/// Convert a `Value` type to a string representation of the type.
fn value_type_to_type(ident: &Ident) -> &str {
    match ident.to_string().as_ref() {
        "Bool" => "bool",
        "Float" => "float",
        "Int" => "integer",
        "Str" => "string",
        ty => panic!("Unknown Value type {}", ty),
    }
}
<|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::collections::HashMap;
use std::fs::{File, OpenOptions};
use std::path::{Path, PathBuf};

use chrono::{DateTime, Duration, Utc};
use rand::{thread_rng, sample};
use uuid::Uuid;

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

use super::super::engine::BlockDev;
use super::super::errors::{EngineError, EngineResult, ErrorEnum};
use super::super::types::{DevUuid, PoolUuid};

use super::cleanup::wipe_blockdevs;
use super::blockdev::StratBlockDev;
use super::device::{blkdev_size, resolve_devices};
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);
const MAX_NUM_TO_WRITE: usize = 10;

#[derive(Debug)]
pub struct BlkDevSegment {
    pub uuid: DevUuid,
    pub segment: Segment,
}

impl BlkDevSegment {
    pub fn new(uuid: DevUuid, segment: Segment) -> BlkDevSegment {
        BlkDevSegment { uuid, segment }
    }

    pub fn to_segment(&self) -> Segment {
        self.segment.clone()
    }
}

impl Recordable<Vec<(Uuid, Sectors, Sectors)>> for Vec<BlkDevSegment> {
    fn record(&self) -> Vec<(Uuid, Sectors, Sectors)> {
        self.iter()
            .map(|bseg| (bseg.uuid, bseg.segment.start, bseg.segment.length))
            .collect::<Vec<_>>()
    }
}

/// Build a Vec<Segment> from BlkDevSegments. This is useful for calls
/// to the devicemapper library.
pub fn map_to_dm(bsegs: &[BlkDevSegment]) -> Vec<Segment> {
    bsegs
        .into_iter()
        .map(|bseg| bseg.to_segment())
        .collect::<Vec<_>>()
}

#[derive(Debug)]
pub struct BlockDevMgr {
    pool_uuid: PoolUuid,
    block_devs: Vec<StratBlockDev>,
    last_update_time: Option<DateTime<Utc>>,
}

impl BlockDevMgr {
    pub fn new(pool_uuid: PoolUuid, block_devs: Vec<StratBlockDev>) -> BlockDevMgr {
        BlockDevMgr {
            pool_uuid: pool_uuid,
            block_devs: block_devs,
            last_update_time: None,
        }
    }

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

    /// Get a function that maps UUIDs to Devices.
    pub fn uuid_to_devno(&self) -> Box<Fn(DevUuid) -> Option<Device>> {
        let uuid_map: HashMap<DevUuid, Device> = self.block_devs
            .iter()
            .map(|bd| (bd.uuid(), *bd.device()))
            .collect();

        Box::new(move |uuid: DevUuid| -> Option<Device> { uuid_map.get(&uuid).cloned() })
    }

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

    pub fn destroy_all(self) -> EngineResult<()> {
        wipe_blockdevs(&self.block_devs)
    }

    /// Allocate space according to sizes vector request.
    /// Return the segments allocated for each request, or None if it was
    /// not possible to satisfy the request.
    /// This method is atomic, it either allocates all requested or allocates
    /// nothing.
    pub fn alloc_space(&mut self, sizes: &[Sectors]) -> Option<Vec<Vec<BlkDevSegment>>> {
        let total_needed: Sectors = sizes.iter().cloned().sum();
        if self.avail_space() < total_needed {
            return None;
        }

        let mut lists = Vec::new();
        for &needed in sizes {
            let mut alloc = Sectors(0);
            let mut segs = Vec::new();
            // TODO: Consider greater efficiency for allocation generally.
            // Over time, the blockdevs at the start will be exhausted. It
            // might be a good idea to keep an auxiliary structure, so that
            // only blockdevs with some space left to allocate are accessed.
            // In the context of this major inefficiency that ensues over time
            // the obvious but more minor inefficiency of this inner loop is
            // not worth worrying about.
            for bd in &mut self.block_devs {
                if alloc == needed {
                    break;
                }

                let (gotten, r_segs) = bd.request_space(needed - alloc);
                let blkdev_segs = r_segs
                    .into_iter()
                    .map(|(start, length)| {
                             BlkDevSegment::new(bd.uuid(),
                                                Segment::new(*bd.device(), start, length))
                         });
                segs.extend(blkdev_segs);
                alloc += gotten;
            }
            assert_eq!(alloc, needed);
            lists.push(segs);
        }

        Some(lists)
    }

    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 current 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. If current time is not more recent than previously written
    /// time, use a time that is one nanosecond greater than that previously
    /// written. Randomly select no more than MAX_NUM_TO_WRITE blockdevs to
    /// write to.
    pub fn save_state(&mut self, metadata: &[u8]) -> EngineResult<()> {
        let current_time = Utc::now();
        let stamp_time = if Some(current_time) <= self.last_update_time {
            self.last_update_time
                .expect("self.last_update_time >= Some(current_time")
                .checked_add_signed(Duration::nanoseconds(1))
                .expect("self.last_update_time << maximum representable DateTime")
        } else {
            current_time
        };

        let data_size = Bytes(metadata.len() as u64).sectors();
        let candidates = self.block_devs
            .iter_mut()
            .filter(|b| b.max_metadata_size() >= data_size);

        // TODO: consider making selection not entirely random, i.e, ensuring
        // distribution of metadata over different paths.
        let saved = sample(&mut thread_rng(), candidates, MAX_NUM_TO_WRITE)
            .iter_mut()
            .fold(false,
                  |acc, b| acc | b.save_state(&stamp_time, metadata).is_ok());

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

    /// Get references to managed blockdevs.
    pub fn blockdevs(&self) -> Vec<&BlockDev> {
        self.block_devs
            .iter()
            .map(|bd| bd as &BlockDev)
            .collect()
    }

    // SIZE methods

    /// The number of sectors not allocated for any purpose.
    pub fn avail_space(&self) -> Sectors {
        self.block_devs.iter().map(|bd| bd.available()).sum()
    }

    /// The current capacity of all the blockdevs.
    /// self.current_capacity() > self.avail_space() because some sectors
    /// are certainly allocated for Stratis metadata
    pub fn current_capacity(&self) -> Sectors {
        self.block_devs
            .iter()
            .map(|b| b.current_capacity())
            .sum()
    }

    /// The number of sectors given over to Stratis metadata
    /// self.current_capacity() - self.metadata_size() >= self.avail_space()
    pub fn metadata_size(&self) -> Sectors {
        self.block_devs
            .iter()
            .map(|bd| bd.metadata_size())
            .sum()
    }
}

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

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

    /// 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(devnode: &Path) -> EngineResult<(&Path, Bytes, DevOwnership, File)> {
        let mut f = OpenOptions::new()
            .read(true)
            .write(true)
            .open(&devnode)?;
        let dev_size = blkdev_size(&f)?;
        let ownership = 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<'a, I>(dev_infos: I,
                          pool_uuid: PoolUuid,
                          force: bool)
                          -> EngineResult<Vec<(Device, (&'a Path, Bytes, File))>>
        where I: Iterator<Item = (Device, EngineResult<(&'a Path, Bytes, DevOwnership, File)>)>
    {
        let mut add_devs = Vec::new();
        for (dev, dev_result) in dev_infos {
            let (devnode, dev_size, ownership, f) = 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)
    }

    validate_mda_size(mda_size)?;

    let dev_infos = devices.into_iter().map(|(d, p)| (d, dev_info(p)));

    let add_devs = filter_devs(dev_infos, pool_uuid, force)?;

    let mut bds: Vec<StratBlockDev> = 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(),
                                  Utc::now().timestamp() as u64);
        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(StratBlockDev::new(dev, devnode.to_owned(), 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>Allow cloning of BlkDevSegments<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::collections::HashMap;
use std::fs::{File, OpenOptions};
use std::path::{Path, PathBuf};

use chrono::{DateTime, Duration, Utc};
use rand::{thread_rng, sample};
use uuid::Uuid;

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

use super::super::engine::BlockDev;
use super::super::errors::{EngineError, EngineResult, ErrorEnum};
use super::super::types::{DevUuid, PoolUuid};

use super::cleanup::wipe_blockdevs;
use super::blockdev::StratBlockDev;
use super::device::{blkdev_size, resolve_devices};
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);
const MAX_NUM_TO_WRITE: usize = 10;

#[derive(Clone, Debug)]
pub struct BlkDevSegment {
    pub uuid: DevUuid,
    pub segment: Segment,
}

impl BlkDevSegment {
    pub fn new(uuid: DevUuid, segment: Segment) -> BlkDevSegment {
        BlkDevSegment { uuid, segment }
    }

    pub fn to_segment(&self) -> Segment {
        self.segment.clone()
    }
}

impl Recordable<Vec<(Uuid, Sectors, Sectors)>> for Vec<BlkDevSegment> {
    fn record(&self) -> Vec<(Uuid, Sectors, Sectors)> {
        self.iter()
            .map(|bseg| (bseg.uuid, bseg.segment.start, bseg.segment.length))
            .collect::<Vec<_>>()
    }
}

/// Build a Vec<Segment> from BlkDevSegments. This is useful for calls
/// to the devicemapper library.
pub fn map_to_dm(bsegs: &[BlkDevSegment]) -> Vec<Segment> {
    bsegs
        .into_iter()
        .map(|bseg| bseg.to_segment())
        .collect::<Vec<_>>()
}

#[derive(Debug)]
pub struct BlockDevMgr {
    pool_uuid: PoolUuid,
    block_devs: Vec<StratBlockDev>,
    last_update_time: Option<DateTime<Utc>>,
}

impl BlockDevMgr {
    pub fn new(pool_uuid: PoolUuid, block_devs: Vec<StratBlockDev>) -> BlockDevMgr {
        BlockDevMgr {
            pool_uuid: pool_uuid,
            block_devs: block_devs,
            last_update_time: None,
        }
    }

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

    /// Get a function that maps UUIDs to Devices.
    pub fn uuid_to_devno(&self) -> Box<Fn(DevUuid) -> Option<Device>> {
        let uuid_map: HashMap<DevUuid, Device> = self.block_devs
            .iter()
            .map(|bd| (bd.uuid(), *bd.device()))
            .collect();

        Box::new(move |uuid: DevUuid| -> Option<Device> { uuid_map.get(&uuid).cloned() })
    }

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

    pub fn destroy_all(self) -> EngineResult<()> {
        wipe_blockdevs(&self.block_devs)
    }

    /// Allocate space according to sizes vector request.
    /// Return the segments allocated for each request, or None if it was
    /// not possible to satisfy the request.
    /// This method is atomic, it either allocates all requested or allocates
    /// nothing.
    pub fn alloc_space(&mut self, sizes: &[Sectors]) -> Option<Vec<Vec<BlkDevSegment>>> {
        let total_needed: Sectors = sizes.iter().cloned().sum();
        if self.avail_space() < total_needed {
            return None;
        }

        let mut lists = Vec::new();
        for &needed in sizes {
            let mut alloc = Sectors(0);
            let mut segs = Vec::new();
            // TODO: Consider greater efficiency for allocation generally.
            // Over time, the blockdevs at the start will be exhausted. It
            // might be a good idea to keep an auxiliary structure, so that
            // only blockdevs with some space left to allocate are accessed.
            // In the context of this major inefficiency that ensues over time
            // the obvious but more minor inefficiency of this inner loop is
            // not worth worrying about.
            for bd in &mut self.block_devs {
                if alloc == needed {
                    break;
                }

                let (gotten, r_segs) = bd.request_space(needed - alloc);
                let blkdev_segs = r_segs
                    .into_iter()
                    .map(|(start, length)| {
                             BlkDevSegment::new(bd.uuid(),
                                                Segment::new(*bd.device(), start, length))
                         });
                segs.extend(blkdev_segs);
                alloc += gotten;
            }
            assert_eq!(alloc, needed);
            lists.push(segs);
        }

        Some(lists)
    }

    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 current 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. If current time is not more recent than previously written
    /// time, use a time that is one nanosecond greater than that previously
    /// written. Randomly select no more than MAX_NUM_TO_WRITE blockdevs to
    /// write to.
    pub fn save_state(&mut self, metadata: &[u8]) -> EngineResult<()> {
        let current_time = Utc::now();
        let stamp_time = if Some(current_time) <= self.last_update_time {
            self.last_update_time
                .expect("self.last_update_time >= Some(current_time")
                .checked_add_signed(Duration::nanoseconds(1))
                .expect("self.last_update_time << maximum representable DateTime")
        } else {
            current_time
        };

        let data_size = Bytes(metadata.len() as u64).sectors();
        let candidates = self.block_devs
            .iter_mut()
            .filter(|b| b.max_metadata_size() >= data_size);

        // TODO: consider making selection not entirely random, i.e, ensuring
        // distribution of metadata over different paths.
        let saved = sample(&mut thread_rng(), candidates, MAX_NUM_TO_WRITE)
            .iter_mut()
            .fold(false,
                  |acc, b| acc | b.save_state(&stamp_time, metadata).is_ok());

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

    /// Get references to managed blockdevs.
    pub fn blockdevs(&self) -> Vec<&BlockDev> {
        self.block_devs
            .iter()
            .map(|bd| bd as &BlockDev)
            .collect()
    }

    // SIZE methods

    /// The number of sectors not allocated for any purpose.
    pub fn avail_space(&self) -> Sectors {
        self.block_devs.iter().map(|bd| bd.available()).sum()
    }

    /// The current capacity of all the blockdevs.
    /// self.current_capacity() > self.avail_space() because some sectors
    /// are certainly allocated for Stratis metadata
    pub fn current_capacity(&self) -> Sectors {
        self.block_devs
            .iter()
            .map(|b| b.current_capacity())
            .sum()
    }

    /// The number of sectors given over to Stratis metadata
    /// self.current_capacity() - self.metadata_size() >= self.avail_space()
    pub fn metadata_size(&self) -> Sectors {
        self.block_devs
            .iter()
            .map(|bd| bd.metadata_size())
            .sum()
    }
}

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

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

    /// 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(devnode: &Path) -> EngineResult<(&Path, Bytes, DevOwnership, File)> {
        let mut f = OpenOptions::new()
            .read(true)
            .write(true)
            .open(&devnode)?;
        let dev_size = blkdev_size(&f)?;
        let ownership = 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<'a, I>(dev_infos: I,
                          pool_uuid: PoolUuid,
                          force: bool)
                          -> EngineResult<Vec<(Device, (&'a Path, Bytes, File))>>
        where I: Iterator<Item = (Device, EngineResult<(&'a Path, Bytes, DevOwnership, File)>)>
    {
        let mut add_devs = Vec::new();
        for (dev, dev_result) in dev_infos {
            let (devnode, dev_size, ownership, f) = 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)
    }

    validate_mda_size(mda_size)?;

    let dev_infos = devices.into_iter().map(|(d, p)| (d, dev_info(p)));

    let add_devs = filter_devs(dev_infos, pool_uuid, force)?;

    let mut bds: Vec<StratBlockDev> = 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(),
                                  Utc::now().timestamp() as u64);
        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(StratBlockDev::new(dev, devnode.to_owned(), 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>use core::ops::{Add, AddAssign, Sub, SubAssign};
use core::iter::Step;
use core::{fmt, mem};
use core::convert::{Into, TryFrom, TryInto};

use usize_conversions::usize_from;
use bit_field::BitField;
use ux::*;

/// A canonical 64-bit virtual memory address.
///
/// This is a wrapper type around an `u64`, so it is always 8 bytes, even when compiled
/// on non 64-bit systems. The `UsizeConversions` trait can be used for performing conversions
/// between `u64` and `usize`.
///
/// On `x86_64`, only the 48 lower bits of a virtual address can be used. The top 16 bits need
/// to be copies of bit 47, i.e. the most significant bit. Addresses that fulfil this criterium
/// are called “canonical”. This type guarantees that it always represents a canonical address.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct VirtAddr(u64);

/// A 64-bit physical memory address.
///
/// This is a wrapper type around an `u64`, so it is always 8 bytes, even when compiled
/// on non 64-bit systems. The `UsizeConversions` trait can be used for performing conversions
/// between `u64` and `usize`.
///
/// On `x86_64`, only the 52 lower bits of a physical address can be used. The top 12 bits need
/// to be zero. This type guarantees that it always represents a valid physical address.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct PhysAddr(u64);

/// A passed `u64` was not a valid virtual address.
///
/// This means that bits 48 to 64 are not
/// a valid sign extension and are not null either. So automatic sign extension would have
/// overwritten possibly meaningful bits. This likely indicates a bug, for example an invalid
/// address calculation.
#[derive(Debug)]
pub struct VirtAddrNotValid(u64);

impl VirtAddr {
    /// Creates a new canonical virtual address.
    ///
    /// This function performs sign extension of bit 47 to make the address canonical. Panics
    /// if the bits in the range 48 to 64 contain data (i.e. are not null and no sign extension).
    pub fn new(addr: u64) -> VirtAddr {
        Self::try_new(addr).expect("address passed to VirtAddr::new must not contain any data \
        in bits 48 to 64")
    }

    /// Tries to create a new canonical virtual address.
    ///
    /// This function tries to performs sign
    /// extension of bit 47 to make the address canonical. It succeeds if bits 48 to 64 are
    /// either a correct sign extension (i.e. copies of bit 47) or all null. Else, an error
    /// is returned.
    pub fn try_new(addr: u64) -> Result<VirtAddr, VirtAddrNotValid> {
        match addr.get_bits(47..64) {
            0 | 0x1ffff => Ok(VirtAddr(addr)), // address is canonical
            1 => Ok(VirtAddr::new_unchecked(addr)), // address needs sign extension
            other => Err(VirtAddrNotValid(other))
        }
    }

    /// Creates a new canonical virtual address without checks.
    ///
    /// This function performs sign extension of bit 47 to make the address canonical, so
    /// bits 48 to 64 are overwritten. If you want to check that these bits contain no data,
    /// use `new` or `try_new`.
    pub fn new_unchecked(mut addr: u64) -> VirtAddr {
        if addr.get_bit(47) {
            addr.set_bits(48..64, 0xffff);
        } else {
            addr.set_bits(48..64, 0);
        }
        VirtAddr(addr)
    }

    /// Converts the address to an `u64`.
    pub fn as_u64(self) -> u64 {
        self.0
    }

    pub fn as_ptr<T>(self) -> *const T {
        usize_from(self.as_u64()) as *const T
    }

    pub fn as_mut_ptr<T>(self) -> *mut T {
        self.as_ptr::<T>() as *mut T
    }

    /// Aligns the virtual address upwards to the given alignment.
    ///
    /// See the `align_up` function for more information.
    pub fn align_up<U>(self, align: U) -> Self
        where U: Into<u64>
    {
        VirtAddr(align_up(self.0, align.into()))
    }

    /// Aligns the virtual address downwards to the given alignment.
    ///
    /// See the `align_down` function for more information.
    pub fn align_down<U>(self, align: U) -> Self
        where U: Into<u64>
    {
        VirtAddr(align_down(self.0, align.into()))
    }

    /// Returns the 12-bit page offset of this virtual address.
    pub fn page_offset(&self) -> u12 {
        u12::new((self.0 & 0xfff).try_into().unwrap())
    }

    /// Returns the 9-bit level 1 page table index.
    pub fn p1_index(&self) -> u9 {
        u9::new(((self.0 >> 12) & 0o777).try_into().unwrap())
    }

    /// Returns the 9-bit level 2 page table index.
    pub fn p2_index(&self) -> u9 {
        u9::new(((self.0 >> 12 >> 9) & 0o777).try_into().unwrap())
    }

    /// Returns the 9-bit level 3 page table index.
    pub fn p3_index(&self) -> u9 {
        u9::new(((self.0 >> 12 >> 9 >> 9) & 0o777).try_into().unwrap())
    }

    /// Returns the 9-bit level 4 page table index.
    pub fn p4_index(&self) -> u9 {
        u9::new(((self.0 >> 12 >> 9 >> 9 >> 9) & 0o777).try_into().unwrap())
    }
}

impl fmt::Debug for VirtAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "VirtAddr({:#x})", self.0)
    }
}

impl Add<u64> for VirtAddr {
    type Output = Self;
    fn add(self, rhs: u64) -> Self::Output {
        VirtAddr::new(self.0 + rhs)
    }
}

impl AddAssign<u64> for VirtAddr {
    fn add_assign(&mut self, rhs: u64) {
        *self = *self + rhs;
    }
}

impl Sub<u64> for VirtAddr {
    type Output = Self;
    fn sub(self, rhs: u64) -> Self::Output {
        VirtAddr::new(self.0 - rhs)
    }
}

impl SubAssign<u64> for VirtAddr {
    fn sub_assign(&mut self, rhs: u64) {
        *self = *self - rhs;
    }
}

impl Sub<VirtAddr> for VirtAddr {
    type Output = u64;
    fn sub(self, rhs: VirtAddr) -> Self::Output {
        self.as_u64() - rhs.as_u64()
    }
}

impl Step for VirtAddr {
    fn steps_between(start: &Self, end: &Self) -> Option<usize> {
        if *start < *end {
            usize::try_from(end.0.get_bits(0..48) - start.0.get_bits(0..48)).ok()
        } else {
            Some(0)
        }
    }

    fn replace_one(&mut self) -> Self {
        mem::replace(self, VirtAddr(1))
    }

    fn replace_zero(&mut self) -> Self {
        mem::replace(self, VirtAddr(0))
    }

    fn add_one(&self) -> Self {
        *self + 1
    }

    fn sub_one(&self) -> Self {
        *self - 1
    }

    fn add_usize(&self, n: usize) -> Option<Self> {
        u64::try_from(n).ok().and_then(|n| self.0.checked_add(n)).map(VirtAddr)
    }
}

/// A passed `u64` was not a valid physical address.
///
/// This means that bits 52 to 64 are not were not all null.
#[derive(Debug)]
pub struct PhysAddrNotValid(u64);

impl PhysAddr {
    /// Creates a new physical address.
    ///
    /// Panics if a bit in the range 52 to 64 is set.
    pub fn new(addr: u64) -> PhysAddr {
        assert_eq!(addr.get_bits(52..64), 0,
            "physical addresses must not have any bits in the range 52 to 64 set");
        PhysAddr(addr)
    }

    /// Tries to create a new physical address.
    ///
    /// Fails if any bits in the range 52 to 64 are set.
    pub fn try_new(addr: u64) -> Result<PhysAddr, PhysAddrNotValid> {
        match addr.get_bits(52..64) {
            0 => Ok(PhysAddr(addr)), // address is valid
            other => Err(PhysAddrNotValid(other))
        }
    }

    /// Converts the address to an `u64`.
    pub fn as_u64(self) -> u64 {
        self.0
    }

    /// Convenience method for checking if a physical address is null.
    pub fn is_null(&self) -> bool {
        self.0 == 0
    }

    /// Aligns the physical address upwards to the given alignment.
    ///
    /// See the `align_up` function for more information.
    pub fn align_up<U>(self, align: U) -> Self
        where U: Into<u64>
    {
        PhysAddr(align_up(self.0, align.into()))
    }

    /// Aligns the physical address downwards to the given alignment.
    ///
    /// See the `align_down` function for more information.
    pub fn align_down<U>(self, align: U) -> Self
        where U: Into<u64>
    {
        PhysAddr(align_down(self.0, align.into()))
    }
}

impl fmt::Debug for PhysAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "PhysAddr({:#x})", self.0)
    }
}

impl fmt::Binary for PhysAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::LowerHex for PhysAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::Octal for PhysAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::UpperHex for PhysAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl Add<u64> for PhysAddr {
    type Output = Self;
    fn add(self, rhs: u64) -> Self::Output {
        PhysAddr::new(self.0 + rhs)
    }
}

impl AddAssign<u64> for PhysAddr {
    fn add_assign(&mut self, rhs: u64) {
        *self = *self + rhs;
    }
}

impl Sub<u64> for PhysAddr {
    type Output = Self;
    fn sub(self, rhs: u64) -> Self::Output {
        PhysAddr::new(self.0 - rhs)
    }
}

impl SubAssign<u64> for PhysAddr {
    fn sub_assign(&mut self, rhs: u64) {
        *self = *self - rhs;
    }
}

impl Sub<PhysAddr> for PhysAddr {
    type Output = u64;
    fn sub(self, rhs: PhysAddr) -> Self::Output {
        self.as_u64() - rhs.as_u64()
    }
}

impl Step for PhysAddr {
    fn steps_between(start: &Self, end: &Self) -> Option<usize> {
        if *start < *end {
            usize::try_from(end.0 - start.0).ok()
        } else {
            Some(0)
        }
    }

    fn replace_one(&mut self) -> Self {
        mem::replace(self, PhysAddr(1))
    }

    fn replace_zero(&mut self) -> Self {
        mem::replace(self, PhysAddr(0))
    }

    fn add_one(&self) -> Self {
        *self + 1
    }

    fn sub_one(&self) -> Self {
        *self - 1
    }

    fn add_usize(&self, n: usize) -> Option<Self> {
        u64::try_from(n).ok().and_then(|n| self.0.checked_add(n)).map(PhysAddr)
    }
}

/// Align address downwards.
///
/// Returns the greatest x with alignment `align` so that x <= addr. The alignment must be
///  a power of 2.
pub fn align_down(addr: u64, align: u64) -> u64 {
    assert!(align.is_power_of_two(), "`align` must be a power of two");
    addr & !(align - 1)
}

/// Align address upwards.
///
/// Returns the smallest x with alignment `align` so that x >= addr. The alignment must be
/// a power of 2.
pub fn align_up(addr: u64, align: u64) -> u64 {
    assert!(align.is_power_of_two(), "`align` must be a power of two");
    let align_mask = align - 1;
    if addr & align_mask == 0 {
        addr // already aligned
    } else {
        (addr | align_mask) + 1
    }
}

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

    #[test]
    pub fn test_align_up() {
        // align 1
        assert_eq!(align_up(0, 1), 0);
        assert_eq!(align_up(1234, 1), 1234);
        assert_eq!(align_up(0xffffffffffffffff, 1), 0xffffffffffffffff);
        // align 2
        assert_eq!(align_up(0, 2), 0);
        assert_eq!(align_up(1233, 2), 1234);
        assert_eq!(align_up(0xfffffffffffffffe, 2), 0xfffffffffffffffe);
        // address 0
        assert_eq!(align_up(0, 128), 0);
        assert_eq!(align_up(0, 1), 0);
        assert_eq!(align_up(0, 2), 0);
        assert_eq!(align_up(0, 0x8000000000000000), 0);
    }
}
<commit_msg>Impl {Add, AddAssign, Sub, SubAssign}<usize> for VirtAddr and PhysAddr<commit_after>use core::ops::{Add, AddAssign, Sub, SubAssign};
use core::iter::Step;
use core::{fmt, mem};
use core::convert::{Into, TryFrom, TryInto};

use usize_conversions::{usize_from, FromUsize};
use bit_field::BitField;
use ux::*;

/// A canonical 64-bit virtual memory address.
///
/// This is a wrapper type around an `u64`, so it is always 8 bytes, even when compiled
/// on non 64-bit systems. The `UsizeConversions` trait can be used for performing conversions
/// between `u64` and `usize`.
///
/// On `x86_64`, only the 48 lower bits of a virtual address can be used. The top 16 bits need
/// to be copies of bit 47, i.e. the most significant bit. Addresses that fulfil this criterium
/// are called “canonical”. This type guarantees that it always represents a canonical address.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct VirtAddr(u64);

/// A 64-bit physical memory address.
///
/// This is a wrapper type around an `u64`, so it is always 8 bytes, even when compiled
/// on non 64-bit systems. The `UsizeConversions` trait can be used for performing conversions
/// between `u64` and `usize`.
///
/// On `x86_64`, only the 52 lower bits of a physical address can be used. The top 12 bits need
/// to be zero. This type guarantees that it always represents a valid physical address.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct PhysAddr(u64);

/// A passed `u64` was not a valid virtual address.
///
/// This means that bits 48 to 64 are not
/// a valid sign extension and are not null either. So automatic sign extension would have
/// overwritten possibly meaningful bits. This likely indicates a bug, for example an invalid
/// address calculation.
#[derive(Debug)]
pub struct VirtAddrNotValid(u64);

impl VirtAddr {
    /// Creates a new canonical virtual address.
    ///
    /// This function performs sign extension of bit 47 to make the address canonical. Panics
    /// if the bits in the range 48 to 64 contain data (i.e. are not null and no sign extension).
    pub fn new(addr: u64) -> VirtAddr {
        Self::try_new(addr).expect("address passed to VirtAddr::new must not contain any data \
        in bits 48 to 64")
    }

    /// Tries to create a new canonical virtual address.
    ///
    /// This function tries to performs sign
    /// extension of bit 47 to make the address canonical. It succeeds if bits 48 to 64 are
    /// either a correct sign extension (i.e. copies of bit 47) or all null. Else, an error
    /// is returned.
    pub fn try_new(addr: u64) -> Result<VirtAddr, VirtAddrNotValid> {
        match addr.get_bits(47..64) {
            0 | 0x1ffff => Ok(VirtAddr(addr)), // address is canonical
            1 => Ok(VirtAddr::new_unchecked(addr)), // address needs sign extension
            other => Err(VirtAddrNotValid(other))
        }
    }

    /// Creates a new canonical virtual address without checks.
    ///
    /// This function performs sign extension of bit 47 to make the address canonical, so
    /// bits 48 to 64 are overwritten. If you want to check that these bits contain no data,
    /// use `new` or `try_new`.
    pub fn new_unchecked(mut addr: u64) -> VirtAddr {
        if addr.get_bit(47) {
            addr.set_bits(48..64, 0xffff);
        } else {
            addr.set_bits(48..64, 0);
        }
        VirtAddr(addr)
    }

    /// Converts the address to an `u64`.
    pub fn as_u64(self) -> u64 {
        self.0
    }

    pub fn as_ptr<T>(self) -> *const T {
        usize_from(self.as_u64()) as *const T
    }

    pub fn as_mut_ptr<T>(self) -> *mut T {
        self.as_ptr::<T>() as *mut T
    }

    /// Aligns the virtual address upwards to the given alignment.
    ///
    /// See the `align_up` function for more information.
    pub fn align_up<U>(self, align: U) -> Self
        where U: Into<u64>
    {
        VirtAddr(align_up(self.0, align.into()))
    }

    /// Aligns the virtual address downwards to the given alignment.
    ///
    /// See the `align_down` function for more information.
    pub fn align_down<U>(self, align: U) -> Self
        where U: Into<u64>
    {
        VirtAddr(align_down(self.0, align.into()))
    }

    /// Returns the 12-bit page offset of this virtual address.
    pub fn page_offset(&self) -> u12 {
        u12::new((self.0 & 0xfff).try_into().unwrap())
    }

    /// Returns the 9-bit level 1 page table index.
    pub fn p1_index(&self) -> u9 {
        u9::new(((self.0 >> 12) & 0o777).try_into().unwrap())
    }

    /// Returns the 9-bit level 2 page table index.
    pub fn p2_index(&self) -> u9 {
        u9::new(((self.0 >> 12 >> 9) & 0o777).try_into().unwrap())
    }

    /// Returns the 9-bit level 3 page table index.
    pub fn p3_index(&self) -> u9 {
        u9::new(((self.0 >> 12 >> 9 >> 9) & 0o777).try_into().unwrap())
    }

    /// Returns the 9-bit level 4 page table index.
    pub fn p4_index(&self) -> u9 {
        u9::new(((self.0 >> 12 >> 9 >> 9 >> 9) & 0o777).try_into().unwrap())
    }
}

impl fmt::Debug for VirtAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "VirtAddr({:#x})", self.0)
    }
}

impl Add<u64> for VirtAddr {
    type Output = Self;
    fn add(self, rhs: u64) -> Self::Output {
        VirtAddr::new(self.0 + rhs)
    }
}

impl AddAssign<u64> for VirtAddr {
    fn add_assign(&mut self, rhs: u64) {
        *self = *self + rhs;
    }
}

impl Add<usize> for VirtAddr where u64: FromUsize {
    type Output = Self;
    fn add(self, rhs: usize) -> Self::Output {
        self + u64::from_usize(rhs)
    }
}

impl AddAssign<usize> for VirtAddr where u64: FromUsize {
    fn add_assign(&mut self, rhs: usize) {
        self.add_assign(u64::from_usize(rhs))
    }
}

impl Sub<u64> for VirtAddr {
    type Output = Self;
    fn sub(self, rhs: u64) -> Self::Output {
        VirtAddr::new(self.0 - rhs)
    }
}

impl SubAssign<u64> for VirtAddr {
    fn sub_assign(&mut self, rhs: u64) {
        *self = *self - rhs;
    }
}

impl Sub<usize> for VirtAddr where u64: FromUsize {
    type Output = Self;
    fn sub(self, rhs: usize) -> Self::Output {
        self - u64::from_usize(rhs)
    }
}

impl SubAssign<usize> for VirtAddr where u64: FromUsize {
    fn sub_assign(&mut self, rhs: usize) {
        self.sub_assign(u64::from_usize(rhs))
    }
}

impl Sub<VirtAddr> for VirtAddr {
    type Output = u64;
    fn sub(self, rhs: VirtAddr) -> Self::Output {
        self.as_u64() - rhs.as_u64()
    }
}

impl Step for VirtAddr {
    fn steps_between(start: &Self, end: &Self) -> Option<usize> {
        if *start < *end {
            usize::try_from(end.0.get_bits(0..48) - start.0.get_bits(0..48)).ok()
        } else {
            Some(0)
        }
    }

    fn replace_one(&mut self) -> Self {
        mem::replace(self, VirtAddr(1))
    }

    fn replace_zero(&mut self) -> Self {
        mem::replace(self, VirtAddr(0))
    }

    fn add_one(&self) -> Self {
        *self + 1u64
    }

    fn sub_one(&self) -> Self {
        *self - 1u64
    }

    fn add_usize(&self, n: usize) -> Option<Self> {
        u64::try_from(n).ok().and_then(|n| self.0.checked_add(n)).map(VirtAddr)
    }
}

/// A passed `u64` was not a valid physical address.
///
/// This means that bits 52 to 64 are not were not all null.
#[derive(Debug)]
pub struct PhysAddrNotValid(u64);

impl PhysAddr {
    /// Creates a new physical address.
    ///
    /// Panics if a bit in the range 52 to 64 is set.
    pub fn new(addr: u64) -> PhysAddr {
        assert_eq!(addr.get_bits(52..64), 0,
            "physical addresses must not have any bits in the range 52 to 64 set");
        PhysAddr(addr)
    }

    /// Tries to create a new physical address.
    ///
    /// Fails if any bits in the range 52 to 64 are set.
    pub fn try_new(addr: u64) -> Result<PhysAddr, PhysAddrNotValid> {
        match addr.get_bits(52..64) {
            0 => Ok(PhysAddr(addr)), // address is valid
            other => Err(PhysAddrNotValid(other))
        }
    }

    /// Converts the address to an `u64`.
    pub fn as_u64(self) -> u64 {
        self.0
    }

    /// Convenience method for checking if a physical address is null.
    pub fn is_null(&self) -> bool {
        self.0 == 0
    }

    /// Aligns the physical address upwards to the given alignment.
    ///
    /// See the `align_up` function for more information.
    pub fn align_up<U>(self, align: U) -> Self
        where U: Into<u64>
    {
        PhysAddr(align_up(self.0, align.into()))
    }

    /// Aligns the physical address downwards to the given alignment.
    ///
    /// See the `align_down` function for more information.
    pub fn align_down<U>(self, align: U) -> Self
        where U: Into<u64>
    {
        PhysAddr(align_down(self.0, align.into()))
    }
}

impl fmt::Debug for PhysAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "PhysAddr({:#x})", self.0)
    }
}

impl fmt::Binary for PhysAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::LowerHex for PhysAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::Octal for PhysAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::UpperHex for PhysAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl Add<u64> for PhysAddr {
    type Output = Self;
    fn add(self, rhs: u64) -> Self::Output {
        PhysAddr::new(self.0 + rhs)
    }
}

impl AddAssign<u64> for PhysAddr {
    fn add_assign(&mut self, rhs: u64) {
        *self = *self + rhs;
    }
}

impl Add<usize> for PhysAddr where u64: FromUsize {
    type Output = Self;
    fn add(self, rhs: usize) -> Self::Output {
        self + u64::from_usize(rhs)
    }
}

impl AddAssign<usize> for PhysAddr where u64: FromUsize {
    fn add_assign(&mut self, rhs: usize) {
        self.add_assign(u64::from_usize(rhs))
    }
}

impl Sub<u64> for PhysAddr {
    type Output = Self;
    fn sub(self, rhs: u64) -> Self::Output {
        PhysAddr::new(self.0 - rhs)
    }
}

impl SubAssign<u64> for PhysAddr {
    fn sub_assign(&mut self, rhs: u64) {
        *self = *self - rhs;
    }
}

impl Sub<usize> for PhysAddr where u64: FromUsize {
    type Output = Self;
    fn sub(self, rhs: usize) -> Self::Output {
        self - u64::from_usize(rhs)
    }
}

impl SubAssign<usize> for PhysAddr where u64: FromUsize {
    fn sub_assign(&mut self, rhs: usize) {
        self.sub_assign(u64::from_usize(rhs))
    }
}

impl Sub<PhysAddr> for PhysAddr {
    type Output = u64;
    fn sub(self, rhs: PhysAddr) -> Self::Output {
        self.as_u64() - rhs.as_u64()
    }
}

impl Step for PhysAddr {
    fn steps_between(start: &Self, end: &Self) -> Option<usize> {
        if *start < *end {
            usize::try_from(end.0 - start.0).ok()
        } else {
            Some(0)
        }
    }

    fn replace_one(&mut self) -> Self {
        mem::replace(self, PhysAddr(1))
    }

    fn replace_zero(&mut self) -> Self {
        mem::replace(self, PhysAddr(0))
    }

    fn add_one(&self) -> Self {
        *self + 1u64
    }

    fn sub_one(&self) -> Self {
        *self - 1u64
    }

    fn add_usize(&self, n: usize) -> Option<Self> {
        u64::try_from(n).ok().and_then(|n| self.0.checked_add(n)).map(PhysAddr)
    }
}

/// Align address downwards.
///
/// Returns the greatest x with alignment `align` so that x <= addr. The alignment must be
///  a power of 2.
pub fn align_down(addr: u64, align: u64) -> u64 {
    assert!(align.is_power_of_two(), "`align` must be a power of two");
    addr & !(align - 1)
}

/// Align address upwards.
///
/// Returns the smallest x with alignment `align` so that x >= addr. The alignment must be
/// a power of 2.
pub fn align_up(addr: u64, align: u64) -> u64 {
    assert!(align.is_power_of_two(), "`align` must be a power of two");
    let align_mask = align - 1;
    if addr & align_mask == 0 {
        addr // already aligned
    } else {
        (addr | align_mask) + 1
    }
}

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

    #[test]
    pub fn test_align_up() {
        // align 1
        assert_eq!(align_up(0, 1), 0);
        assert_eq!(align_up(1234, 1), 1234);
        assert_eq!(align_up(0xffffffffffffffff, 1), 0xffffffffffffffff);
        // align 2
        assert_eq!(align_up(0, 2), 0);
        assert_eq!(align_up(1233, 2), 1234);
        assert_eq!(align_up(0xfffffffffffffffe, 2), 0xfffffffffffffffe);
        // address 0
        assert_eq!(align_up(0, 128), 0);
        assert_eq!(align_up(0, 1), 0);
        assert_eq!(align_up(0, 2), 0);
        assert_eq!(align_up(0, 0x8000000000000000), 0);
    }
}
<|endoftext|>


<commit_before>use std::f32::consts::FRAC_PI_2 as QUARTER_TAU;
use std::ops::{Add, Sub, Mul, Div, Neg};

use glium::{self, Display, Texture2d, Program, VertexBuffer};
use glium::{DrawParameters, BlendingFunction, LinearBlendingFactor};
use glium::Surface as SurfaceTrait;
use glium::index::{NoIndices, PrimitiveType};

use ui::{BB, Px};
use ui::color::Color;
use ui::text::FontFaces;

#[cfg(not(windows))]
fn gamma_pre_correct([r, g, b, a]: Color) -> Color {
    fn ch(x: f32) -> f32 { ((x + 0.055) / 1.055).powf(2.4) }
    [ch(r), ch(g), ch(b), a]
}

#[cfg(windows)]
fn gamma_pre_correct(color: Color) -> Color {
    color
}

pub type Surface = glium::Frame;

#[derive(Copy, Clone)]
struct VertexXY {
    xy: [Px; 2]
}
implement_vertex!(VertexXY, xy);

#[derive(Copy, Clone)]
struct VertexUV {
    uv: [Px; 2]
}
implement_vertex!(VertexUV, uv);

const VERTEX_COUNT: usize = 256;

pub struct Renderer {
    data: Box<([VertexXY; VERTEX_COUNT], [VertexUV; VERTEX_COUNT])>,
    xy_buffer: VertexBuffer<VertexXY>,
    uv_buffer: VertexBuffer<VertexUV>,
    shader_color: Program,
    shader_texture: Program,
    pub fonts: FontFaces
}

impl Renderer {
    pub fn new(facade: &Display, fonts: FontFaces) -> Renderer {
        Renderer {
            data: box { ([VertexXY { xy: [0.0, 0.0] }; VERTEX_COUNT],
                         [VertexUV { uv: [0.0, 0.0] }; VERTEX_COUNT]) },
            xy_buffer: VertexBuffer::empty_dynamic(facade, VERTEX_COUNT).unwrap(),
            uv_buffer: VertexBuffer::empty_dynamic(facade, VERTEX_COUNT).unwrap(),
            shader_color: Program::from_source(facade, "
                #version 120
                uniform vec4 color;
                uniform vec2 scale;
                attribute vec2 xy;
                void main() {
                    gl_Position = vec4(xy * scale + vec2(-1.0, 1.0), 0.0, 1.0);
                }","
                #version 120
                uniform vec4 color;
                void main() {
                    gl_FragColor = color;
                }",
                None).unwrap(),
            shader_texture: Program::from_source(facade, "
                #version 120
                uniform sampler2D s_texture;
                uniform vec4 color;
                uniform vec2 scale;
                attribute vec2 xy;
                attribute vec2 uv;
                varying vec2 v_uv;
                void main() {
                    v_uv = uv;
                    gl_Position = vec4(xy * scale + vec2(-1.0, 1.0), 0.0, 1.0);
                }","
                #version 120
                uniform sampler2D s_texture;
                uniform vec4 color;
                varying vec2 v_uv;
                void main() {
                    gl_FragColor = texture2D(s_texture, v_uv) * color;
                }", None).unwrap(),
            fonts: fonts
        }
    }

    fn scale(&self, surface: &Surface) -> [Px; 2] {
        let (w, h) = surface.get_dimensions();
        let (w, h) = (w as Px, h as Px);
        [2.0 / w, -2.0 / h]
    }

    pub fn clear(&mut self, surface: &mut Surface, color: Color) {
        let [r, g, b, a] = gamma_pre_correct(color);
        surface.clear_color(r, g, b, a);
    }

    pub fn colored<F>(&mut self, surface: &mut Surface, color: Color, mut f: F)
        where F: FnMut((&mut [VertexXY; VERTEX_COUNT], &mut FnMut(&[VertexXY], PrimitiveType))) {

        let color = gamma_pre_correct(color);
        let scale = self.scale(surface);
        let xy_buffer = &self.xy_buffer;
        let shader = &self.shader_color;

        f((&mut self.data.0, &mut |xy_data: &[VertexXY], ty| {
            let xys = xy_buffer.slice(0..xy_data.len()).unwrap();
            xys.write(xy_data);

            surface.draw(xys, &NoIndices(ty), shader,
                &uniform! {
                    color: color,
                    scale: scale
                },
                &DrawParameters {
                    blending_function: Some(BlendingFunction::Addition {
                        source: LinearBlendingFactor::SourceAlpha,
                        destination: LinearBlendingFactor::OneMinusSourceAlpha,
                    }),
                    .. Default::default()
                }
            ).unwrap();
        }))
    }

    pub fn textured<F>(&mut self, surface: &mut Surface, color: Color, texture: &Texture2d, mut f: F)
        where F: FnMut((&mut [VertexXY; VERTEX_COUNT],
                        &mut [VertexUV; VERTEX_COUNT],
                        &mut FnMut(&[VertexXY], &[VertexUV], PrimitiveType))) {
        let color = gamma_pre_correct(color);
        let scale = self.scale(surface);
        let shader = &self.shader_texture;
        let (xy_buffer, uv_buffer) = (&self.xy_buffer, &self.uv_buffer);
        let (ref mut xy_data, ref mut uv_data) = *&mut *self.data;

        f((xy_data, uv_data,  &mut |xy_data: &[VertexXY], uv_data: &[VertexUV], ty| {
            let xys = xy_buffer.slice(0..xy_data.len()).unwrap();
            let uvs = uv_buffer.slice(0..uv_data.len()).unwrap();
            xys.write(xy_data);
            uvs.write(uv_data);

            surface.draw((xys, uvs), &NoIndices(ty), shader,
                &uniform! {
                    color: color,
                    scale: scale,
                    s_texture: texture
                },
                &DrawParameters {
                    blending_function: Some(BlendingFunction::Addition {
                        source: LinearBlendingFactor::SourceAlpha,
                        destination: LinearBlendingFactor::OneMinusSourceAlpha,
                    }),
                    .. Default::default()
                },
            ).unwrap();
        }))
    }
}

pub trait Buffer: Sized {
    type E: Copy + Sqrt +
            Neg<Output=Self::E> +
            Add<Output=Self::E> +
            Sub<Output=Self::E> +
            Mul<Px, Output=Self::E> +
            Mul<Output=Self::E> +
            Div<Output=Self::E>;

    fn vertex(&mut self, i: usize, vertex: [Self::E; 2]);
    fn flush(&mut self, n: usize, ty: PrimitiveType);
    fn flush_if_full(&mut self, n: usize, ty: PrimitiveType) -> bool;

    fn filled_polygon<I: Iterator<Item=[Self::E; 2]>>(&mut self, polygon: I) {
        let mut i = 0;
        for vertex in polygon {
            self.vertex(i, vertex);
            i += 1;

            if self.flush_if_full(i, PrimitiveType::TriangleFan) {
                // Preserve the first and last vertices.
                self.vertex(1, vertex);
                i = 2;
            }
        }
        self.flush(i, PrimitiveType::TriangleFan);
    }

    fn hollow_polygon<I: Iterator<Item=([Self::E; 2], [Self::E; 2])>>(&mut self, mut polygon: I) {
        let (a, b) = match polygon.next() { None => return, Some(x) => x };
        self.vertex(0, a);
        self.vertex(1, b);

        let mut i = 2;
        for (c, d) in polygon.chain(Some((a, b)).into_iter()) {
            self.vertex(i, c);
            self.vertex(i + 1, d);
            i += 2;

            if self.flush_if_full(i, PrimitiveType::TriangleStrip) {
                // Preserve the last two vertices.
                self.vertex(0, c);
                self.vertex(1, d);
                i = 2;
            }
        }
        self.flush(i, PrimitiveType::TriangleStrip);
    }

    fn line(mut self, from: [Self::E; 2], to: [Self::E; 2], width: Self::E) {
        let [x1, y1] = from;
        let [x2, y2] = to;
        let [lx, ly] = [x2 - x1, y2 - y1];
        let l = (lx * lx + ly * ly).sqrt();
        let scale = width * 0.5 / l;
        // Rotate by 90°.
        let dx = ly * scale;
        let dy = lx * -scale;
        self.filled_polygon([
            [x1 + dx, y1 + dy],
            [x1 - dx, y1 - dy],
            [x2 - dx, y2 - dy],
            [x2 + dx, y2 + dy]
        ].iter().cloned());
    }

    fn rect(mut self, bb: BB<Self::E>) {
        self.filled_polygon([
            bb.bottom_left(),
            bb.top_left(),
            bb.top_right(),
            bb.bottom_right()
        ].iter().cloned());
    }

    fn rect_border(mut self, bb: BB<Self::E>, border_size: Self::E) {
        let o = bb; // outer
        let i = bb.shrink(border_size); // inner
        self.hollow_polygon([
            (o.bottom_right(), i.bottom_right()),
            (o.bottom_left(), i.bottom_left()),
            (o.top_left(), i.top_left()),
            (o.top_right(), i.top_right())
        ].iter().cloned());
    }

    fn rect_round(mut self, bb: BB<Self::E>, resolution: u32, radius: Self::E) {
        let segment_rads = QUARTER_TAU / resolution as Px;
        let quarter = |i, [cx, cy]: [_; 2]| (0..resolution + 1).map(move |j| {
            let angle = (i as Px) * QUARTER_TAU + (j as Px) * segment_rads;
            [cx + radius * angle.cos(), cy + radius * angle.sin()]
        });
        let c = bb.shrink(radius);
        self.filled_polygon(quarter(0, c.bottom_right())
                     .chain(quarter(1, c.bottom_left()))
                     .chain(quarter(2, c.top_left()))
                     .chain(quarter(3, c.top_right())));
    }

    fn rect_border_round(mut self, bb: BB<Self::E>, border_size: Self::E, resolution: u32, radius: Self::E) {
        let segment_rads = QUARTER_TAU / resolution as Px;
        let inner = radius - border_size;
        let quarter = |i, [cx, cy]: [_; 2]| (0..resolution + 1).map(move |j| {
            let angle = (i as Px) * QUARTER_TAU + (j as Px) * segment_rads;
            let (cos, sin) = (angle.cos(), angle.sin());
            ([cx + radius * cos, cy + radius * sin],
             [cx + inner * cos,  cy + inner * sin])
        });
        let c = bb.shrink(radius);
        self.hollow_polygon(quarter(0, c.bottom_right())
                     .chain(quarter(1, c.bottom_left()))
                     .chain(quarter(2, c.top_left()))
                     .chain(quarter(3, c.top_right())));
    }
}

trait Sqrt {
    fn sqrt(self) -> Self;
}

impl Sqrt for Px {
    fn sqrt(self) -> Self {
        self.sqrt()
    }
}

impl<'a, F> Buffer for (&'a mut [VertexXY; VERTEX_COUNT], F)
    where F: FnMut(&[VertexXY], PrimitiveType) {

    type E = Px;

    #[inline(always)]
    fn vertex(&mut self, i: usize, xy: [Px; 2]) {
        self.0[i].xy = xy;
    }

    fn flush(&mut self, n: usize, ty: PrimitiveType) {
        if n >= 3 {
            self.1(&self.0[..n], ty);
        }
    }

    #[inline(always)]
    fn flush_if_full(&mut self, n: usize, ty: PrimitiveType) -> bool {
        if n >= VERTEX_COUNT {
            self.1(self.0, ty);
            true
        } else {
            false
        }
    }
}

#[derive(Copy, Clone)]
pub struct XYAndUV(pub Px, pub Px);

impl Add for XYAndUV {
    type Output = Self;
    fn add(self, other: Self) -> Self {
        XYAndUV(self.0 + other.0, self.1 + other.1)
    }
}
impl Mul<Px> for XYAndUV {
    type Output = Self;
    fn mul(self, x: Px) -> Self {
        XYAndUV(self.0 * x, self.1 * x)
    }
}
impl Mul for XYAndUV {
    type Output = Self;
    fn mul(self, other: Self) -> Self {
        XYAndUV(self.0 * other.0, self.1 * other.0)
    }
}
impl Div for XYAndUV {
    type Output = Self;
    fn div(self, other: Self) -> Self {
        XYAndUV(self.0 / other.0, self.1 / other.0)
    }
}
impl Sqrt for XYAndUV {
    fn sqrt(self) -> Self {
        XYAndUV(self.0.sqrt(), self.1.sqrt())
    }
}
impl Neg for XYAndUV { type Output = Self; fn neg(self) -> Self { self * -1.0 } }
impl Sub for XYAndUV { type Output = Self; fn sub(self, other: Self) -> Self { self + (-other) } }

impl<'a, 'b, F> Buffer for (&'a mut [VertexXY; VERTEX_COUNT], &'b mut [VertexUV; VERTEX_COUNT], F)
    where F: FnMut(&[VertexXY], &[VertexUV], PrimitiveType) {

    type E = XYAndUV;

    #[inline(always)]
    fn vertex(&mut self, i: usize, [XYAndUV(x, u), XYAndUV(y, v)]: [XYAndUV; 2]) {
        self.0[i].xy = [x, y];
        self.1[i].uv = [u, v];
    }

    fn flush(&mut self, n: usize, ty: PrimitiveType) {
        if n >= 3 {
            self.2(&self.0[..n], &self.1[..n], ty);
        }
    }

    #[inline(always)]
    fn flush_if_full(&mut self, n: usize, ty: PrimitiveType) -> bool {
        if n >= VERTEX_COUNT {
            self.2(self.0, self.1, ty);
            true
        } else {
            false
        }
    }
}
<commit_msg>Disable sRGB conversion in glium instead of using a gamma-correction hack.<commit_after>use std::f32::consts::FRAC_PI_2 as QUARTER_TAU;
use std::ops::{Add, Sub, Mul, Div, Neg};

use glium::{self, Display, Texture2d, Program, VertexBuffer};
use glium::{DrawParameters, BlendingFunction, LinearBlendingFactor};
use glium::Surface as SurfaceTrait;
use glium::index::{NoIndices, PrimitiveType};

use ui::{BB, Px};
use ui::color::Color;
use ui::text::FontFaces;

pub type Surface = glium::Frame;

#[derive(Copy, Clone)]
struct VertexXY {
    xy: [Px; 2]
}
implement_vertex!(VertexXY, xy);

#[derive(Copy, Clone)]
struct VertexUV {
    uv: [Px; 2]
}
implement_vertex!(VertexUV, uv);

const VERTEX_COUNT: usize = 256;

pub struct Renderer {
    data: Box<([VertexXY; VERTEX_COUNT], [VertexUV; VERTEX_COUNT])>,
    xy_buffer: VertexBuffer<VertexXY>,
    uv_buffer: VertexBuffer<VertexUV>,
    shader_color: Program,
    shader_texture: Program,
    pub fonts: FontFaces
}

impl Renderer {
    pub fn new(facade: &Display, fonts: FontFaces) -> Renderer {
        Renderer {
            data: box { ([VertexXY { xy: [0.0, 0.0] }; VERTEX_COUNT],
                         [VertexUV { uv: [0.0, 0.0] }; VERTEX_COUNT]) },
            xy_buffer: VertexBuffer::empty_dynamic(facade, VERTEX_COUNT).unwrap(),
            uv_buffer: VertexBuffer::empty_dynamic(facade, VERTEX_COUNT).unwrap(),
            shader_color: program! { facade, 100 => {
                vertex: "
                    #version 100
                    precision mediump float;

                    uniform vec4 color;
                    uniform vec2 scale;
                    attribute vec2 xy;
                    void main() {
                        gl_Position = vec4(xy * scale + vec2(-1.0, 1.0), 0.0, 1.0);
                    }",
                fragment: "
                    #version 100
                    precision mediump float;

                    uniform vec4 color;
                    void main() {
                        gl_FragColor = color;
                    }",
                outputs_srgb: true
            }}.unwrap(),
            shader_texture: program! { facade, 100 => {
                vertex: "
                    #version 100
                    precision mediump float;

                    uniform sampler2D s_texture;
                    uniform vec4 color;
                    uniform vec2 scale;
                    attribute vec2 xy;
                    attribute vec2 uv;
                    varying vec2 v_uv;
                    void main() {
                        v_uv = uv;
                        gl_Position = vec4(xy * scale + vec2(-1.0, 1.0), 0.0, 1.0);
                    }",
                fragment: "
                    #version 100
                    precision mediump float;

                    uniform sampler2D s_texture;
                    uniform vec4 color;
                    varying vec2 v_uv;
                    void main() {
                        gl_FragColor = texture2D(s_texture, v_uv) * color;
                    }",
                outputs_srgb: true
            }}.unwrap(),
            fonts: fonts
        }
    }

    fn scale(&self, surface: &Surface) -> [Px; 2] {
        let (w, h) = surface.get_dimensions();
        let (w, h) = (w as Px, h as Px);
        [2.0 / w, -2.0 / h]
    }

    pub fn clear(&mut self, surface: &mut Surface, [r, g, b, a]: Color) {
        surface.clear_color(r, g, b, a);
    }

    pub fn colored<F>(&mut self, surface: &mut Surface, color: Color, mut f: F)
        where F: FnMut((&mut [VertexXY; VERTEX_COUNT], &mut FnMut(&[VertexXY], PrimitiveType))) {

        let scale = self.scale(surface);
        let xy_buffer = &self.xy_buffer;
        let shader = &self.shader_color;

        f((&mut self.data.0, &mut |xy_data: &[VertexXY], ty| {
            let xys = xy_buffer.slice(0..xy_data.len()).unwrap();
            xys.write(xy_data);

            surface.draw(xys, &NoIndices(ty), shader,
                &uniform! {
                    color: color,
                    scale: scale
                },
                &DrawParameters {
                    blending_function: Some(BlendingFunction::Addition {
                        source: LinearBlendingFactor::SourceAlpha,
                        destination: LinearBlendingFactor::OneMinusSourceAlpha,
                    }),
                    .. Default::default()
                }
            ).unwrap();
        }))
    }

    pub fn textured<F>(&mut self, surface: &mut Surface, color: Color, texture: &Texture2d, mut f: F)
        where F: FnMut((&mut [VertexXY; VERTEX_COUNT],
                        &mut [VertexUV; VERTEX_COUNT],
                        &mut FnMut(&[VertexXY], &[VertexUV], PrimitiveType))) {

        let scale = self.scale(surface);
        let shader = &self.shader_texture;
        let (xy_buffer, uv_buffer) = (&self.xy_buffer, &self.uv_buffer);
        let (ref mut xy_data, ref mut uv_data) = *&mut *self.data;

        f((xy_data, uv_data,  &mut |xy_data: &[VertexXY], uv_data: &[VertexUV], ty| {
            let xys = xy_buffer.slice(0..xy_data.len()).unwrap();
            let uvs = uv_buffer.slice(0..uv_data.len()).unwrap();
            xys.write(xy_data);
            uvs.write(uv_data);

            surface.draw((xys, uvs), &NoIndices(ty), shader,
                &uniform! {
                    color: color,
                    scale: scale,
                    s_texture: texture
                },
                &DrawParameters {
                    blending_function: Some(BlendingFunction::Addition {
                        source: LinearBlendingFactor::SourceAlpha,
                        destination: LinearBlendingFactor::OneMinusSourceAlpha,
                    }),
                    .. Default::default()
                },
            ).unwrap();
        }))
    }
}

pub trait Buffer: Sized {
    type E: Copy + Sqrt +
            Neg<Output=Self::E> +
            Add<Output=Self::E> +
            Sub<Output=Self::E> +
            Mul<Px, Output=Self::E> +
            Mul<Output=Self::E> +
            Div<Output=Self::E>;

    fn vertex(&mut self, i: usize, vertex: [Self::E; 2]);
    fn flush(&mut self, n: usize, ty: PrimitiveType);
    fn flush_if_full(&mut self, n: usize, ty: PrimitiveType) -> bool;

    fn filled_polygon<I: Iterator<Item=[Self::E; 2]>>(&mut self, polygon: I) {
        let mut i = 0;
        for vertex in polygon {
            self.vertex(i, vertex);
            i += 1;

            if self.flush_if_full(i, PrimitiveType::TriangleFan) {
                // Preserve the first and last vertices.
                self.vertex(1, vertex);
                i = 2;
            }
        }
        self.flush(i, PrimitiveType::TriangleFan);
    }

    fn hollow_polygon<I: Iterator<Item=([Self::E; 2], [Self::E; 2])>>(&mut self, mut polygon: I) {
        let (a, b) = match polygon.next() { None => return, Some(x) => x };
        self.vertex(0, a);
        self.vertex(1, b);

        let mut i = 2;
        for (c, d) in polygon.chain(Some((a, b)).into_iter()) {
            self.vertex(i, c);
            self.vertex(i + 1, d);
            i += 2;

            if self.flush_if_full(i, PrimitiveType::TriangleStrip) {
                // Preserve the last two vertices.
                self.vertex(0, c);
                self.vertex(1, d);
                i = 2;
            }
        }
        self.flush(i, PrimitiveType::TriangleStrip);
    }

    fn line(mut self, from: [Self::E; 2], to: [Self::E; 2], width: Self::E) {
        let [x1, y1] = from;
        let [x2, y2] = to;
        let [lx, ly] = [x2 - x1, y2 - y1];
        let l = (lx * lx + ly * ly).sqrt();
        let scale = width * 0.5 / l;
        // Rotate by 90°.
        let dx = ly * scale;
        let dy = lx * -scale;
        self.filled_polygon([
            [x1 + dx, y1 + dy],
            [x1 - dx, y1 - dy],
            [x2 - dx, y2 - dy],
            [x2 + dx, y2 + dy]
        ].iter().cloned());
    }

    fn rect(mut self, bb: BB<Self::E>) {
        self.filled_polygon([
            bb.bottom_left(),
            bb.top_left(),
            bb.top_right(),
            bb.bottom_right()
        ].iter().cloned());
    }

    fn rect_border(mut self, bb: BB<Self::E>, border_size: Self::E) {
        let o = bb; // outer
        let i = bb.shrink(border_size); // inner
        self.hollow_polygon([
            (o.bottom_right(), i.bottom_right()),
            (o.bottom_left(), i.bottom_left()),
            (o.top_left(), i.top_left()),
            (o.top_right(), i.top_right())
        ].iter().cloned());
    }

    fn rect_round(mut self, bb: BB<Self::E>, resolution: u32, radius: Self::E) {
        let segment_rads = QUARTER_TAU / resolution as Px;
        let quarter = |i, [cx, cy]: [_; 2]| (0..resolution + 1).map(move |j| {
            let angle = (i as Px) * QUARTER_TAU + (j as Px) * segment_rads;
            [cx + radius * angle.cos(), cy + radius * angle.sin()]
        });
        let c = bb.shrink(radius);
        self.filled_polygon(quarter(0, c.bottom_right())
                     .chain(quarter(1, c.bottom_left()))
                     .chain(quarter(2, c.top_left()))
                     .chain(quarter(3, c.top_right())));
    }

    fn rect_border_round(mut self, bb: BB<Self::E>, border_size: Self::E, resolution: u32, radius: Self::E) {
        let segment_rads = QUARTER_TAU / resolution as Px;
        let inner = radius - border_size;
        let quarter = |i, [cx, cy]: [_; 2]| (0..resolution + 1).map(move |j| {
            let angle = (i as Px) * QUARTER_TAU + (j as Px) * segment_rads;
            let (cos, sin) = (angle.cos(), angle.sin());
            ([cx + radius * cos, cy + radius * sin],
             [cx + inner * cos,  cy + inner * sin])
        });
        let c = bb.shrink(radius);
        self.hollow_polygon(quarter(0, c.bottom_right())
                     .chain(quarter(1, c.bottom_left()))
                     .chain(quarter(2, c.top_left()))
                     .chain(quarter(3, c.top_right())));
    }
}

trait Sqrt {
    fn sqrt(self) -> Self;
}

impl Sqrt for Px {
    fn sqrt(self) -> Self {
        self.sqrt()
    }
}

impl<'a, F> Buffer for (&'a mut [VertexXY; VERTEX_COUNT], F)
    where F: FnMut(&[VertexXY], PrimitiveType) {

    type E = Px;

    #[inline(always)]
    fn vertex(&mut self, i: usize, xy: [Px; 2]) {
        self.0[i].xy = xy;
    }

    fn flush(&mut self, n: usize, ty: PrimitiveType) {
        if n >= 3 {
            self.1(&self.0[..n], ty);
        }
    }

    #[inline(always)]
    fn flush_if_full(&mut self, n: usize, ty: PrimitiveType) -> bool {
        if n >= VERTEX_COUNT {
            self.1(self.0, ty);
            true
        } else {
            false
        }
    }
}

#[derive(Copy, Clone)]
pub struct XYAndUV(pub Px, pub Px);

impl Add for XYAndUV {
    type Output = Self;
    fn add(self, other: Self) -> Self {
        XYAndUV(self.0 + other.0, self.1 + other.1)
    }
}
impl Mul<Px> for XYAndUV {
    type Output = Self;
    fn mul(self, x: Px) -> Self {
        XYAndUV(self.0 * x, self.1 * x)
    }
}
impl Mul for XYAndUV {
    type Output = Self;
    fn mul(self, other: Self) -> Self {
        XYAndUV(self.0 * other.0, self.1 * other.0)
    }
}
impl Div for XYAndUV {
    type Output = Self;
    fn div(self, other: Self) -> Self {
        XYAndUV(self.0 / other.0, self.1 / other.0)
    }
}
impl Sqrt for XYAndUV {
    fn sqrt(self) -> Self {
        XYAndUV(self.0.sqrt(), self.1.sqrt())
    }
}
impl Neg for XYAndUV { type Output = Self; fn neg(self) -> Self { self * -1.0 } }
impl Sub for XYAndUV { type Output = Self; fn sub(self, other: Self) -> Self { self + (-other) } }

impl<'a, 'b, F> Buffer for (&'a mut [VertexXY; VERTEX_COUNT], &'b mut [VertexUV; VERTEX_COUNT], F)
    where F: FnMut(&[VertexXY], &[VertexUV], PrimitiveType) {

    type E = XYAndUV;

    #[inline(always)]
    fn vertex(&mut self, i: usize, [XYAndUV(x, u), XYAndUV(y, v)]: [XYAndUV; 2]) {
        self.0[i].xy = [x, y];
        self.1[i].uv = [u, v];
    }

    fn flush(&mut self, n: usize, ty: PrimitiveType) {
        if n >= 3 {
            self.2(&self.0[..n], &self.1[..n], ty);
        }
    }

    #[inline(always)]
    fn flush_if_full(&mut self, n: usize, ty: PrimitiveType) -> bool {
        if n >= VERTEX_COUNT {
            self.2(self.0, self.1, ty);
            true
        } else {
            false
        }
    }
}
<|endoftext|>