<commit_before>use std::collections::HashMap;
use {RawFbx, FbxNode};

#[derive(Debug)]
pub enum FbxObject {
    Geometry(FbxGeometry),
    Model(FbxModel),
    /// Currently unsupported object type.
    NotSupported(String)
}

#[derive(Debug)]
pub struct FbxGeometry {
    pub id: i64,
    pub name: String,
    /// Vertices that make up the polygon.
    pub vertices: Vec<[f32; 3]>,
    /// Vertex indices that make up the polygons.
    pub polygons: Vec<Vec<u32>>,
    /// Normals for polygon vertices. Other normal types than "ByPolygonVertex", "Direct" not
    /// currently supported.
    pub normals: Vec<[f32; 3]>,
    /// UVs for polygon vertices. Other uv types than "ByPolygonVertex", "IndexToDirect" not
    /// currently supported.
    pub uvs: Vec<[f32; 2]>,
}

impl FbxGeometry {
    fn from_node(node: &FbxNode) -> Self {
        // Read in the vertex data, which is just stored in the sub-node "Vertices"
        let vert_node = node.find_child("Vertices").unwrap();
        let vertices = node_to_vector3s(vert_node);

        // Read in the indices
        let indi_node = node.find_child("PolygonVertexIndex").unwrap();
        let mut polygons = Vec::new();
        let mut cur_polygon = Vec::new();
        for val in indi_node.properties[0].get_vec_i32().unwrap().iter() {
            let mut val: i32 = *val;

            // If this one is negative we need to adjust it and that means this is end of the polygon
            let end = if val < 0 {
                val = -val-1;
                true
            } else { false };

            // Add it to the polygon
            cur_polygon.push(val as u32);

            // If this is the end, add this polygon to the list and create a new one
            if end {
                polygons.push(cur_polygon);
                cur_polygon = Vec::new();
            }
        }
        assert!(cur_polygon.len() == 0);

        // Read in the normals (only supports Direct)
        let norm_node = node.find_child("LayerElementNormal").unwrap();
        assert!(
            norm_node.find_child("MappingInformationType").unwrap()
                .properties[0].get_string().unwrap() == "ByPolygonVertex");
        assert!(
            norm_node.find_child("ReferenceInformationType").unwrap()
                .properties[0].get_string().unwrap() == "Direct");
        let norm_values_node = norm_node.find_child("Normals").unwrap();
        let normals = node_to_vector3s(norm_values_node);

        // Read in the uvs (only supports IndexToDirect)
        let uvs_node = node.find_child("LayerElementUV").unwrap();
        assert!(
            uvs_node.find_child("MappingInformationType").unwrap()
                .properties[0].get_string().unwrap() == "ByPolygonVertex");
        assert!(
            uvs_node.find_child("ReferenceInformationType").unwrap()
                .properties[0].get_string().unwrap() == "IndexToDirect");
        let uvs_raw = node_to_vector2s(uvs_node.find_child("UV").unwrap());
        let uvs_indices = uvs_node.find_child("UVIndex").unwrap().properties[0].get_vec_i32().unwrap();
        let mut uvs = Vec::new();
        for index in uvs_indices.iter() {
            uvs.push(uvs_raw[*index as usize]);
        }

        // Finish off the geometry type
        FbxGeometry {
            id: node.properties[0].get_i64().unwrap(),
            name: node.properties[1].get_string().unwrap().clone(),
            vertices: vertices,
            polygons: polygons,
            normals: normals,
            uvs: uvs,
        }
    }

    pub fn triangles(&self) -> Vec<[([f32; 3], [f32; 3], [f32; 2]); 3]> {
        // If our assumptions are right, normals and uvs should have the same amount of entries
        assert!(self.normals.len() == self.uvs.len());

        let mut triangles = Vec::new();

        // Go through all polygons
        for (poly_num, poly) in self.polygons.iter().enumerate() {
            // Make sure this is a triangle, our current method of getting the normals and uvs
            // doesn't make sense otherwise.
            assert!(poly.len() == 3); // TODO: Improve error handling

            // Go through the indices in this polygon
            let mut triangle: [([f32; 3], [f32; 3], [f32; 2]); 3] = Default::default();
            for (index_num, index) in poly.iter().enumerate() {
                triangle[index_num] = (
                    self.vertices[*index as usize],
                    self.normals[poly_num * 3 + index_num],
                    self.uvs[poly_num * 3 + index_num],
                );
            }
            triangles.push(triangle);
        }

        triangles
    }
}

fn node_to_vector3s(node: &FbxNode) -> Vec<[f32; 3]> {
    let mut vectors = Vec::new();

    for val in node.properties[0].get_vec_f32().unwrap().chunks(3) {
        assert!(val.len() == 3);
        vectors.push([val[0], val[1], val[2]]);
    }

    vectors
}

fn node_to_vector2s(node: &FbxNode) -> Vec<[f32; 2]> {
    let mut vectors = Vec::new();

    for val in node.properties[0].get_vec_f32().unwrap().chunks(2) {
        assert!(val.len() == 2);
        vectors.push([val[0], val[1]]);
    }

    vectors
}

#[derive(Debug)]
pub struct FbxModel {
    pub id: i64,
    pub name: String,
}

impl FbxModel {
    fn from_node(node: &FbxNode) -> Self {
        // Retrieve model parameter information
        let model = FbxModel {
            id: node.properties[0].get_i64().unwrap(),
            name: node.properties[1].get_string().unwrap().clone()
        };

        model
    }
}

/// Represents a connection within the FBX file. Connections are laid out (Child, Parent).
#[derive(Debug)]
pub enum FbxConnection {
    /// Object ID to Object ID connections.
    ObjectObject(i64, i64),
    /// Currently unsupported connection type.
    NotSupported(String),
}

#[derive(Debug)]
pub struct SimpleFbx {
    pub objects: HashMap<i64, FbxObject>,
    pub connections: Vec<FbxConnection>,
}

impl SimpleFbx {
    pub fn from_raw(fbx: &RawFbx) -> Self {
        SimpleFbx {
            objects: get_objects(fbx),
            connections: get_connections(fbx),
        }
    }

    /// Gets all objects that are linked as children of another object by the parent's id.
    pub fn children_of(&self, id: i64) -> Vec<&FbxObject> {
        let mut objs = Vec::new();

        // Go through all connections
        for connection in &self.connections {
            if let &FbxConnection::ObjectObject(child, parent) = connection {
                if parent == id {
                    // We've found one, look it up and add it
                    objs.push(&self.objects[&child])
                }
            }
        }

        objs
    }
}

fn get_objects(fbx: &RawFbx) -> HashMap<i64, FbxObject> {
    // Get the node for objects itself
    let objects = fbx.nodes.iter().find(|n| n.name == "Objects").unwrap();
    let mut objs_map = HashMap::new();

    // Go through all the nodes in there
    for node in &objects.nodes {
        // Send this node over to the appropriate converter
        match node.name.as_str() {
            "Geometry" => {
                let geom = FbxGeometry::from_node(node);
                objs_map.insert(geom.id, FbxObject::Geometry(geom));
            }
            "Model" => {
                let model = FbxModel::from_node(node);
                objs_map.insert(model.id, FbxObject::Model(model));
            },
            _ => {
                objs_map.insert(
                    node.properties[0].get_i64().unwrap(),
                    FbxObject::NotSupported(node.name.clone())
                );
            },
        }
    }

    objs_map
}

fn get_connections(fbx: &RawFbx) -> Vec<FbxConnection> {
    // Get the node for connections itself
    let connections = fbx.nodes.iter().find(|n| n.name == "Connections").unwrap();
    let mut con_vec = Vec::new();

    // Go through all the nodes in there
    for node in &connections.nodes {
        let con = match node.properties[0].get_string().unwrap().as_str() {
            "OO" => FbxConnection::ObjectObject(
                node.properties[1].get_i64().unwrap(),
                node.properties[2].get_i64().unwrap(),
            ),
            other => FbxConnection::NotSupported(other.to_string())
        };
        con_vec.push(con);
    }

    con_vec
}
<commit_msg>Work in progress support for transforms<commit_after>use std::collections::HashMap;
use {RawFbx, FbxNode};

#[derive(Debug)]
pub enum FbxObject {
    Geometry(FbxGeometry),
    Model(FbxModel),
    /// Currently unsupported object type.
    NotSupported(String)
}

#[derive(Debug)]
pub struct FbxGeometry {
    pub id: i64,
    pub name: String,
    /// Vertices that make up the polygon.
    pub vertices: Vec<[f32; 3]>,
    /// Vertex indices that make up the polygons.
    pub polygons: Vec<Vec<u32>>,
    /// Normals for polygon vertices. Other normal types than "ByPolygonVertex", "Direct" not
    /// currently supported.
    pub normals: Vec<[f32; 3]>,
    /// UVs for polygon vertices. Other uv types than "ByPolygonVertex", "IndexToDirect" not
    /// currently supported.
    pub uvs: Vec<[f32; 2]>,
}

impl FbxGeometry {
    fn from_node(node: &FbxNode) -> Self {
        // Read in the vertex data, which is just stored in the sub-node "Vertices"
        let vert_node = node.find_child("Vertices").unwrap();
        let vertices = node_to_vector3s(vert_node);

        // Read in the indices
        let indi_node = node.find_child("PolygonVertexIndex").unwrap();
        let mut polygons = Vec::new();
        let mut cur_polygon = Vec::new();
        for val in indi_node.properties[0].get_vec_i32().unwrap().iter() {
            let mut val: i32 = *val;

            // If this one is negative we need to adjust it and that means this is end of the polygon
            let end = if val < 0 {
                val = -val-1;
                true
            } else { false };

            // Add it to the polygon
            cur_polygon.push(val as u32);

            // If this is the end, add this polygon to the list and create a new one
            if end {
                polygons.push(cur_polygon);
                cur_polygon = Vec::new();
            }
        }
        assert!(cur_polygon.len() == 0);

        // Read in the normals (only supports Direct)
        let norm_node = node.find_child("LayerElementNormal").unwrap();
        assert!(
            norm_node.find_child("MappingInformationType").unwrap()
                .properties[0].get_string().unwrap() == "ByPolygonVertex");
        assert!(
            norm_node.find_child("ReferenceInformationType").unwrap()
                .properties[0].get_string().unwrap() == "Direct");
        let norm_values_node = norm_node.find_child("Normals").unwrap();
        let normals = node_to_vector3s(norm_values_node);

        // Read in the uvs (only supports IndexToDirect)
        let uvs_node = node.find_child("LayerElementUV").unwrap();
        assert!(
            uvs_node.find_child("MappingInformationType").unwrap()
                .properties[0].get_string().unwrap() == "ByPolygonVertex");
        assert!(
            uvs_node.find_child("ReferenceInformationType").unwrap()
                .properties[0].get_string().unwrap() == "IndexToDirect");
        let uvs_raw = node_to_vector2s(uvs_node.find_child("UV").unwrap());
        let uvs_indices = uvs_node.find_child("UVIndex").unwrap().properties[0].get_vec_i32().unwrap();
        let mut uvs = Vec::new();
        for index in uvs_indices.iter() {
            uvs.push(uvs_raw[*index as usize]);
        }

        // Finish off the geometry type
        FbxGeometry {
            id: node.properties[0].get_i64().unwrap(),
            name: node.properties[1].get_string().unwrap().clone(),
            vertices: vertices,
            polygons: polygons,
            normals: normals,
            uvs: uvs,
        }
    }

    pub fn triangles(&self) -> Vec<[([f32; 3], [f32; 3], [f32; 2]); 3]> {
        // If our assumptions are right, normals and uvs should have the same amount of entries
        assert!(self.normals.len() == self.uvs.len());

        let mut triangles = Vec::new();

        // Go through all polygons
        for (poly_num, poly) in self.polygons.iter().enumerate() {
            // Make sure this is a triangle, our current method of getting the normals and uvs
            // doesn't make sense otherwise.
            assert!(poly.len() == 3); // TODO: Improve error handling

            // Go through the indices in this polygon
            let mut triangle: [([f32; 3], [f32; 3], [f32; 2]); 3] = Default::default();
            for (index_num, index) in poly.iter().enumerate() {
                triangle[index_num] = (
                    self.vertices[*index as usize],
                    self.normals[poly_num * 3 + index_num],
                    self.uvs[poly_num * 3 + index_num],
                );
            }
            triangles.push(triangle);
        }

        triangles
    }
}

fn node_to_vector3s(node: &FbxNode) -> Vec<[f32; 3]> {
    let mut vectors = Vec::new();

    for val in node.properties[0].get_vec_f32().unwrap().chunks(3) {
        assert!(val.len() == 3);
        vectors.push([val[0], val[1], val[2]]);
    }

    vectors
}

fn node_to_vector2s(node: &FbxNode) -> Vec<[f32; 2]> {
    let mut vectors = Vec::new();

    for val in node.properties[0].get_vec_f32().unwrap().chunks(2) {
        assert!(val.len() == 2);
        vectors.push([val[0], val[1]]);
    }

    vectors
}

#[derive(Debug)]
pub struct FbxModel {
    pub id: i64,
    pub name: String,
    pub translation: [f32; 3],
}

impl FbxModel {
    fn from_node(node: &FbxNode) -> Self {
        // Find the translation in the model
        let translation: [f32; 3] = Default::default();

        // Retrieve model parameter information
        let model = FbxModel {
            id: node.properties[0].get_i64().unwrap(),
            name: node.properties[1].get_string().unwrap().clone(),
            translation: translation,
        };

        model
    }
}

/// Represents a connection within the FBX file. Connections are laid out (Child, Parent).
#[derive(Debug)]
pub enum FbxConnection {
    /// Object ID to Object ID connections.
    ObjectObject(i64, i64),
    /// Currently unsupported connection type.
    NotSupported(String),
}

#[derive(Debug)]
pub struct SimpleFbx {
    pub objects: HashMap<i64, FbxObject>,
    pub connections: Vec<FbxConnection>,
}

impl SimpleFbx {
    pub fn from_raw(fbx: &RawFbx) -> Self {
        SimpleFbx {
            objects: get_objects(fbx),
            connections: get_connections(fbx),
        }
    }

    /// Gets all objects that are linked as children of another object by the parent's id.
    pub fn children_of(&self, id: i64) -> Vec<&FbxObject> {
        let mut objs = Vec::new();

        // Go through all connections
        for connection in &self.connections {
            if let &FbxConnection::ObjectObject(child, parent) = connection {
                if parent == id {
                    // We've found one, look it up and add it
                    objs.push(&self.objects[&child])
                }
            }
        }

        objs
    }
}

fn get_objects(fbx: &RawFbx) -> HashMap<i64, FbxObject> {
    // Get the node for objects itself
    let objects = fbx.nodes.iter().find(|n| n.name == "Objects").unwrap();
    let mut objs_map = HashMap::new();

    // Go through all the nodes in there
    for node in &objects.nodes {
        // Send this node over to the appropriate converter
        match node.name.as_str() {
            "Geometry" => {
                let geom = FbxGeometry::from_node(node);
                objs_map.insert(geom.id, FbxObject::Geometry(geom));
            }
            "Model" => {
                let model = FbxModel::from_node(node);
                objs_map.insert(model.id, FbxObject::Model(model));
            },
            _ => {
                objs_map.insert(
                    node.properties[0].get_i64().unwrap(),
                    FbxObject::NotSupported(node.name.clone())
                );
            },
        }
    }

    objs_map
}

fn get_connections(fbx: &RawFbx) -> Vec<FbxConnection> {
    // Get the node for connections itself
    let connections = fbx.nodes.iter().find(|n| n.name == "Connections").unwrap();
    let mut con_vec = Vec::new();

    // Go through all the nodes in there
    for node in &connections.nodes {
        let con = match node.properties[0].get_string().unwrap().as_str() {
            "OO" => FbxConnection::ObjectObject(
                node.properties[1].get_i64().unwrap(),
                node.properties[2].get_i64().unwrap(),
            ),
            other => FbxConnection::NotSupported(other.to_string())
        };
        con_vec.push(con);
    }

    con_vec
}
<|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/.

// Functions for dealing with device mapper names.

use std::fmt;
use std::fmt::Display;

use devicemapper::{DmNameBuf, DmUuidBuf};

use super::super::super::engine::{FilesystemUuid, PoolUuid};

const FORMAT_VERSION: u16 = 1;

#[derive(Clone, Copy)]
pub enum FlexRole {
    MetadataVolume,
    ThinData,
    ThinMeta,
    ThinMetaSpare,
}

impl Display for FlexRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            FlexRole::MetadataVolume => write!(f, "mdv"),
            FlexRole::ThinData => write!(f, "thindata"),
            FlexRole::ThinMeta => write!(f, "thinmeta"),
            FlexRole::ThinMetaSpare => write!(f, "thinmetaspare"),
        }
    }
}

#[derive(Clone, Copy)]
pub enum ThinRole {
    Filesystem(FilesystemUuid),
}

impl Display for ThinRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ThinRole::Filesystem(uuid) => write!(f, "fs-{}", uuid.simple().to_string()),
        }
    }
}

#[derive(Clone, Copy)]
pub enum ThinPoolRole {
    Pool,
}

impl Display for ThinPoolRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ThinPoolRole::Pool => write!(f, "pool"),
        }
    }
}

/// The various roles taken on by DM devices in the cache tier.
#[derive(Clone, Copy)]
pub enum CacheRole {
    /// The DM cache device, contains the other three devices.
    #[allow(dead_code)]
    Cache,
    /// The cache sub-device of the DM cache device.
    #[allow(dead_code)]
    CacheSub,
    /// The meta sub-device of the DM cache device.
    #[allow(dead_code)]
    MetaSub,
    /// The origin sub-device of the DM cache device, holds the actual data.
    OriginSub,
}

impl Display for CacheRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CacheRole::Cache => write!(f, "cache"),
            CacheRole::CacheSub => write!(f, "cachesub"),
            CacheRole::MetaSub => write!(f, "metasub"),
            CacheRole::OriginSub => write!(f, "originsub"),
        }
    }
}

/// Format a name & uuid for the flex layer.
/// Prerequisite: len(format!("{}", FORMAT_VERSION)) < 72
pub fn format_flex_ids(pool_uuid: PoolUuid, role: FlexRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!("stratis-{}-{}-flex-{}",
                        FORMAT_VERSION,
                        pool_uuid.simple().to_string(),
                        role);
    (DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display length < 72"),
     DmUuidBuf::new(value).expect("FORMAT_VERSION display length < 73"))

}

/// Format a name & uuid for the thin layer.
/// Prerequisite: len(format!("{}", FORMAT_VERSION)) < 50
pub fn format_thin_ids(pool_uuid: PoolUuid, role: ThinRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!("stratis-{}-{}-thin-{}",
                        FORMAT_VERSION,
                        pool_uuid.simple().to_string(),
                        role);
    (DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display length < 50"),
     DmUuidBuf::new(value).expect("FORMAT_VERSION display length < 51"))
}

/// Format a name & uuid for the thin pool layer.
/// Prerequisite: len(format!("{}", FORMAT_VERSION)) < 81
pub fn format_thinpool_ids(pool_uuid: PoolUuid, role: ThinPoolRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!("stratis-{}-{}-thinpool-{}",
                        FORMAT_VERSION,
                        pool_uuid.simple().to_string(),
                        role);
    (DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display_length < 81"),
     DmUuidBuf::new(value).expect("FORMAT_VERSION display_length < 82"))
}

/// Format a name & uuid for dm devices in the backstore.
/// Prerequisite: len(format!("{}", FORMAT_VERSION) < 76
pub fn format_backstore_ids(pool_uuid: PoolUuid, role: CacheRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!("stratis-{}-{}-physical-{}",
                        FORMAT_VERSION,
                        pool_uuid.simple().to_string(),
                        role);
    (DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display_length < 76"),
     DmUuidBuf::new(value).expect("FORMAT_VERSION display_length < 77"))
}
<commit_msg>Formalize prerequisites about length of FORMAT_VERSION<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/.

// Functions for dealing with device mapper names.

use std::fmt;
use std::fmt::Display;

use devicemapper::{DmNameBuf, DmUuidBuf};

use super::super::super::engine::{FilesystemUuid, PoolUuid};

const FORMAT_VERSION: u16 = 1;

#[derive(Clone, Copy)]
pub enum FlexRole {
    MetadataVolume,
    ThinData,
    ThinMeta,
    ThinMetaSpare,
}

impl Display for FlexRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            FlexRole::MetadataVolume => write!(f, "mdv"),
            FlexRole::ThinData => write!(f, "thindata"),
            FlexRole::ThinMeta => write!(f, "thinmeta"),
            FlexRole::ThinMetaSpare => write!(f, "thinmetaspare"),
        }
    }
}

#[derive(Clone, Copy)]
pub enum ThinRole {
    Filesystem(FilesystemUuid),
}

impl Display for ThinRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ThinRole::Filesystem(uuid) => write!(f, "fs-{}", uuid.simple().to_string()),
        }
    }
}

#[derive(Clone, Copy)]
pub enum ThinPoolRole {
    Pool,
}

impl Display for ThinPoolRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ThinPoolRole::Pool => write!(f, "pool"),
        }
    }
}

/// The various roles taken on by DM devices in the cache tier.
#[derive(Clone, Copy)]
pub enum CacheRole {
    /// The DM cache device, contains the other three devices.
    #[allow(dead_code)]
    Cache,
    /// The cache sub-device of the DM cache device.
    #[allow(dead_code)]
    CacheSub,
    /// The meta sub-device of the DM cache device.
    #[allow(dead_code)]
    MetaSub,
    /// The origin sub-device of the DM cache device, holds the actual data.
    OriginSub,
}

impl Display for CacheRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CacheRole::Cache => write!(f, "cache"),
            CacheRole::CacheSub => write!(f, "cachesub"),
            CacheRole::MetaSub => write!(f, "metasub"),
            CacheRole::OriginSub => write!(f, "originsub"),
        }
    }
}

/// Format a name & uuid for the flex layer.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
///             + len("stratis")                         7
///             + len("flex")                            4
///             + num_dashes                             4
///             + len(pool uuid)                         32
///             + max(len(FlexRole))                     13
///             < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 68 (69 for UUID)
pub fn format_flex_ids(pool_uuid: PoolUuid, role: FlexRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!("stratis-{}-{}-flex-{}",
                        FORMAT_VERSION,
                        pool_uuid.simple().to_string(),
                        role);
    (DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display length < 68"),
     DmUuidBuf::new(value).expect("FORMAT_VERSION display length < 69"))

}

/// Format a name & uuid for the thin layer.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
///             + len("stratis")                         7
///             + len("thin")                            4
///             + num_dashes                             4
///             + len(pool uuid)                         32
///             + max(len(ThinRole))                     35
///             < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 46 (47 for UUID)
pub fn format_thin_ids(pool_uuid: PoolUuid, role: ThinRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!("stratis-{}-{}-thin-{}",
                        FORMAT_VERSION,
                        pool_uuid.simple().to_string(),
                        role);
    (DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display length < 46"),
     DmUuidBuf::new(value).expect("FORMAT_VERSION display length < 47"))
}

/// Format a name & uuid for the thin pool layer.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
///             + len("stratis")                         7
///             + len("thinpool")                        8
///             + num_dashes                             4
///             + len(pool uuid)                         32
///             + max(len(ThinPoolRole))                 4
///             < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 73 (74 for UUID)
pub fn format_thinpool_ids(pool_uuid: PoolUuid, role: ThinPoolRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!("stratis-{}-{}-thinpool-{}",
                        FORMAT_VERSION,
                        pool_uuid.simple().to_string(),
                        role);
    (DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display_length < 73"),
     DmUuidBuf::new(value).expect("FORMAT_VERSION display_length < 74"))
}

/// Format a name & uuid for dm devices in the backstore.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
///             + len("stratis")                         7
///             + len("physical")                        8
///             + num_dashes                             4
///             + len(pool uuid)                         32
///             + max(len(CacheRole))                    9
///             < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 68 (69 for UUID)
pub fn format_backstore_ids(pool_uuid: PoolUuid, role: CacheRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!("stratis-{}-{}-physical-{}",
                        FORMAT_VERSION,
                        pool_uuid.simple().to_string(),
                        role);
    (DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display_length < 68"),
     DmUuidBuf::new(value).expect("FORMAT_VERSION display_length < 69"))
}
<|endoftext|>


<commit_before>//! Requires the "cache", "methods", and "voice" features be enabled in your
//! Cargo.toml, like so:
//!
//! ```toml
//! [dependencies.serenity]
//! version = "*"
//! features = ["cache", "framework", "voice"]
//! ```

#[macro_use]
extern crate serenity;

use serenity::client::{CACHE, Client};
use serenity::ext::voice;
use serenity::model::{ChannelId, Message, Mentionable};
use serenity::Result as SerenityResult;
use std::env;

fn main() {
    // Configure the client with your Discord bot token in the environment.
    let token = env::var("DISCORD_TOKEN")
        .expect("Expected a token in the environment");
    let mut client = Client::login_bot(&token);

    client.with_framework(|f| f
        .configure(|c| c
            .prefix("~")
            .on_mention(true))
        .on("deafen", deafen)
        .on("join", join)
        .on("leave", leave)
        .on("mute", mute)
        .on("play", play)
        .on("ping", ping)
        .on("undeafen", undeafen)
        .on("unmute", unmute));

    client.on_ready(|_context, ready| {
        println!("{} is connected!", ready.user.name);
    });

    let _ = client.start().map_err(|why| println!("Client ended: {:?}", why));
}

command!(deafen(context, message) {
    let guild_id = match CACHE.read().unwrap().get_guild_channel(message.channel_id) {
        Some(channel) => channel.read().unwrap().guild_id,
        None => {
            check_msg(context.say("Groups and DMs not supported"));

            return Ok(());
        },
    };

    let mut shard = context.shard.lock().unwrap();

    let handler = match shard.manager.get(guild_id) {
        Some(handler) => handler,
        None => {
            check_msg(message.reply("Not in a voice channel"));

            return Ok(());
        },
    };

    if handler.is_deafened() {
        check_msg(context.say("Already deafened"));
    } else {
        handler.deafen(true);

        check_msg(context.say("Deafened"));
    }
});

command!(join(context, message, args) {
    let connect_to = match args.get(0) {
        Some(arg) => match arg.parse::<u64>() {
            Ok(id) => ChannelId(id),
            Err(_why) => {
                check_msg(message.reply("Invalid voice channel ID given"));

                return Ok(());
            },
        },
        None => {
            check_msg(message.reply("Requires a voice channel ID be given"));

            return Ok(());
        },
    };

    let guild_id = match CACHE.read().unwrap().get_guild_channel(message.channel_id) {
        Some(channel) => channel.read().unwrap().guild_id,
        None => {
            check_msg(context.say("Groups and DMs not supported"));

            return Ok(());
        },
    };

    let mut shard = context.shard.lock().unwrap();
    shard.manager.join(Some(guild_id), connect_to);

    check_msg(context.say(&format!("Joined {}", connect_to.mention())));
});

command!(leave(context, message) {
    let guild_id = match CACHE.read().unwrap().get_guild_channel(message.channel_id) {
        Some(channel) => channel.read().unwrap().guild_id,
        None => {
            check_msg(context.say("Groups and DMs not supported"));

            return Ok(());
        },
    };

    let mut shard = context.shard.lock().unwrap();
    let has_handler = shard.manager.get(guild_id).is_some();

    if has_handler {
        shard.manager.remove(guild_id);

        check_msg(context.say("Left voice channel"));
    } else {
        check_msg(message.reply("Not in a voice channel"));
    }
});

command!(mute(context, message) {
    let guild_id = match CACHE.read().unwrap().get_guild_channel(message.channel_id) {
        Some(channel) => channel.read().unwrap().guild_id,
        None => {
            check_msg(context.say("Groups and DMs not supported"));

            return Ok(());
        },
    };

    let mut shard = context.shard.lock().unwrap();

    let handler = match shard.manager.get(guild_id) {
        Some(handler) => handler,
        None => {
            check_msg(message.reply("Not in a voice channel"));

            return Ok(());
        },
    };

    if handler.is_muted() {
        check_msg(context.say("Already muted"));
    } else {
        handler.mute(true);

        check_msg(context.say("Now muted"));
    }
});

command!(ping(context) {
    check_msg(context.say("Pong!"));
});

command!(play(context, message, args) {
    let url = match args.get(0) {
        Some(url) => url,
        None => {
            check_msg(context.say("Must provide a URL to a video or audio"));

            return Ok(());
        },
    };

    if !url.starts_with("http") {
        check_msg(context.say("Must provide a valid URL"));

        return Ok(());
    }

    let guild_id = match CACHE.read().unwrap().get_guild_channel(message.channel_id) {
        Some(channel) => channel.read().unwrap().guild_id,
        None => {
            check_msg(context.say("Error finding channel info"));

            return Ok(());
        },
    };

    if let Some(handler) = context.shard.lock().unwrap().manager.get(guild_id) {
        let source = match voice::ytdl(url) {
            Ok(source) => source,
            Err(why) => {
                println!("Err starting source: {:?}", why);

                check_msg(context.say("Error sourcing ffmpeg"));

                return Ok(());
            },
        };

        handler.play(source);

        check_msg(context.say("Playing song"));
    } else {
        check_msg(context.say("Not in a voice channel to play in"));
    }
});

command!(undeafen(context, message) {
    let guild_id = match CACHE.read().unwrap().get_guild_channel(message.channel_id) {
        Some(channel) => channel.read().unwrap().guild_id,
        None => {
            check_msg(context.say("Error finding channel info"));

            return Ok(());
        },
    };

    if let Some(handler) = context.shard.lock().unwrap().manager.get(guild_id) {
        handler.deafen(false);

        check_msg(context.say("Undeafened"));
    } else {
        check_msg(context.say("Not in a voice channel to undeafen in"));
    }
});

command!(unmute(context, message) {
    let guild_id = match CACHE.read().unwrap().get_guild_channel(message.channel_id) {
        Some(channel) => channel.read().unwrap().guild_id,
        None => {
            check_msg(context.say("Error finding channel info"));

            return Ok(());
        },
    };

    if let Some(handler) = context.shard.lock().unwrap().manager.get(guild_id) {
        handler.mute(false);

        check_msg(context.say("Unmuted"));
    } else {
        check_msg(context.say("Not in a voice channel to undeafen in"));
    }
});

/// Checks that a message successfully sent; if not, then logs why to stdout.
fn check_msg(result: SerenityResult<Message>) {
    if let Err(why) = result {
        println!("Error sending message: {:?}", why);
    }
}
<commit_msg>Update voice example to latest changes<commit_after>//! Requires the "cache", "methods", and "voice" features be enabled in your
//! Cargo.toml, like so:
//!
//! ```toml
//! [dependencies.serenity]
//! version = "*"
//! features = ["cache", "framework", "voice"]
//! ```

#[macro_use]
extern crate serenity;

use serenity::client::{CACHE, Client};
use serenity::ext::voice;
use serenity::model::{ChannelId, Message, Mentionable};
use serenity::Result as SerenityResult;
use std::env;

fn main() {
    // Configure the client with your Discord bot token in the environment.
    let token = env::var("DISCORD_TOKEN")
        .expect("Expected a token in the environment");
    let mut client = Client::login_bot(&token);

    client.with_framework(|f| f
        .configure(|c| c
            .prefix("~")
            .on_mention(true))
        .on("deafen", deafen)
        .on("join", join)
        .on("leave", leave)
        .on("mute", mute)
        .on("play", play)
        .on("ping", ping)
        .on("undeafen", undeafen)
        .on("unmute", unmute));

    client.on_ready(|_context, ready| {
        println!("{} is connected!", ready.user.name);
    });

    let _ = client.start().map_err(|why| println!("Client ended: {:?}", why));
}

command!(deafen(context, message) {
    let guild_id = match CACHE.read().unwrap().get_guild_channel(message.channel_id) {
        Some(channel) => channel.read().unwrap().guild_id,
        None => {
            check_msg(context.say("Groups and DMs not supported"));

            return Ok(());
        },
    };

    let mut shard = context.shard.lock().unwrap();

    let handler = match shard.manager.get(guild_id) {
        Some(handler) => handler,
        None => {
            check_msg(message.reply("Not in a voice channel"));

            return Ok(());
        },
    };

    if handler.self_deaf {
        check_msg(context.say("Already deafened"));
    } else {
        handler.deafen(true);

        check_msg(context.say("Deafened"));
    }
});

command!(join(context, message, args) {
    let connect_to = match args.get(0) {
        Some(arg) => match arg.parse::<u64>() {
            Ok(id) => ChannelId(id),
            Err(_why) => {
                check_msg(message.reply("Invalid voice channel ID given"));

                return Ok(());
            },
        },
        None => {
            check_msg(message.reply("Requires a voice channel ID be given"));

            return Ok(());
        },
    };

    let guild_id = match CACHE.read().unwrap().get_guild_channel(message.channel_id) {
        Some(channel) => channel.read().unwrap().guild_id,
        None => {
            check_msg(context.say("Groups and DMs not supported"));

            return Ok(());
        },
    };

    let mut shard = context.shard.lock().unwrap();
    shard.manager.join(Some(guild_id), connect_to);

    check_msg(context.say(&format!("Joined {}", connect_to.mention())));
});

command!(leave(context, message) {
    let guild_id = match CACHE.read().unwrap().get_guild_channel(message.channel_id) {
        Some(channel) => channel.read().unwrap().guild_id,
        None => {
            check_msg(context.say("Groups and DMs not supported"));

            return Ok(());
        },
    };

    let mut shard = context.shard.lock().unwrap();
    let has_handler = shard.manager.get(guild_id).is_some();

    if has_handler {
        shard.manager.remove(guild_id);

        check_msg(context.say("Left voice channel"));
    } else {
        check_msg(message.reply("Not in a voice channel"));
    }
});

command!(mute(context, message) {
    let guild_id = match CACHE.read().unwrap().get_guild_channel(message.channel_id) {
        Some(channel) => channel.read().unwrap().guild_id,
        None => {
            check_msg(context.say("Groups and DMs not supported"));

            return Ok(());
        },
    };

    let mut shard = context.shard.lock().unwrap();

    let handler = match shard.manager.get(guild_id) {
        Some(handler) => handler,
        None => {
            check_msg(message.reply("Not in a voice channel"));

            return Ok(());
        },
    };

    if handler.self_mute {
        check_msg(context.say("Already muted"));
    } else {
        handler.mute(true);

        check_msg(context.say("Now muted"));
    }
});

command!(ping(context) {
    check_msg(context.say("Pong!"));
});

command!(play(context, message, args) {
    let url = match args.get(0) {
        Some(url) => url,
        None => {
            check_msg(context.say("Must provide a URL to a video or audio"));

            return Ok(());
        },
    };

    if !url.starts_with("http") {
        check_msg(context.say("Must provide a valid URL"));

        return Ok(());
    }

    let guild_id = match CACHE.read().unwrap().get_guild_channel(message.channel_id) {
        Some(channel) => channel.read().unwrap().guild_id,
        None => {
            check_msg(context.say("Error finding channel info"));

            return Ok(());
        },
    };

    if let Some(handler) = context.shard.lock().unwrap().manager.get(guild_id) {
        let source = match voice::ytdl(url) {
            Ok(source) => source,
            Err(why) => {
                println!("Err starting source: {:?}", why);

                check_msg(context.say("Error sourcing ffmpeg"));

                return Ok(());
            },
        };

        handler.play(source);

        check_msg(context.say("Playing song"));
    } else {
        check_msg(context.say("Not in a voice channel to play in"));
    }
});

command!(undeafen(context, message) {
    let guild_id = match CACHE.read().unwrap().get_guild_channel(message.channel_id) {
        Some(channel) => channel.read().unwrap().guild_id,
        None => {
            check_msg(context.say("Error finding channel info"));

            return Ok(());
        },
    };

    if let Some(handler) = context.shard.lock().unwrap().manager.get(guild_id) {
        handler.deafen(false);

        check_msg(context.say("Undeafened"));
    } else {
        check_msg(context.say("Not in a voice channel to undeafen in"));
    }
});

command!(unmute(context, message) {
    let guild_id = match CACHE.read().unwrap().get_guild_channel(message.channel_id) {
        Some(channel) => channel.read().unwrap().guild_id,
        None => {
            check_msg(context.say("Error finding channel info"));

            return Ok(());
        },
    };

    if let Some(handler) = context.shard.lock().unwrap().manager.get(guild_id) {
        handler.mute(false);

        check_msg(context.say("Unmuted"));
    } else {
        check_msg(context.say("Not in a voice channel to undeafen in"));
    }
});

/// Checks that a message successfully sent; if not, then logs why to stdout.
fn check_msg(result: SerenityResult<Message>) {
    if let Err(why) = result {
        println!("Error sending message: {:?}", why);
    }
}
<|endoftext|>


<commit_before>//! Exposes the `Ingot` trait which must be implemented by
//! all middleware.

use super::response::Response;
use super::request::Request;
use super::alloy::Alloy;

/// The Status returned by `Ingot's` `enter` and `exit` methods. This indicates
/// to the `Furnace` whether this is a terminal `Ingot` or whether to continue
/// passing the `Request` and `Response` down the `Furnace's` stack.
///
/// Most `Furnaces` will ignore the returned `Status` from the `exit` method of
/// `Ingots`.
pub enum Status {
    /// `Continue` indicates that this is an intermediate `Ingot` in the stack
    /// and the `Furnace` should continue passing requests down the `Furnace's`
    /// stack.
    ///
    /// Most `Ingots` will return `Continue` from both `enter` and `exit`.
    Continue,

    /// `Unwind` indicates that this is a terminal `Ingot` or something went
    /// wrong. It can be used to immediately stop passing requests down the
    /// `Furnace's` stack and start calling `exit` of all previous `Ingots`.
    ///
    /// For instance, an authorization `Ingot` might return `Unwind` if the
    /// request fails an authentication check, and `Continue` otherwise.
    Unwind
}

/// All middleware should implement `Ingot`, which allows it to be `smelted`
/// to a `Furnace` so that it will be called for each incoming request.
///
/// There are two sorts of data associated with `Ingots`, data internal
/// to the `Ingot` and data that the `Ingot` would like to expose to `Ingots`
/// further down the stack or terminal controllers.
///
/// Internal data should be stored on the `struct` that implements `Ingot`
/// itself. All `Ingots` are cloned for each client request, so the object
/// initially smelted on to the `Iron` instance will be provided as `&self` to
/// enter for every request. Data stored on `Ingot` instances does _not_ persist
/// between requests and is _not_ shared between different, concurrent, requests.
/// The same is true for data stored on `Alloys`.
///
/// External data should be stored in the `Alloy` passed to both `enter` and
/// `exit`. `Alloy` is a thin wrapper around `AnyMap` and is effectively a
/// a key value store from a type to an instance of that type. This means
/// that each `Ingot` can have a unique type that it stores in the `Alloy`.
/// This can either be an instance of that `Ingot` or some other type. Since
/// the same `Alloy` is passed to all further `Ingots` in the `Furnace`, this
/// scheme allows you to expose data or functionality to future `Ingots`.
pub trait Ingot<Rq: Request, Rs: Response>: Send + Clone {
    /// `enter` is called for each `Ingot` in a `Furnace` as a client request
    /// comes down the stack. `Ingots` should expose data through `Alloy` and
    /// store any data that will persist through the request here.
    ///
    /// returning `Unwind` from this handler will cause the `Furnace` to stop
    /// going down the `Furnace's` stack and start bubbling back up and calling
    /// `exit`.
    fn enter(&mut self, _request: &mut Rq, _response: &mut Rs, _alloy: &mut Alloy) -> Status {
        Continue
    }

    /// `exit` is called for each `Ingot` in `Furnace` that has had it's `enter`
    /// method called for this request. `Ingot's``exit` method will be called
    /// as the stack is unwound in FILO order. `Ingots` have their `exit`
    /// methods called in opposite order from which `enter` was called, which
    /// is FIFO.
    ///
    /// While this method must return a `Status`, most `Furnaces` will ignore
    /// this method's return value.
    fn exit(&mut self, _request: &mut Rq, _response: &mut Rs, _alloy: &mut Alloy) -> Status {
        Continue
    }

    fn clone_box(&self) -> Box<Ingot<Rq, Rs>> { box self.clone() as Box<Ingot<Rq, Rs>> }
}

impl<Rq: Request, Rs: Response> Clone for Box<Ingot<Rq, Rs>> {
    fn clone(&self) -> Box<Ingot<Rq, Rs>> { self.clone_box() }
}
<commit_msg>(refactor) Refactored Ingot with Request and Response types.<commit_after>//! Exposes the `Ingot` trait which must be implemented by
//! all middleware.

use super::response::Response;
use super::request::Request;
use super::alloy::Alloy;

/// The Status returned by `Ingot's` `enter` and `exit` methods. This indicates
/// to the `Furnace` whether this is a terminal `Ingot` or whether to continue
/// passing the `Request` and `Response` down the `Furnace's` stack.
///
/// Most `Furnaces` will ignore the returned `Status` from the `exit` method of
/// `Ingots`.
pub enum Status {
    /// `Continue` indicates that this is an intermediate `Ingot` in the stack
    /// and the `Furnace` should continue passing requests down the `Furnace's`
    /// stack.
    ///
    /// Most `Ingots` will return `Continue` from both `enter` and `exit`.
    Continue,

    /// `Unwind` indicates that this is a terminal `Ingot` or something went
    /// wrong. It can be used to immediately stop passing requests down the
    /// `Furnace's` stack and start calling `exit` of all previous `Ingots`.
    ///
    /// For instance, an authorization `Ingot` might return `Unwind` if the
    /// request fails an authentication check, and `Continue` otherwise.
    Unwind
}

/// All middleware should implement `Ingot`, which allows it to be `smelted`
/// to a `Furnace` so that it will be called for each incoming request.
///
/// There are two sorts of data associated with `Ingots`, data internal
/// to the `Ingot` and data that the `Ingot` would like to expose to `Ingots`
/// further down the stack or terminal controllers.
///
/// Internal data should be stored on the `struct` that implements `Ingot`
/// itself. All `Ingots` are cloned for each client request, so the object
/// initially smelted on to the `Iron` instance will be provided as `&self` to
/// enter for every request. Data stored on `Ingot` instances does _not_ persist
/// between requests and is _not_ shared between different, concurrent, requests.
/// The same is true for data stored on `Alloys`.
///
/// External data should be stored in the `Alloy` passed to both `enter` and
/// `exit`. `Alloy` is a thin wrapper around `AnyMap` and is effectively a
/// a key value store from a type to an instance of that type. This means
/// that each `Ingot` can have a unique type that it stores in the `Alloy`.
/// This can either be an instance of that `Ingot` or some other type. Since
/// the same `Alloy` is passed to all further `Ingots` in the `Furnace`, this
/// scheme allows you to expose data or functionality to future `Ingots`.
pub trait Ingot: Send + Clone {
    /// `enter` is called for each `Ingot` in a `Furnace` as a client request
    /// comes down the stack. `Ingots` should expose data through `Alloy` and
    /// store any data that will persist through the request here.
    ///
    /// returning `Unwind` from this handler will cause the `Furnace` to stop
    /// going down the `Furnace's` stack and start bubbling back up and calling
    /// `exit`.
    fn enter(&mut self,
             _request: &mut Request,
             _response: &mut Response,
             _alloy: &mut Alloy) -> Status {
        Continue
    }

    /// `exit` is called for each `Ingot` in `Furnace` that has had it's `enter`
    /// method called for this request. `Ingot's``exit` method will be called
    /// as the stack is unwound in FILO order. `Ingots` have their `exit`
    /// methods called in opposite order from which `enter` was called, which
    /// is FIFO.
    ///
    /// While this method must return a `Status`, most `Furnaces` will ignore
    /// this method's return value.
    fn exit(&mut self,
            _request: &mut Request,
            _response: &mut Response,
            _alloy: &mut Alloy) -> Status {
        Continue
    }

    fn clone_box(&self) -> Box<Ingot> { box self.clone() as Box<Ingot> }
}

impl Clone for Box<Ingot> {
    fn clone(&self) -> Box<Ingot> { self.clone_box() }
}
<|endoftext|>


<commit_before>fn main() {
    // In general, the `{}` will be automatically replaced with any
    // arguments. These will be stringified.
    println!("{} days", 31);

    // Without a suffix, 31 becomes an i32. You can change what type 31 is,
    // with a suffix.

    // There are various optional patterns this works with. Positional
    // arguments can be used.
    println!("{0}, this is {1}. {1}, this is {0}", "Alice", "Bob");

    // As can named arguments.
    println!("{subject} {verb} {predicate}",
             predicate="over the lazy dog",
             subject="the quick brown fox",
             verb="jumps");

    // Special formatting can be specified after a `:`.
    println!("{} of {:b} people know binary, the other half don't", 1, 2);

    // It will even check to make sure the correct number of arguments are
    // used.
    println!("My name is {0}, {1} {0}", "Bond");
    // FIXME ^ Add the missing argument: "James"

    // Create a structure which contains an `i32`. Name it `Structure`.
    struct Structure(i32);

    // However, custom types such as this structure require more complicated
    // handling. This will not work.
    println!("This struct `{}` won't print...", Structure(3));
    // FIXME ^ Comment out this line.
}
<commit_msg>Add alignment and fill examples in 1.2 Formatted print<commit_after>fn main() {
    // In general, the `{}` will be automatically replaced with any
    // arguments. These will be stringified.
    println!("{} days", 31);

    // Without a suffix, 31 becomes an i32. You can change what type 31 is,
    // with a suffix.

    // There are various optional patterns this works with. Positional
    // arguments can be used.
    println!("{0}, this is {1}. {1}, this is {0}", "Alice", "Bob");

    // As can named arguments.
    println!("{subject} {verb} {predicate}",
             predicate="over the lazy dog",
             subject="the quick brown fox",
             verb="jumps");

    // Special formatting can be specified after a `:`.
    println!("{} of {:b} people know binary, the other half don't", 1, 2);

    // You can right-align text with a specified width. This will output
    // "     1". 5 white spaces and a "1".
    println!("{number:>width$}",
             number=1,
             width=6);

    // You can pad numbers with extra zeroes. This will output "000001".
    println!("{number:>0width$}",
             number=1,
             width=6);

    // It will even check to make sure the correct number of arguments are
    // used.
    println!("My name is {0}, {1} {0}", "Bond");
    // FIXME ^ Add the missing argument: "James"

    // Create a structure which contains an `i32`. Name it `Structure`.
    struct Structure(i32);

    // However, custom types such as this structure require more complicated
    // handling. This will not work.
    println!("This struct `{}` won't print...", Structure(3));
    // FIXME ^ Comment out this line.
}
<|endoftext|>


<commit_before>use crate::iter::{DoubleEndedIterator, FusedIterator, Iterator, TrustedLen};
use crate::ops::Try;
use crate::usize;

/// An iterator that links two iterators together, in a chain.
///
/// This `struct` is created by the [`chain`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`chain`]: trait.Iterator.html#method.chain
/// [`Iterator`]: trait.Iterator.html
#[derive(Clone, Debug)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Chain<A, B> {
    // These are "fused" with `Option` so we don't need separate state to track which part is
    // already exhausted, and we may also get niche layout for `None`. We don't use the real `Fuse`
    // adapter because its specialization for `FusedIterator` unconditionally descends into the
    // iterator, and that could be expensive to keep revisiting stuff like nested chains. It also
    // hurts compiler performance to add more iterator layers to `Chain`.
    a: Option<A>,
    b: Option<B>,
}
impl<A, B> Chain<A, B> {
    pub(in super::super) fn new(a: A, b: B) -> Chain<A, B> {
        Chain { a: Some(a), b: Some(b) }
    }
}

/// Fuse the iterator if the expression is `None`.
macro_rules! fuse {
    ($self:ident . $iter:ident . $($call:tt)+) => {
        match $self.$iter {
            Some(ref mut iter) => match iter.$($call)+ {
                None => {
                    $self.$iter = None;
                    None
                }
                item => item,
            },
            None => None,
        }
    };
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A, B> Iterator for Chain<A, B>
where
    A: Iterator,
    B: Iterator<Item = A::Item>,
{
    type Item = A::Item;

    #[inline]
    fn next(&mut self) -> Option<A::Item> {
        match fuse!(self.a.next()) {
            None => fuse!(self.b.next()),
            item => item,
        }
    }

    #[inline]
    #[rustc_inherit_overflow_checks]
    fn count(self) -> usize {
        let a_count = match self.a {
            Some(a) => a.count(),
            None => 0,
        };
        let b_count = match self.b {
            Some(b) => b.count(),
            None => 0,
        };
        a_count + b_count
    }

    fn try_fold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R
    where
        Self: Sized,
        F: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        if let Some(ref mut a) = self.a {
            acc = a.try_fold(acc, &mut f)?;
            self.a = None;
        }
        if let Some(ref mut b) = self.b {
            acc = b.try_fold(acc, &mut f)?;
            self.b = None;
        }
        Try::from_ok(acc)
    }

    fn fold<Acc, F>(self, mut acc: Acc, mut f: F) -> Acc
    where
        F: FnMut(Acc, Self::Item) -> Acc,
    {
        if let Some(a) = self.a {
            acc = a.fold(acc, &mut f);
        }
        if let Some(b) = self.b {
            acc = b.fold(acc, &mut f);
        }
        acc
    }

    #[inline]
    fn nth(&mut self, mut n: usize) -> Option<A::Item> {
        if let Some(ref mut a) = self.a {
            while let Some(x) = a.next() {
                if n == 0 {
                    return Some(x);
                }
                n -= 1;
            }
            self.a = None;
        }
        fuse!(self.b.nth(n))
    }

    #[inline]
    fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item>
    where
        P: FnMut(&Self::Item) -> bool,
    {
        match fuse!(self.a.find(&mut predicate)) {
            None => fuse!(self.b.find(predicate)),
            item => item,
        }
    }

    #[inline]
    fn last(self) -> Option<A::Item> {
        // Must exhaust a before b.
        let a_last = match self.a {
            Some(a) => a.last(),
            None => None,
        };
        let b_last = match self.b {
            Some(b) => b.last(),
            None => None,
        };
        b_last.or(a_last)
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        match self {
            Chain { a: Some(a), b: Some(b) } => {
                let (a_lower, a_upper) = a.size_hint();
                let (b_lower, b_upper) = b.size_hint();

                let lower = a_lower.saturating_add(b_lower);

                let upper = match (a_upper, b_upper) {
                    (Some(x), Some(y)) => x.checked_add(y),
                    _ => None,
                };

                (lower, upper)
            }
            Chain { a: Some(a), b: None } => a.size_hint(),
            Chain { a: None, b: Some(b) } => b.size_hint(),
            Chain { a: None, b: None } => (0, Some(0)),
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A, B> DoubleEndedIterator for Chain<A, B>
where
    A: DoubleEndedIterator,
    B: DoubleEndedIterator<Item = A::Item>,
{
    #[inline]
    fn next_back(&mut self) -> Option<A::Item> {
        match fuse!(self.b.next_back()) {
            None => fuse!(self.a.next_back()),
            item => item,
        }
    }

    #[inline]
    fn nth_back(&mut self, mut n: usize) -> Option<A::Item> {
        if let Some(ref mut b) = self.b {
            while let Some(x) = b.next_back() {
                if n == 0 {
                    return Some(x);
                }
                n -= 1;
            }
            self.b = None;
        }
        fuse!(self.a.nth_back(n))
    }

    #[inline]
    fn rfind<P>(&mut self, mut predicate: P) -> Option<Self::Item>
    where
        P: FnMut(&Self::Item) -> bool,
    {
        match fuse!(self.b.rfind(&mut predicate)) {
            None => fuse!(self.a.rfind(predicate)),
            item => item,
        }
    }

    fn try_rfold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R
    where
        Self: Sized,
        F: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        if let Some(ref mut b) = self.b {
            acc = b.try_rfold(acc, &mut f)?;
            self.b = None;
        }
        if let Some(ref mut a) = self.a {
            acc = a.try_rfold(acc, f)?;
            self.a = None;
        }
        Try::from_ok(acc)
    }

    fn rfold<Acc, F>(self, mut acc: Acc, mut f: F) -> Acc
    where
        F: FnMut(Acc, Self::Item) -> Acc,
    {
        if let Some(b) = self.b {
            acc = b.rfold(acc, &mut f);
        }
        if let Some(a) = self.a {
            acc = a.rfold(acc, f);
        }
        acc
    }
}

// Note: *both* must be fused to handle double-ended iterators.
// Now that we "fuse" both sides, we *could* implement this unconditionally,
// but we should be cautious about committing to that in the public API.
#[stable(feature = "fused", since = "1.26.0")]
impl<A, B> FusedIterator for Chain<A, B>
where
    A: FusedIterator,
    B: FusedIterator<Item = A::Item>,
{
}

#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<A, B> TrustedLen for Chain<A, B>
where
    A: TrustedLen,
    B: TrustedLen<Item = A::Item>,
{
}
<commit_msg>Avoid extra &mut in Chain::fold and try_fold<commit_after>use crate::iter::{DoubleEndedIterator, FusedIterator, Iterator, TrustedLen};
use crate::ops::Try;
use crate::usize;

/// An iterator that links two iterators together, in a chain.
///
/// This `struct` is created by the [`chain`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`chain`]: trait.Iterator.html#method.chain
/// [`Iterator`]: trait.Iterator.html
#[derive(Clone, Debug)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Chain<A, B> {
    // These are "fused" with `Option` so we don't need separate state to track which part is
    // already exhausted, and we may also get niche layout for `None`. We don't use the real `Fuse`
    // adapter because its specialization for `FusedIterator` unconditionally descends into the
    // iterator, and that could be expensive to keep revisiting stuff like nested chains. It also
    // hurts compiler performance to add more iterator layers to `Chain`.
    a: Option<A>,
    b: Option<B>,
}
impl<A, B> Chain<A, B> {
    pub(in super::super) fn new(a: A, b: B) -> Chain<A, B> {
        Chain { a: Some(a), b: Some(b) }
    }
}

/// Fuse the iterator if the expression is `None`.
macro_rules! fuse {
    ($self:ident . $iter:ident . $($call:tt)+) => {
        match $self.$iter {
            Some(ref mut iter) => match iter.$($call)+ {
                None => {
                    $self.$iter = None;
                    None
                }
                item => item,
            },
            None => None,
        }
    };
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A, B> Iterator for Chain<A, B>
where
    A: Iterator,
    B: Iterator<Item = A::Item>,
{
    type Item = A::Item;

    #[inline]
    fn next(&mut self) -> Option<A::Item> {
        match fuse!(self.a.next()) {
            None => fuse!(self.b.next()),
            item => item,
        }
    }

    #[inline]
    #[rustc_inherit_overflow_checks]
    fn count(self) -> usize {
        let a_count = match self.a {
            Some(a) => a.count(),
            None => 0,
        };
        let b_count = match self.b {
            Some(b) => b.count(),
            None => 0,
        };
        a_count + b_count
    }

    fn try_fold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R
    where
        Self: Sized,
        F: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        if let Some(ref mut a) = self.a {
            acc = a.try_fold(acc, &mut f)?;
            self.a = None;
        }
        if let Some(ref mut b) = self.b {
            acc = b.try_fold(acc, f)?;
            self.b = None;
        }
        Try::from_ok(acc)
    }

    fn fold<Acc, F>(self, mut acc: Acc, mut f: F) -> Acc
    where
        F: FnMut(Acc, Self::Item) -> Acc,
    {
        if let Some(a) = self.a {
            acc = a.fold(acc, &mut f);
        }
        if let Some(b) = self.b {
            acc = b.fold(acc, f);
        }
        acc
    }

    #[inline]
    fn nth(&mut self, mut n: usize) -> Option<A::Item> {
        if let Some(ref mut a) = self.a {
            while let Some(x) = a.next() {
                if n == 0 {
                    return Some(x);
                }
                n -= 1;
            }
            self.a = None;
        }
        fuse!(self.b.nth(n))
    }

    #[inline]
    fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item>
    where
        P: FnMut(&Self::Item) -> bool,
    {
        match fuse!(self.a.find(&mut predicate)) {
            None => fuse!(self.b.find(predicate)),
            item => item,
        }
    }

    #[inline]
    fn last(self) -> Option<A::Item> {
        // Must exhaust a before b.
        let a_last = match self.a {
            Some(a) => a.last(),
            None => None,
        };
        let b_last = match self.b {
            Some(b) => b.last(),
            None => None,
        };
        b_last.or(a_last)
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        match self {
            Chain { a: Some(a), b: Some(b) } => {
                let (a_lower, a_upper) = a.size_hint();
                let (b_lower, b_upper) = b.size_hint();

                let lower = a_lower.saturating_add(b_lower);

                let upper = match (a_upper, b_upper) {
                    (Some(x), Some(y)) => x.checked_add(y),
                    _ => None,
                };

                (lower, upper)
            }
            Chain { a: Some(a), b: None } => a.size_hint(),
            Chain { a: None, b: Some(b) } => b.size_hint(),
            Chain { a: None, b: None } => (0, Some(0)),
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A, B> DoubleEndedIterator for Chain<A, B>
where
    A: DoubleEndedIterator,
    B: DoubleEndedIterator<Item = A::Item>,
{
    #[inline]
    fn next_back(&mut self) -> Option<A::Item> {
        match fuse!(self.b.next_back()) {
            None => fuse!(self.a.next_back()),
            item => item,
        }
    }

    #[inline]
    fn nth_back(&mut self, mut n: usize) -> Option<A::Item> {
        if let Some(ref mut b) = self.b {
            while let Some(x) = b.next_back() {
                if n == 0 {
                    return Some(x);
                }
                n -= 1;
            }
            self.b = None;
        }
        fuse!(self.a.nth_back(n))
    }

    #[inline]
    fn rfind<P>(&mut self, mut predicate: P) -> Option<Self::Item>
    where
        P: FnMut(&Self::Item) -> bool,
    {
        match fuse!(self.b.rfind(&mut predicate)) {
            None => fuse!(self.a.rfind(predicate)),
            item => item,
        }
    }

    fn try_rfold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R
    where
        Self: Sized,
        F: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        if let Some(ref mut b) = self.b {
            acc = b.try_rfold(acc, &mut f)?;
            self.b = None;
        }
        if let Some(ref mut a) = self.a {
            acc = a.try_rfold(acc, f)?;
            self.a = None;
        }
        Try::from_ok(acc)
    }

    fn rfold<Acc, F>(self, mut acc: Acc, mut f: F) -> Acc
    where
        F: FnMut(Acc, Self::Item) -> Acc,
    {
        if let Some(b) = self.b {
            acc = b.rfold(acc, &mut f);
        }
        if let Some(a) = self.a {
            acc = a.rfold(acc, f);
        }
        acc
    }
}

// Note: *both* must be fused to handle double-ended iterators.
// Now that we "fuse" both sides, we *could* implement this unconditionally,
// but we should be cautious about committing to that in the public API.
#[stable(feature = "fused", since = "1.26.0")]
impl<A, B> FusedIterator for Chain<A, B>
where
    A: FusedIterator,
    B: FusedIterator<Item = A::Item>,
{
}

#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<A, B> TrustedLen for Chain<A, B>
where
    A: TrustedLen,
    B: TrustedLen<Item = A::Item>,
{
}
<|endoftext|>


<commit_before>//! This module contains the `EvalContext` methods for executing a single step of the interpreter.
//!
//! The main entry point is the `step` method.

use rustc::hir::def_id::DefId;
use rustc::hir;
use rustc::mir::visit::{Visitor, LvalueContext};
use rustc::mir;
use rustc::traits::Reveal;
use rustc::ty;
use rustc::ty::layout::Layout;
use rustc::ty::subst::Substs;

use super::{
    EvalResult, EvalError,
    EvalContext, StackPopCleanup, TyAndPacked,
    Global, GlobalId, Lvalue,
    Value, PrimVal,
    HasMemory,
    Machine,
};

use syntax::codemap::Span;
use syntax::ast::Mutability;

impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
    pub fn inc_step_counter_and_check_limit(&mut self, n: u64) -> EvalResult<'tcx> {
        self.steps_remaining = self.steps_remaining.saturating_sub(n);
        if self.steps_remaining > 0 {
            Ok(())
        } else {
            Err(EvalError::ExecutionTimeLimitReached)
        }
    }

    /// Returns true as long as there are more things to do.
    pub fn step(&mut self) -> EvalResult<'tcx, bool> {
        self.inc_step_counter_and_check_limit(1)?;
        if self.stack.is_empty() {
            return Ok(false);
        }

        let block = self.frame().block;
        let stmt_id = self.frame().stmt;
        let mir = self.mir();
        let basic_block = &mir.basic_blocks()[block];

        if let Some(stmt) = basic_block.statements.get(stmt_id) {
            let mut new = Ok(0);
            ConstantExtractor {
                span: stmt.source_info.span,
                instance: self.frame().instance,
                ecx: self,
                mir,
                new_constants: &mut new,
            }.visit_statement(block, stmt, mir::Location { block, statement_index: stmt_id });
            // if ConstantExtractor added new frames, we don't execute anything here
            // but await the next call to step
            if new? == 0 {
                self.statement(stmt)?;
            }
            return Ok(true);
        }

        let terminator = basic_block.terminator();
        let mut new = Ok(0);
        ConstantExtractor {
            span: terminator.source_info.span,
            instance: self.frame().instance,
            ecx: self,
            mir,
            new_constants: &mut new,
        }.visit_terminator(block, terminator, mir::Location { block, statement_index: stmt_id });
        // if ConstantExtractor added new frames, we don't execute anything here
        // but await the next call to step
        if new? == 0 {
            self.terminator(terminator)?;
        }
        Ok(true)
    }

    fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<'tcx> {
        trace!("{:?}", stmt);

        use rustc::mir::StatementKind::*;
        match stmt.kind {
            Assign(ref lvalue, ref rvalue) => self.eval_rvalue_into_lvalue(rvalue, lvalue)?,

            SetDiscriminant { ref lvalue, variant_index } => {
                let dest = self.eval_lvalue(lvalue)?;
                let dest_ty = self.lvalue_ty(lvalue);
                let dest_layout = self.type_layout(dest_ty)?;

                match *dest_layout {
                    Layout::General { discr, .. } => {
                        let discr_size = discr.size().bytes();
                        let dest_ptr = self.force_allocation(dest)?.to_ptr()?;
                        self.memory.write_uint(dest_ptr, variant_index as u128, discr_size)?
                    }

                    Layout::RawNullablePointer { nndiscr, .. } => {
                        if variant_index as u64 != nndiscr {
                            self.write_null(dest, dest_ty)?;
                        }
                    }

                    Layout::StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
                        if variant_index as u64 != nndiscr {
                            let (offset, TyAndPacked { ty, packed }) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?;
                            let nonnull = self.force_allocation(dest)?.to_ptr()?.offset(offset.bytes(), &self)?;
                            trace!("struct wrapped nullable pointer type: {}", ty);
                            // only the pointer part of a fat pointer is used for this space optimization
                            let discr_size = self.type_size(ty)?.expect("bad StructWrappedNullablePointer discrfield");
                            self.write_maybe_aligned_mut(!packed, |ectx| ectx.memory.write_uint(nonnull, 0, discr_size))?;
                        }
                    },

                    _ => bug!("SetDiscriminant on {} represented as {:#?}", dest_ty, dest_layout),
                }
            }

            // Mark locals as dead or alive.
            StorageLive(ref lvalue) | StorageDead(ref lvalue)=> {
                let (frame, local) = match self.eval_lvalue(lvalue)? {
                    Lvalue::Local{ frame, local } if self.cur_frame() == frame => (frame, local),
                    _ => return Err(EvalError::Unimplemented("Storage annotations must refer to locals of the topmost stack frame.".to_owned())) // FIXME maybe this should get its own error type
                };
                let old_val = match stmt.kind {
                    StorageLive(_) => self.stack[frame].storage_live(local)?,
                    StorageDead(_) =>  self.stack[frame].storage_dead(local)?,
                    _ => bug!("We already checked that we are a storage stmt")
                };
                self.deallocate_local(old_val)?;
            }

            // NOPs for now.
            EndRegion(_ce) => {}

            // Defined to do nothing. These are added by optimization passes, to avoid changing the
            // size of MIR constantly.
            Nop => {}

            InlineAsm { .. } => return Err(EvalError::InlineAsm),
        }

        self.frame_mut().stmt += 1;
        Ok(())
    }

    fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> EvalResult<'tcx> {
        trace!("{:?}", terminator.kind);
        self.eval_terminator(terminator)?;
        if !self.stack.is_empty() {
            trace!("// {:?}", self.frame().block);
        }
        Ok(())
    }

    /// returns `true` if a stackframe was pushed
    fn global_item(
        &mut self,
        def_id: DefId,
        substs: &'tcx Substs<'tcx>,
        span: Span,
        mutability: Mutability,
    ) -> EvalResult<'tcx, bool> {
        let instance = self.resolve_associated_const(def_id, substs);
        let cid = GlobalId { instance, promoted: None };
        if self.globals.contains_key(&cid) {
            return Ok(false);
        }
        if self.tcx.has_attr(def_id, "linkage") {
            // FIXME: check that it's `#[linkage = "extern_weak"]`
            trace!("Initializing an extern global with NULL");
            self.globals.insert(cid, Global::initialized(self.tcx.type_of(def_id), Value::ByVal(PrimVal::Bytes(0)), mutability));
            return Ok(false);
        }
        let mir = self.load_mir(instance.def)?;
        self.globals.insert(cid, Global::uninitialized(mir.return_ty));
        let internally_mutable = !mir.return_ty.is_freeze(
                self.tcx,
                ty::ParamEnv::empty(Reveal::All),
                span);
        let mutability = if mutability == Mutability::Mutable || internally_mutable {
            Mutability::Mutable
        } else {
            Mutability::Immutable
        };
        let cleanup = StackPopCleanup::MarkStatic(mutability);
        let name = ty::tls::with(|tcx| tcx.item_path_str(def_id));
        trace!("pushing stack frame for global: {}", name);
        self.push_stack_frame(
            instance,
            span,
            mir,
            Lvalue::Global(cid),
            cleanup,
        )?;
        Ok(true)
    }
}

// WARNING: make sure that any methods implemented on this type don't ever access ecx.stack
// this includes any method that might access the stack
// basically don't call anything other than `load_mir`, `alloc_ptr`, `push_stack_frame`
// The reason for this is, that `push_stack_frame` modifies the stack out of obvious reasons
struct ConstantExtractor<'a, 'b: 'a, 'tcx: 'b, M: Machine<'tcx> + 'a> {
    span: Span,
    ecx: &'a mut EvalContext<'b, 'tcx, M>,
    mir: &'tcx mir::Mir<'tcx>,
    instance: ty::Instance<'tcx>,
    new_constants: &'a mut EvalResult<'tcx, u64>,
}

impl<'a, 'b, 'tcx, M: Machine<'tcx>> ConstantExtractor<'a, 'b, 'tcx, M> {
    fn try<F: FnOnce(&mut Self) -> EvalResult<'tcx, bool>>(&mut self, f: F) {
        // previous constant errored
        let n = match *self.new_constants {
            Ok(n) => n,
            Err(_) => return,
        };
        match f(self) {
            // everything ok + a new stackframe
            Ok(true) => *self.new_constants = Ok(n + 1),
            // constant correctly evaluated, but no new stackframe
            Ok(false) => {},
            // constant eval errored
            Err(err) => *self.new_constants = Err(err),
        }
    }
}

impl<'a, 'b, 'tcx, M: Machine<'tcx>> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx, M> {
    fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: mir::Location) {
        self.super_constant(constant, location);
        match constant.literal {
            // already computed by rustc
            mir::Literal::Value { .. } => {}
            mir::Literal::Item { def_id, substs } => {
                self.try(|this| this.ecx.global_item(def_id, substs, constant.span, Mutability::Immutable));
            },
            mir::Literal::Promoted { index } => {
                let cid = GlobalId {
                    instance: self.instance,
                    promoted: Some(index),
                };
                if self.ecx.globals.contains_key(&cid) {
                    return;
                }
                let mir = &self.mir.promoted[index];
                self.try(|this| {
                    let ty = this.ecx.monomorphize(mir.return_ty, this.instance.substs);
                    this.ecx.globals.insert(cid, Global::uninitialized(ty));
                    trace!("pushing stack frame for {:?}", index);
                    this.ecx.push_stack_frame(this.instance,
                                              constant.span,
                                              mir,
                                              Lvalue::Global(cid),
                                              StackPopCleanup::MarkStatic(Mutability::Immutable),
                    )?;
                    Ok(true)
                });
            }
        }
    }

    fn visit_lvalue(
        &mut self,
        lvalue: &mir::Lvalue<'tcx>,
        context: LvalueContext<'tcx>,
        location: mir::Location
    ) {
        self.super_lvalue(lvalue, context, location);
        if let mir::Lvalue::Static(ref static_) = *lvalue {
            let def_id = static_.def_id;
            let substs = self.ecx.tcx.intern_substs(&[]);
            let span = self.span;
            if let Some(node_item) = self.ecx.tcx.hir.get_if_local(def_id) {
                if let hir::map::Node::NodeItem(&hir::Item { ref node, .. }) = node_item {
                    if let hir::ItemStatic(_, m, _) = *node {
                        self.try(|this| this.ecx.global_item(def_id, substs, span, if m == hir::MutMutable { Mutability::Mutable } else { Mutability::Immutable }));
                        return;
                    } else {
                        bug!("static def id doesn't point to static");
                    }
                } else {
                    bug!("static def id doesn't point to item");
                }
            } else {
                let def = self.ecx.tcx.describe_def(def_id).expect("static not found");
                if let hir::def::Def::Static(_, mutable) = def {
                    self.try(|this| this.ecx.global_item(def_id, substs, span, if mutable { Mutability::Mutable } else { Mutability::Immutable }));
                } else {
                    bug!("static found but isn't a static: {:?}", def);
                }
            }
        }
    }
}
<commit_msg>step.rs: improve comment for clarity<commit_after>//! This module contains the `EvalContext` methods for executing a single step of the interpreter.
//!
//! The main entry point is the `step` method.

use rustc::hir::def_id::DefId;
use rustc::hir;
use rustc::mir::visit::{Visitor, LvalueContext};
use rustc::mir;
use rustc::traits::Reveal;
use rustc::ty;
use rustc::ty::layout::Layout;
use rustc::ty::subst::Substs;

use super::{
    EvalResult, EvalError,
    EvalContext, StackPopCleanup, TyAndPacked,
    Global, GlobalId, Lvalue,
    Value, PrimVal,
    HasMemory,
    Machine,
};

use syntax::codemap::Span;
use syntax::ast::Mutability;

impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
    pub fn inc_step_counter_and_check_limit(&mut self, n: u64) -> EvalResult<'tcx> {
        self.steps_remaining = self.steps_remaining.saturating_sub(n);
        if self.steps_remaining > 0 {
            Ok(())
        } else {
            Err(EvalError::ExecutionTimeLimitReached)
        }
    }

    /// Returns true as long as there are more things to do.
    pub fn step(&mut self) -> EvalResult<'tcx, bool> {
        self.inc_step_counter_and_check_limit(1)?;
        if self.stack.is_empty() {
            return Ok(false);
        }

        let block = self.frame().block;
        let stmt_id = self.frame().stmt;
        let mir = self.mir();
        let basic_block = &mir.basic_blocks()[block];

        if let Some(stmt) = basic_block.statements.get(stmt_id) {
            let mut new = Ok(0);
            ConstantExtractor {
                span: stmt.source_info.span,
                instance: self.frame().instance,
                ecx: self,
                mir,
                new_constants: &mut new,
            }.visit_statement(block, stmt, mir::Location { block, statement_index: stmt_id });
            // if ConstantExtractor added new frames, we don't execute anything here
            // but await the next call to step
            if new? == 0 {
                self.statement(stmt)?;
            }
            return Ok(true);
        }

        let terminator = basic_block.terminator();
        let mut new = Ok(0);
        ConstantExtractor {
            span: terminator.source_info.span,
            instance: self.frame().instance,
            ecx: self,
            mir,
            new_constants: &mut new,
        }.visit_terminator(block, terminator, mir::Location { block, statement_index: stmt_id });
        // if ConstantExtractor added new frames, we don't execute anything here
        // but await the next call to step
        if new? == 0 {
            self.terminator(terminator)?;
        }
        Ok(true)
    }

    fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<'tcx> {
        trace!("{:?}", stmt);

        use rustc::mir::StatementKind::*;
        match stmt.kind {
            Assign(ref lvalue, ref rvalue) => self.eval_rvalue_into_lvalue(rvalue, lvalue)?,

            SetDiscriminant { ref lvalue, variant_index } => {
                let dest = self.eval_lvalue(lvalue)?;
                let dest_ty = self.lvalue_ty(lvalue);
                let dest_layout = self.type_layout(dest_ty)?;

                match *dest_layout {
                    Layout::General { discr, .. } => {
                        let discr_size = discr.size().bytes();
                        let dest_ptr = self.force_allocation(dest)?.to_ptr()?;
                        self.memory.write_uint(dest_ptr, variant_index as u128, discr_size)?
                    }

                    Layout::RawNullablePointer { nndiscr, .. } => {
                        if variant_index as u64 != nndiscr {
                            self.write_null(dest, dest_ty)?;
                        }
                    }

                    Layout::StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
                        if variant_index as u64 != nndiscr {
                            let (offset, TyAndPacked { ty, packed }) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?;
                            let nonnull = self.force_allocation(dest)?.to_ptr()?.offset(offset.bytes(), &self)?;
                            trace!("struct wrapped nullable pointer type: {}", ty);
                            // only the pointer part of a fat pointer is used for this space optimization
                            let discr_size = self.type_size(ty)?.expect("bad StructWrappedNullablePointer discrfield");
                            self.write_maybe_aligned_mut(!packed, |ectx| ectx.memory.write_uint(nonnull, 0, discr_size))?;
                        }
                    },

                    _ => bug!("SetDiscriminant on {} represented as {:#?}", dest_ty, dest_layout),
                }
            }

            // Mark locals as dead or alive.
            StorageLive(ref lvalue) | StorageDead(ref lvalue)=> {
                let (frame, local) = match self.eval_lvalue(lvalue)? {
                    Lvalue::Local{ frame, local } if self.cur_frame() == frame => (frame, local),
                    _ => return Err(EvalError::Unimplemented("Storage annotations must refer to locals of the topmost stack frame.".to_owned())) // FIXME maybe this should get its own error type
                };
                let old_val = match stmt.kind {
                    StorageLive(_) => self.stack[frame].storage_live(local)?,
                    StorageDead(_) =>  self.stack[frame].storage_dead(local)?,
                    _ => bug!("We already checked that we are a storage stmt")
                };
                self.deallocate_local(old_val)?;
            }

            // NOPs for now.
            EndRegion(_ce) => {}

            // Defined to do nothing. These are added by optimization passes, to avoid changing the
            // size of MIR constantly.
            Nop => {}

            InlineAsm { .. } => return Err(EvalError::InlineAsm),
        }

        self.frame_mut().stmt += 1;
        Ok(())
    }

    fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> EvalResult<'tcx> {
        trace!("{:?}", terminator.kind);
        self.eval_terminator(terminator)?;
        if !self.stack.is_empty() {
            trace!("// {:?}", self.frame().block);
        }
        Ok(())
    }

    /// returns `true` if a stackframe was pushed
    fn global_item(
        &mut self,
        def_id: DefId,
        substs: &'tcx Substs<'tcx>,
        span: Span,
        mutability: Mutability,
    ) -> EvalResult<'tcx, bool> {
        let instance = self.resolve_associated_const(def_id, substs);
        let cid = GlobalId { instance, promoted: None };
        if self.globals.contains_key(&cid) {
            return Ok(false);
        }
        if self.tcx.has_attr(def_id, "linkage") {
            // FIXME: check that it's `#[linkage = "extern_weak"]`
            trace!("Initializing an extern global with NULL");
            self.globals.insert(cid, Global::initialized(self.tcx.type_of(def_id), Value::ByVal(PrimVal::Bytes(0)), mutability));
            return Ok(false);
        }
        let mir = self.load_mir(instance.def)?;
        self.globals.insert(cid, Global::uninitialized(mir.return_ty));
        let internally_mutable = !mir.return_ty.is_freeze(
                self.tcx,
                ty::ParamEnv::empty(Reveal::All),
                span);
        let mutability = if mutability == Mutability::Mutable || internally_mutable {
            Mutability::Mutable
        } else {
            Mutability::Immutable
        };
        let cleanup = StackPopCleanup::MarkStatic(mutability);
        let name = ty::tls::with(|tcx| tcx.item_path_str(def_id));
        trace!("pushing stack frame for global: {}", name);
        self.push_stack_frame(
            instance,
            span,
            mir,
            Lvalue::Global(cid),
            cleanup,
        )?;
        Ok(true)
    }
}

// WARNING: This code pushes new stack frames.  Make sure that any methods implemented on this
// type don't ever access ecx.stack[ecx.cur_frame()], as that will change. This includes, e.g.,
// using the current stack frame's substitution.
// Basically don't call anything other than `load_mir`, `alloc_ptr`, `push_stack_frame`.
struct ConstantExtractor<'a, 'b: 'a, 'tcx: 'b, M: Machine<'tcx> + 'a> {
    span: Span,
    ecx: &'a mut EvalContext<'b, 'tcx, M>,
    mir: &'tcx mir::Mir<'tcx>,
    instance: ty::Instance<'tcx>,
    new_constants: &'a mut EvalResult<'tcx, u64>,
}

impl<'a, 'b, 'tcx, M: Machine<'tcx>> ConstantExtractor<'a, 'b, 'tcx, M> {
    fn try<F: FnOnce(&mut Self) -> EvalResult<'tcx, bool>>(&mut self, f: F) {
        // previous constant errored
        let n = match *self.new_constants {
            Ok(n) => n,
            Err(_) => return,
        };
        match f(self) {
            // everything ok + a new stackframe
            Ok(true) => *self.new_constants = Ok(n + 1),
            // constant correctly evaluated, but no new stackframe
            Ok(false) => {},
            // constant eval errored
            Err(err) => *self.new_constants = Err(err),
        }
    }
}

impl<'a, 'b, 'tcx, M: Machine<'tcx>> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx, M> {
    fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: mir::Location) {
        self.super_constant(constant, location);
        match constant.literal {
            // already computed by rustc
            mir::Literal::Value { .. } => {}
            mir::Literal::Item { def_id, substs } => {
                self.try(|this| this.ecx.global_item(def_id, substs, constant.span, Mutability::Immutable));
            },
            mir::Literal::Promoted { index } => {
                let cid = GlobalId {
                    instance: self.instance,
                    promoted: Some(index),
                };
                if self.ecx.globals.contains_key(&cid) {
                    return;
                }
                let mir = &self.mir.promoted[index];
                self.try(|this| {
                    let ty = this.ecx.monomorphize(mir.return_ty, this.instance.substs);
                    this.ecx.globals.insert(cid, Global::uninitialized(ty));
                    trace!("pushing stack frame for {:?}", index);
                    this.ecx.push_stack_frame(this.instance,
                                              constant.span,
                                              mir,
                                              Lvalue::Global(cid),
                                              StackPopCleanup::MarkStatic(Mutability::Immutable),
                    )?;
                    Ok(true)
                });
            }
        }
    }

    fn visit_lvalue(
        &mut self,
        lvalue: &mir::Lvalue<'tcx>,
        context: LvalueContext<'tcx>,
        location: mir::Location
    ) {
        self.super_lvalue(lvalue, context, location);
        if let mir::Lvalue::Static(ref static_) = *lvalue {
            let def_id = static_.def_id;
            let substs = self.ecx.tcx.intern_substs(&[]);
            let span = self.span;
            if let Some(node_item) = self.ecx.tcx.hir.get_if_local(def_id) {
                if let hir::map::Node::NodeItem(&hir::Item { ref node, .. }) = node_item {
                    if let hir::ItemStatic(_, m, _) = *node {
                        self.try(|this| this.ecx.global_item(def_id, substs, span, if m == hir::MutMutable { Mutability::Mutable } else { Mutability::Immutable }));
                        return;
                    } else {
                        bug!("static def id doesn't point to static");
                    }
                } else {
                    bug!("static def id doesn't point to item");
                }
            } else {
                let def = self.ecx.tcx.describe_def(def_id).expect("static not found");
                if let hir::def::Def::Static(_, mutable) = def {
                    self.try(|this| this.ecx.global_item(def_id, substs, span, if mutable { Mutability::Mutable } else { Mutability::Immutable }));
                } else {
                    bug!("static found but isn't a static: {:?}", def);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! `x86_64` architecture-specific implementation.
// pub mod cpu;
pub mod drivers;
pub mod interrupts;

#[path = "../x86_all/bda.rs"] pub mod bda;
#[path = "../x86_all/multiboot2.rs"] pub mod multiboot2;

use memory::PAddr;
use params::InitParams;
use ::kernel_init;

pub const ARCH_BITS: u8 = 64;

/// Trampoline to ensure we have a correct stack frame for calling [`arch_init`]
///
/// I have no idea why this works, but it does.
///
/// [`arch_init`]: fn.arch_init
#[naked]
#[no_mangle]
pub unsafe extern "C" fn long_mode_init() {
    asm!("movabsq $$(stack_top), %rsp");
    asm!("mov ax, 0
          mov ss, ax
          mov ds, ax
          mov es, ax
          mov fs, ax
          mov gs, ax
          call arch_init"
        :::: "intel");

}

/// Entry point for architecture-specific kernel init
///
/// This expects to be passed the address of a valid
/// Multiboot 2 info struct. It's the bootloader's responsibility to ensure
/// that this is passed in the correct register as expected by the calling
/// convention (`edi` on x86). If this isn't there, you can expect to have a
/// bad problem and not go to space today.
#[no_mangle]
pub extern "C" fn arch_init(multiboot_addr: PAddr) {
    use memory::arch::{HEAP_BASE, HEAP_TOP};

    ::io::term::CONSOLE.lock().clear();
    ::logger::initialize()
        .expect("Could not initialize logger!");

    kinfoln!("in arch_init");

    // -- Unpack multiboot tag ------------------------------------------------
    kinfoln!( dots: " . "
            , "trying to unpack multiboot info at {:?}"
            , multiboot_addr);

    let boot_info
        = unsafe { multiboot2::Info::from(multiboot_addr)
                    .expect("Could not unpack multiboot2 information!") };
    // Extract the memory map tag from the multiboot info
    let mem_map = boot_info.mem_map()
                           .expect("Memory map tag required!");

    kinfoln!(dots: " . ", "Detected memory areas:");
    for area in mem_map {
        kinfoln!( dots: " . . ", "{}", area);
        // TODO: add memory map to init params here
    }

    // Extract ELF sections tag from the multiboot info
    let elf_sections_tag
        = boot_info.elf_sections()
                   .expect("ELF sections tag required!");

    kinfoln!(dots: " . ", "Detecting kernel ELF sections:");

    // Extract kernel ELF sections from  multiboot info
    let kernel_begin
        = elf_sections_tag.sections()
            .map(|s| {
                kinfoln!( dots: " . . ", "{}, flags: {:?}", s, s.flags() );
                s.addr() })
            .min()
            .expect("Could not find kernel start section!\
                    \nSomething is deeply wrong.");

    let mut n_elf_sections = 0;
    let kernel_end
        = elf_sections_tag.sections()
            .map(|s| { n_elf_sections += 1; s.addr() })
            .max()
            .expect("Could not find kernel end section!\
                    \nSomething is deeply wrong.");

    kinfoln!( dots: " . ", "Detected {} kernel ELF sections.", n_elf_sections);
    kinfoln!(dots: " . . ", "Kernel begins at {:#x} and ends at {:#x}."
             , kernel_begin, kernel_end );

    let multiboot_end = multiboot_addr + boot_info.length as u64;

    kinfoln!(dots: " . . ", "Multiboot info begins at {:#x} and ends at {:#x}."
             , multiboot_addr, multiboot_end);

    let params = InitParams { kernel_base: kernel_begin
                            , kernel_top:  kernel_end
                            , heap_base:   unsafe { PAddr::from(HEAP_BASE) }
                            , heap_top:    unsafe { PAddr::from(HEAP_TOP) }
                            };
    kernel_init(params);
}
<commit_msg>refac(x86_64): nicer formatting of ELF section flags in arch_init<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! `x86_64` architecture-specific implementation.
// pub mod cpu;
pub mod drivers;
pub mod interrupts;

#[path = "../x86_all/bda.rs"] pub mod bda;
#[path = "../x86_all/multiboot2.rs"] pub mod multiboot2;

use memory::PAddr;
use params::InitParams;
use ::kernel_init;

pub const ARCH_BITS: u8 = 64;

/// Trampoline to ensure we have a correct stack frame for calling [`arch_init`]
///
/// I have no idea why this works, but it does.
///
/// [`arch_init`]: fn.arch_init
#[naked]
#[no_mangle]
pub unsafe extern "C" fn long_mode_init() {
    asm!("movabsq $$(stack_top), %rsp");
    asm!("mov ax, 0
          mov ss, ax
          mov ds, ax
          mov es, ax
          mov fs, ax
          mov gs, ax
          call arch_init"
        :::: "intel");

}

/// Entry point for architecture-specific kernel init
///
/// This expects to be passed the address of a valid
/// Multiboot 2 info struct. It's the bootloader's responsibility to ensure
/// that this is passed in the correct register as expected by the calling
/// convention (`edi` on x86). If this isn't there, you can expect to have a
/// bad problem and not go to space today.
#[no_mangle]
pub extern "C" fn arch_init(multiboot_addr: PAddr) {
    use memory::arch::{HEAP_BASE, HEAP_TOP};

    ::io::term::CONSOLE.lock().clear();
    ::logger::initialize()
        .expect("Could not initialize logger!");

    kinfoln!("in arch_init");

    // -- Unpack multiboot tag ------------------------------------------------
    kinfoln!( dots: " . "
            , "trying to unpack multiboot info at {:?}"
            , multiboot_addr);

    let boot_info
        = unsafe { multiboot2::Info::from(multiboot_addr)
                    .expect("Could not unpack multiboot2 information!") };
    // Extract the memory map tag from the multiboot info
    let mem_map = boot_info.mem_map()
                           .expect("Memory map tag required!");

    kinfoln!(dots: " . ", "Detected memory areas:");
    for area in mem_map {
        kinfoln!( dots: " . . ", "{}", area);
        // TODO: add memory map to init params here
    }

    // Extract ELF sections tag from the multiboot info
    let elf_sections_tag
        = boot_info.elf_sections()
                   .expect("ELF sections tag required!");

    kinfoln!(dots: " . ", "Detecting kernel ELF sections:");

    // Extract kernel ELF sections from  multiboot info
    let kernel_begin
        = elf_sections_tag.sections()
            .map(|s| {
                kinfoln!( dots: " . . ", "{}", s );
                kinfoln!( dots: " . . . ", "flags: [ {:?} ]", s.flags());
                s.addr() })
            .min()
            .expect("Could not find kernel start section!\
                    \nSomething is deeply wrong.");

    let mut n_elf_sections = 0;
    let kernel_end
        = elf_sections_tag.sections()
            .map(|s| { n_elf_sections += 1; s.addr() })
            .max()
            .expect("Could not find kernel end section!\
                    \nSomething is deeply wrong.");

    kinfoln!( dots: " . ", "Detected {} kernel ELF sections.", n_elf_sections);
    kinfoln!(dots: " . . ", "Kernel begins at {:#x} and ends at {:#x}."
             , kernel_begin, kernel_end );

    let multiboot_end = multiboot_addr + boot_info.length as u64;

    kinfoln!(dots: " . . ", "Multiboot info begins at {:#x} and ends at {:#x}."
             , multiboot_addr, multiboot_end);

    let params = InitParams { kernel_base: kernel_begin
                            , kernel_top:  kernel_end
                            , heap_base:   unsafe { PAddr::from(HEAP_BASE) }
                            , heap_top:    unsafe { PAddr::from(HEAP_TOP) }
                            };
    kernel_init(params);
}
<|endoftext|>