<commit_before>use std::collections::HashMap;
use std::net;
use uuid::Uuid;

use types::{AsRust, CBytes};
use frame::frame_result::{ColTypeOption, ColTypeOptionValue, ColType};
use types::data_serialization_types::*;
use types::list::List;
use types::udt::UDT;
use error::Result;

#[derive(Debug)]
pub struct Map {
    metadata: ColTypeOption,
    data: HashMap<String, CBytes>,
}

impl Map {
    /// Creates new `Map` basing on provided data and key and value types.
    // TODO: Need to return Result<Map>. If key has not string-like type
    // return Err otherwise return Ok.
    pub fn new(data: Vec<(CBytes, CBytes)>, meta: ColTypeOption) -> Map {
        let accumulator: HashMap<String, CBytes> = HashMap::new();
        let map_option_type = meta.value.clone();

        if map_option_type.is_none() {
            unimplemented!();
        }

        // check that key could be converted into String
        let serializer = if let ColTypeOptionValue::CMap((key_type, _)) =
            map_option_type.unwrap() {
            match key_type.id {
                ColType::Custom => decode_custom,
                ColType::Ascii => decode_ascii,
                ColType::Varchar => decode_varchar,
                _ => unimplemented!(),
            }
        } else {
            unimplemented!();
        };

        let map: HashMap<String, CBytes> = data.iter()
            .fold(accumulator, |mut acc, kv| {
                let (key_b, value_b) = kv.clone();
                let key: String = serializer(key_b.as_plain()).unwrap();

                acc.insert(key, value_b);

                return acc;
            });

        return Map {
            metadata: meta,
            data: map,
        };
    }
}

// into hash map which values are blobs
impl AsRust<HashMap<String, Vec<u8>>> for Map {
    /// Converts `Map` into `HashMap<String, Vec<u8>>` for blob values.
    fn as_rust(&self) -> Result<HashMap<String, Vec<u8>>> {
        let map: HashMap<String, Vec<u8>> = HashMap::new();

        match self.metadata.value.clone().unwrap() {
            ColTypeOptionValue::CMap((_, value_type_option)) => {
                match value_type_option.id {
                    ColType::Blob => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_blob(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    _ => unreachable!(),
                }
            }
            _ => unreachable!(),
        }
    }
}

impl AsRust<HashMap<String, String>> for Map {
    /// Converts `Map` into `HashMap<String, String>` for string-like values.
    fn as_rust(&self) -> Result<HashMap<String, String>> {
        let map: HashMap<String, String> = HashMap::new();

        match self.metadata.value.clone().unwrap() {
            ColTypeOptionValue::CMap((_, value_type_option)) => {
                match value_type_option.id {
                    ColType::Custom => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_custom(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    ColType::Ascii => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_ascii(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    ColType::Varchar => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_varchar(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    _ => unreachable!(),
                }
            }
            _ => unreachable!(),
        }
    }
}

impl AsRust<HashMap<String, bool>> for Map {
    /// Converts `Map` into `HashMap<String, bool>` for boolean values.
    fn as_rust(&self) -> Result<HashMap<String, bool>> {
        let map: HashMap<String, bool> = HashMap::new();

        match self.metadata.value.clone().unwrap() {
            ColTypeOptionValue::CMap((_, value_type_option)) => {
                match value_type_option.id {
                    ColType::Boolean => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_boolean(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    _ => unreachable!(),
                }
            }
            _ => unreachable!(),
        }
    }
}

impl AsRust<HashMap<String, i64>> for Map {
    /// Converts `Map` into `HashMap<String, i64>` for numerical values.
    fn as_rust(&self) -> Result<HashMap<String, i64>> {
        let map: HashMap<String, i64> = HashMap::new();

        match self.metadata.value.clone().unwrap() {
            ColTypeOptionValue::CMap((_, value_type_option)) => {
                match value_type_option.id {
                    ColType::Bigint => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_bigint(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    ColType::Timestamp => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_timestamp(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    ColType::Time => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_time(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    ColType::Varint => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_varint(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    _ => unreachable!(),
                }
            }
            _ => unreachable!(),
        }
    }
}

impl AsRust<HashMap<String, i32>> for Map {
    /// Converts `Map` into `HashMap<String, i32>` for numerical values.
    fn as_rust(&self) -> Result<HashMap<String, i32>> {
        let map: HashMap<String, i32> = HashMap::new();

        match self.metadata.value.clone().unwrap() {
            ColTypeOptionValue::CMap((_, value_type_option)) => {
                match value_type_option.id {
                    ColType::Int => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_int(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    ColType::Date => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_date(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    _ => unreachable!(),
                }
            }
            _ => unreachable!(),
        }
    }
}

impl AsRust<HashMap<String, i16>> for Map {
    /// Converts `Map` into `HashMap<String, i16>` for numerical values.
    fn as_rust(&self) -> Result<HashMap<String, i16>> {
        let map: HashMap<String, i16> = HashMap::new();

        match self.metadata.value.clone().unwrap() {
            ColTypeOptionValue::CMap((_, value_type_option)) => {
                match value_type_option.id {
                    ColType::Smallint => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_smallint(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    _ => unreachable!(),
                }
            }
            _ => unreachable!(),
        }
    }
}

impl AsRust<HashMap<String, f64>> for Map {
    /// Converts `Map` into `HashMap<String, f64>` for numerical values.
    fn as_rust(&self) -> Result<HashMap<String, f64>> {
        let map: HashMap<String, f64> = HashMap::new();

        match self.metadata.value.clone().unwrap() {
            ColTypeOptionValue::CMap((_, value_type_option)) => {
                match value_type_option.id {
                    ColType::Double => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_double(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    _ => unreachable!(),
                }
            }
            _ => unreachable!(),
        }
    }
}

impl AsRust<HashMap<String, f32>> for Map {
    /// Converts `Map` into `HashMap<String, f32>` for numerical values.
    fn as_rust(&self) -> Result<HashMap<String, f32>> {
        let map: HashMap<String, f32> = HashMap::new();

        match self.metadata.value.clone().unwrap() {
            ColTypeOptionValue::CMap((_, value_type_option)) => {
                match value_type_option.id {
                    ColType::Decimal => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_decimal(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    ColType::Float => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_float(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    _ => unreachable!(),
                }
            }
            _ => unreachable!(),
        }
    }
}

impl AsRust<HashMap<String, net::IpAddr>> for Map {
    /// Converts `Map` into `HashMap<String, net::IpAddr>` for IP address values.
    fn as_rust(&self) -> Result<HashMap<String, net::IpAddr>> {
        let map: HashMap<String, net::IpAddr> = HashMap::new();

        match self.metadata.value.clone().unwrap() {
            ColTypeOptionValue::CMap((_, value_type_option)) => {
                match value_type_option.id {
                    ColType::Inet => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_inet(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    _ => unreachable!(),
                }
            }
            _ => unreachable!(),
        }
    }
}

impl AsRust<HashMap<String, Uuid>> for Map {
    /// Converts `Map` into `HashMap<String, Uuid>` for IP address values.
    fn as_rust(&self) -> Result<HashMap<String, Uuid>> {
        let map: HashMap<String, Uuid> = HashMap::new();

        match self.metadata.value.clone().unwrap() {
            ColTypeOptionValue::CMap((_, value_type_option)) => {
                match value_type_option.id {
                    ColType::Uuid => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_timeuuid(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    ColType::Timeuuid => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_timeuuid(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    _ => unreachable!(),
                }
            }
            _ => unreachable!(),
        }
    }
}

impl AsRust<HashMap<String, List>> for Map {
    /// Converts `Map` into `HashMap<String, List>` for List address values.
    fn as_rust(&self) -> Result<HashMap<String, List>> {
        let map: HashMap<String, List> = HashMap::new();

        match self.metadata.value.clone().unwrap() {
            ColTypeOptionValue::CMap((_, value_type_option)) => {
                match value_type_option.id {
                    ColType::List => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                let list = List::new(decode_list(vb.as_plain()).unwrap(),
                                                     value_type_option.as_ref().clone());
                                acc.insert(k.clone(), list);
                                return acc;
                            }))
                    }
                    ColType::Set => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                let list = List::new(decode_list(vb.as_plain()).unwrap(),
                                                     value_type_option.as_ref().clone());
                                acc.insert(k.clone(), list);
                                return acc;
                            }))
                    }
                    _ => unreachable!(),
                }
            }
            _ => unreachable!(),
        }
    }
}

impl AsRust<HashMap<String, Map>> for Map {
    /// Converts `Map` into `HashMap<String, Map>` for Map address values.
    fn as_rust(&self) -> Result<HashMap<String, Map>> {
        let map: HashMap<String, Map> = HashMap::new();

        match self.metadata.value.clone().unwrap() {
            ColTypeOptionValue::CMap((_, value_type_option)) => {
                match value_type_option.id {
                    ColType::Map => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                let list = Map::new(decode_map(vb.as_plain()).unwrap(),
                                                    value_type_option.as_ref().clone());
                                acc.insert(k.clone(), list);
                                return acc;
                            }))
                    }
                    _ => unreachable!(),
                }
            }
            _ => unreachable!(),
        }
    }
}

impl AsRust<HashMap<String, UDT>> for Map {
    /// Converts `Map` into `HashMap<String, Map>` for Map address values.
    fn as_rust(&self) -> Result<HashMap<String, UDT>> {
        let map: HashMap<String, UDT> = HashMap::new();

        match self.metadata.value.clone().unwrap() {
            ColTypeOptionValue::CMap((_, value_type_option)) => {
                let list_type_option = match value_type_option.value {
                    Some(ColTypeOptionValue::UdtType(ref t)) => t,
                    _ => unreachable!(),
                };

                match value_type_option.id {
                    ColType::Udt => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                let list = UDT::new(decode_udt(vb.as_plain()).unwrap(),
                                                    list_type_option);
                                acc.insert(k.clone(), list);
                                return acc;
                            }))
                    }
                    _ => unreachable!(),
                }
            }
            _ => unreachable!(),
        }
    }
}

// TODO: uuid
<commit_msg>Refactoring. Avoid clones 3<commit_after>use std::collections::HashMap;
use std::net;
use uuid::Uuid;

use types::{AsRust, CBytes};
use frame::frame_result::{ColTypeOption, ColTypeOptionValue, ColType};
use types::data_serialization_types::*;
use types::list::List;
use types::udt::UDT;
use error::Result;

#[derive(Debug)]
pub struct Map {
    metadata: ColTypeOption,
    data: HashMap<String, CBytes>,
}

impl Map {
    /// Creates new `Map` basing on provided data and key and value types.
    // TODO: Need to return Result<Map>. If key has not string-like type
    // return Err otherwise return Ok.
    pub fn new(data: Vec<(CBytes, CBytes)>, meta: ColTypeOption) -> Map {
        let accumulator: HashMap<String, CBytes> = HashMap::new();

        // check that key could be converted into String
        let serializer = if let Some(ColTypeOptionValue::CMap((ref key_type, _))) = meta.value {
            match key_type.id {
                ColType::Custom => decode_custom,
                ColType::Ascii => decode_ascii,
                ColType::Varchar => decode_varchar,
                // unreachable ??
                // do we need this arm? is it reachable due to the protocol?
                _ => unimplemented!(),
            }
        } else {
            // do we need this arm? is it reachable due to the protocol?
            unreachable!();
        };

        let map: HashMap<String, CBytes> = data.iter()
            .fold(accumulator, |mut acc, kv| {
                let (key_b, value_b) = kv.clone();
                let key: String = serializer(key_b.as_plain()).unwrap();

                acc.insert(key, value_b);

                return acc;
            });

        return Map {
            metadata: meta,
            data: map,
        };
    }
}

// into hash map which values are blobs
impl AsRust<HashMap<String, Vec<u8>>> for Map {
    /// Converts `Map` into `HashMap<String, Vec<u8>>` for blob values.
    fn as_rust(&self) -> Result<HashMap<String, Vec<u8>>> {
        let map: HashMap<String, Vec<u8>> = HashMap::new();

        match self.metadata.value {
            Some(ColTypeOptionValue::CMap((_, ref value_type_option))) => {
                match value_type_option.id {
                    ColType::Blob => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_blob(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    _ => unreachable!(),
                }
            }
            _ => unreachable!(),
        }
    }
}

impl AsRust<HashMap<String, String>> for Map {
    /// Converts `Map` into `HashMap<String, String>` for string-like values.
    fn as_rust(&self) -> Result<HashMap<String, String>> {
        let map: HashMap<String, String> = HashMap::new();

        match self.metadata.value {
            Some(ColTypeOptionValue::CMap((_, ref value_type_option))) => {
                match value_type_option.id {
                    ColType::Custom => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_custom(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    ColType::Ascii => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_ascii(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    ColType::Varchar => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_varchar(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    _ => unreachable!(),
                }
            }
            _ => unreachable!(),
        }
    }
}

impl AsRust<HashMap<String, bool>> for Map {
    /// Converts `Map` into `HashMap<String, bool>` for boolean values.
    fn as_rust(&self) -> Result<HashMap<String, bool>> {
        let map: HashMap<String, bool> = HashMap::new();

        match self.metadata.value {
            Some(ColTypeOptionValue::CMap((_, ref value_type_option))) => {
                match value_type_option.id {
                    ColType::Boolean => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_boolean(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    _ => unreachable!(),
                }
            }
            _ => unreachable!(),
        }
    }
}

impl AsRust<HashMap<String, i64>> for Map {
    /// Converts `Map` into `HashMap<String, i64>` for numerical values.
    fn as_rust(&self) -> Result<HashMap<String, i64>> {
        let map: HashMap<String, i64> = HashMap::new();

        match self.metadata.value {
            Some(ColTypeOptionValue::CMap((_, ref value_type_option))) => {
                match value_type_option.id {
                    ColType::Bigint => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_bigint(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    ColType::Timestamp => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_timestamp(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    ColType::Time => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_time(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    ColType::Varint => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_varint(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    _ => unreachable!(),
                }
            }
            _ => unreachable!(),
        }
    }
}

impl AsRust<HashMap<String, i32>> for Map {
    /// Converts `Map` into `HashMap<String, i32>` for numerical values.
    fn as_rust(&self) -> Result<HashMap<String, i32>> {
        let map: HashMap<String, i32> = HashMap::new();

        // FIXME: implement via maps
        match self.metadata.value {
            Some(ColTypeOptionValue::CMap((_, ref value_type_option))) => {
                match value_type_option.id {
                    ColType::Int => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_int(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    ColType::Date => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_date(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    _ => unreachable!(),
                }
            }
            _ => unreachable!(),
        }
    }
}

impl AsRust<HashMap<String, i16>> for Map {
    /// Converts `Map` into `HashMap<String, i16>` for numerical values.
    fn as_rust(&self) -> Result<HashMap<String, i16>> {
        let map: HashMap<String, i16> = HashMap::new();

        // FIXME
        match self.metadata.value {
            Some(ColTypeOptionValue::CMap((_, ref value_type_option))) => {
                match value_type_option.id {
                    ColType::Smallint => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_smallint(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    _ => unreachable!(),
                }
            }
            _ => unreachable!(),
        }
    }
}

impl AsRust<HashMap<String, f64>> for Map {
    /// Converts `Map` into `HashMap<String, f64>` for numerical values.
    fn as_rust(&self) -> Result<HashMap<String, f64>> {
        let map: HashMap<String, f64> = HashMap::new();

        match self.metadata.value {
            Some(ColTypeOptionValue::CMap((_, ref value_type_option))) => {
                match value_type_option.id {
                    ColType::Double => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_double(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    _ => unreachable!(),
                }
            }
            _ => unreachable!(),
        }
    }
}

impl AsRust<HashMap<String, f32>> for Map {
    /// Converts `Map` into `HashMap<String, f32>` for numerical values.
    fn as_rust(&self) -> Result<HashMap<String, f32>> {
        let map: HashMap<String, f32> = HashMap::new();

        match self.metadata.value {
            Some(ColTypeOptionValue::CMap((_, ref value_type_option))) => {
                match value_type_option.id {
                    ColType::Decimal => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_decimal(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    ColType::Float => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_float(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    _ => unreachable!(),
                }
            }
            _ => unreachable!(),
        }
    }
}

impl AsRust<HashMap<String, net::IpAddr>> for Map {
    /// Converts `Map` into `HashMap<String, net::IpAddr>` for IP address values.
    fn as_rust(&self) -> Result<HashMap<String, net::IpAddr>> {
        let map: HashMap<String, net::IpAddr> = HashMap::new();

        match self.metadata.value {
            Some(ColTypeOptionValue::CMap((_, ref value_type_option))) => {
                match value_type_option.id {
                    ColType::Inet => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_inet(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    _ => unreachable!(),
                }
            }
            _ => unreachable!(),
        }
    }
}

impl AsRust<HashMap<String, Uuid>> for Map {
    /// Converts `Map` into `HashMap<String, Uuid>` for IP address values.
    fn as_rust(&self) -> Result<HashMap<String, Uuid>> {
        let map: HashMap<String, Uuid> = HashMap::new();

        match self.metadata.value {
            Some(ColTypeOptionValue::CMap((_, ref value_type_option))) => {
                match value_type_option.id {
                    ColType::Uuid => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_timeuuid(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    ColType::Timeuuid => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                acc.insert(k.clone(), decode_timeuuid(vb.as_plain()).unwrap());
                                return acc;
                            }))
                    }
                    _ => unreachable!(),
                }
            }
            _ => unreachable!(),
        }
    }
}

impl AsRust<HashMap<String, List>> for Map {
    /// Converts `Map` into `HashMap<String, List>` for List address values.
    fn as_rust(&self) -> Result<HashMap<String, List>> {
        let map: HashMap<String, List> = HashMap::new();

        match self.metadata.value {
            Some(ColTypeOptionValue::CMap((_, ref value_type_option))) => {
                match value_type_option.id {
                    ColType::List => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                let list = List::new(decode_list(vb.as_plain()).unwrap(),
                                                     value_type_option.as_ref().clone());
                                acc.insert(k.clone(), list);
                                return acc;
                            }))
                    }
                    ColType::Set => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                let list = List::new(decode_list(vb.as_plain()).unwrap(),
                                                     value_type_option.as_ref().clone());
                                acc.insert(k.clone(), list);
                                return acc;
                            }))
                    }
                    _ => unreachable!(),
                }
            }
            _ => unreachable!(),
        }
    }
}

impl AsRust<HashMap<String, Map>> for Map {
    /// Converts `Map` into `HashMap<String, Map>` for Map address values.
    fn as_rust(&self) -> Result<HashMap<String, Map>> {
        let map: HashMap<String, Map> = HashMap::new();

        match self.metadata.value {
            Some(ColTypeOptionValue::CMap((_, ref value_type_option))) => {
                match value_type_option.id {
                    ColType::Map => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                let list = Map::new(decode_map(vb.as_plain()).unwrap(),
                                                    value_type_option.as_ref().clone());
                                acc.insert(k.clone(), list);
                                return acc;
                            }))
                    }
                    _ => unreachable!(),
                }
            }
            _ => unreachable!(),
        }
    }
}

impl AsRust<HashMap<String, UDT>> for Map {
    /// Converts `Map` into `HashMap<String, Map>` for Map address values.
    fn as_rust(&self) -> Result<HashMap<String, UDT>> {
        let map: HashMap<String, UDT> = HashMap::new();

        match self.metadata.value {
            Some(ColTypeOptionValue::CMap((_, ref value_type_option))) => {
                let list_type_option = match value_type_option.value {
                    Some(ColTypeOptionValue::UdtType(ref t)) => t,
                    _ => unreachable!(),
                };

                match value_type_option.id {
                    ColType::Udt => {
                        Ok(self.data
                            .iter()
                            .fold(map, |mut acc, (k, vb)| {
                                let list = UDT::new(decode_udt(vb.as_plain()).unwrap(),
                                                    list_type_option);
                                acc.insert(k.clone(), list);
                                return acc;
                            }))
                    }
                    _ => unreachable!(),
                }
            }
            _ => unreachable!(),
        }
    }
}

// TODO: uuid
<|endoftext|>


<commit_before>use std::convert::Into;
use convert::TryFrom;
use std::string::ToString;
use byteorder::{WriteBytesExt, ByteOrder, BigEndian};
use metainfo::SHA1Hash20b;
use file::PartialFile;
use bit_vec::BitVec;

pub enum PeerMsg {
    // info hash, peer id
    HandShake(String, SHA1Hash20b, SHA1Hash20b),
    KeepAlive,
    Choke,
    Unchoke,
    Interested,
    NotInterested,
    Have(u32),
    Bitfield(BitVec),
    Request(u32, u32, u32),
    Piece(u32, u32, Vec<u8>),
    Cancel(u32, u32, u32),
    Port(u32),
}

impl PeerMsg {
    pub fn id(&self) -> Option<u8> {
        if let &PeerMsg::KeepAlive = self {
            return None;
        } else if let &PeerMsg::HandShake(..) = self {
            return None;
        }

        Some(match self {
            &PeerMsg::KeepAlive => 0, //unreachable
            &PeerMsg::HandShake(..) => 0, //unreachable
            &PeerMsg::Choke => 0,
            &PeerMsg::Unchoke => 1,
            &PeerMsg::Interested => 2,
            &PeerMsg::NotInterested => 3,
            &PeerMsg::Have(_) => 4,
            &PeerMsg::Bitfield(_) => 5,
            &PeerMsg::Request(_, _, _) => 6,
            &PeerMsg::Piece(_, _, _) => 7,
            &PeerMsg::Cancel(_, _, _) => 8,
            &PeerMsg::Port(_) => 9,
        })
    }

    pub fn handshake(protocol_id: String, peer_id: String, hash: &SHA1Hash20b) -> PeerMsg {
        let mut id = peer_id.into_bytes();
        id.resize(20, 0);
        PeerMsg::HandShake(protocol_id, hash.clone(), id)
    }
}

impl Into<Vec<u8>> for PeerMsg {
    fn into(self) -> Vec<u8> {
        let mut out: Vec<u8> = Vec::new();
        let mut bytes = match self {
            PeerMsg::HandShake(mut protocol_id, mut info_hash, mut peer_id) => {
                let protocol_bytes = protocol_id.into_bytes();
                let mut p_bytes = &protocol_bytes[0..protocol_bytes.len()];
                if p_bytes.len() > 255 {
                    p_bytes = &p_bytes[0..255]
                }
                out.push(p_bytes.len() as u8);
                out.extend_from_slice(p_bytes);
                out.append(&mut vec![0, 0, 0, 0, 0, 0, 0, 0]);
                out.append(&mut info_hash);
                out.append(&mut peer_id);
                return out;
            }
            PeerMsg::Have(piece_index) => {
                out.write_u32::<BigEndian>(piece_index);
                out
            }
            PeerMsg::Bitfield(bit_field) => unimplemented!(),
            PeerMsg::Request(index, begin, length) => {
                out.write_u32::<BigEndian>(index);
                out.write_u32::<BigEndian>(begin);
                out.write_u32::<BigEndian>(length);
                out
            }
            PeerMsg::Piece(index, begin, ref block) => {
                out.write_u32::<BigEndian>(begin);
                out.write_u32::<BigEndian>(begin);
                out.append(&mut block.clone());
                out
            }
            PeerMsg::Cancel(index, begin, length) => {
                out.write_u32::<BigEndian>(index);
                out.write_u32::<BigEndian>(begin);
                out.write_u32::<BigEndian>(length);
                out
            }
            PeerMsg::Port(port) => {
                out.write_u32::<BigEndian>(port);
                out
            }
            _ => out,
        };
        let mut front_part = Vec::new();
        let length = bytes.len() as u32;
        front_part.write_u32::<BigEndian>(length);
        if let Some(id) = self.id() {
            front_part.push(id);
        }
        front_part.append(&mut bytes);
        front_part
    }
}

pub enum PeerError {
    TooShort
}

pub fn parse_peermsg(bytes: &[u8]) -> Result<(PeerMsg, usize), PeerError> {
    if bytes.len() < 4 {
        return Err(PeerError::TooShort);
    }

    let len = BigEndian::read_u32(&bytes[0..4]) as usize - 4;

    if bytes.len() >= len || bytes.len() < 5 {
        return Err(PeerError::TooShort);
    }

    match bytes[4] {
        /*
            &PeerMsg::KeepAlive => 0, //unreachable
            &PeerMsg::HandShake(..) => 0, //unreachable
            &PeerMsg::Choke => 0,
            &PeerMsg::Unchoke => 1,
            &PeerMsg::Interested => 2,
            &PeerMsg::NotInterested => 3,
            &PeerMsg::Have(_) => 4,
            &PeerMsg::Bitfield(_) => 5,
            &PeerMsg::Request(_, _, _) => 6,
            &PeerMsg::Piece(_, _, _) => 7,
            &PeerMsg::Cancel(_, _, _) => 8,
            &PeerMsg::Port(_) => 9,
           */
        0 => Ok((PeerMsg::KeepAlive, 5)),
        _ => unimplemented!()
    }
}

impl TryFrom<Vec<u8>> for PeerMsg {
    type Err = ();
    fn try_from(vec: Vec<u8>) -> Result<Self, Self::Err> {
        unimplemented!();
    }
}
<commit_msg>Add untested code for parsing peer messages<commit_after>use std::convert::Into;
use convert::TryFrom;
use std::string::ToString;
use byteorder::{WriteBytesExt, ByteOrder, BigEndian};
use metainfo::SHA1Hash20b;
use file::PartialFile;
use bit_vec::BitVec;

pub enum PeerMsg {
    // info hash, peer id
    HandShake(String, SHA1Hash20b, SHA1Hash20b),
    KeepAlive,
    Choke,
    Unchoke,
    Interested,
    NotInterested,
    Have(u32),
    Bitfield(BitVec),
    Request(u32, u32, u32),
    Piece(u32, u32, Vec<u8>),
    Cancel(u32, u32, u32),
    Port(u32),
}

impl PeerMsg {
    pub fn id(&self) -> Option<u8> {
        if let &PeerMsg::KeepAlive = self {
            return None;
        } else if let &PeerMsg::HandShake(..) = self {
            return None;
        }

        Some(match self {
            &PeerMsg::KeepAlive => 0, //unreachable
            &PeerMsg::HandShake(..) => 0, //unreachable
            &PeerMsg::Choke => 0,
            &PeerMsg::Unchoke => 1,
            &PeerMsg::Interested => 2,
            &PeerMsg::NotInterested => 3,
            &PeerMsg::Have(_) => 4,
            &PeerMsg::Bitfield(_) => 5,
            &PeerMsg::Request(_, _, _) => 6,
            &PeerMsg::Piece(_, _, _) => 7,
            &PeerMsg::Cancel(_, _, _) => 8,
            &PeerMsg::Port(_) => 9,
        })
    }

    pub fn handshake(protocol_id: String, peer_id: String, hash: &SHA1Hash20b) -> PeerMsg {
        let mut id = peer_id.into_bytes();
        id.resize(20, 0);
        PeerMsg::HandShake(protocol_id, hash.clone(), id)
    }
}

impl Into<Vec<u8>> for PeerMsg {
    fn into(self) -> Vec<u8> {
        let mut out: Vec<u8> = Vec::new();
        let mut bytes = match self {
            PeerMsg::HandShake(mut protocol_id, mut info_hash, mut peer_id) => {
                let protocol_bytes = protocol_id.into_bytes();
                let mut p_bytes = &protocol_bytes[0..protocol_bytes.len()];
                if p_bytes.len() > 255 {
                    p_bytes = &p_bytes[0..255]
                }
                out.push(p_bytes.len() as u8);
                out.extend_from_slice(p_bytes);
                out.append(&mut vec![0, 0, 0, 0, 0, 0, 0, 0]);
                out.append(&mut info_hash);
                out.append(&mut peer_id);
                return out;
            }
            PeerMsg::Have(piece_index) => {
                out.write_u32::<BigEndian>(piece_index);
                out
            }
            PeerMsg::Bitfield(bit_field) => unimplemented!(),
            PeerMsg::Request(index, begin, length) => {
                out.write_u32::<BigEndian>(index);
                out.write_u32::<BigEndian>(begin);
                out.write_u32::<BigEndian>(length);
                out
            }
            PeerMsg::Piece(index, begin, ref block) => {
                out.write_u32::<BigEndian>(begin);
                out.write_u32::<BigEndian>(begin);
                out.append(&mut block.clone());
                out
            }
            PeerMsg::Cancel(index, begin, length) => {
                out.write_u32::<BigEndian>(index);
                out.write_u32::<BigEndian>(begin);
                out.write_u32::<BigEndian>(length);
                out
            }
            PeerMsg::Port(port) => {
                out.write_u32::<BigEndian>(port);
                out
            }
            _ => out,
        };
        let mut front_part = Vec::new();
        let length = bytes.len() as u32;
        front_part.write_u32::<BigEndian>(length);
        if let Some(id) = self.id() {
            front_part.push(id);
        }
        front_part.append(&mut bytes);
        front_part
    }
}

pub enum MsgParseError {
    TooShort,
    TooShortForId,
    InvalidId
}

pub fn parse_peermsg(bytes: &[u8]) -> Result<(PeerMsg, usize), MsgParseError> {
    const LEN_LEN: usize = 4;
    const INT_LEN: usize = 4;
    const ID_LEN: usize = 1;
    const PORT_LEN: usize = 2;

    if bytes.len() < 4 {
        return Err(MsgParseError::TooShort);
    }

    let len = BigEndian::read_u32(&bytes[0..4]) as usize - 4;

    if len == 0 {
        return Ok((PeerMsg::KeepAlive, 4));
    }

    if bytes.len() < (len - 1) || bytes.len() < 5 {
        return Err(MsgParseError::TooShort);
    }

    let bytes = &bytes[4..len];
    let result = match bytes[0] {
        0 => Ok(PeerMsg::Choke),
        1 => Ok(PeerMsg::Unchoke),
        2 => Ok(PeerMsg::Interested),
        3 => Ok(PeerMsg::NotInterested),
        4 => {
            if len < ID_LEN + INT_LEN {
                return Err(MsgParseError::TooShortForId);
            }
            let piece_index = BigEndian::read_u32(&bytes[1..(1 + INT_LEN)]);
            Ok(PeerMsg::Have(piece_index))
        },
        5 => {
            let bitfield_bytes = &bytes[0..len];
            Ok(PeerMsg::Bitfield(BitVec::from_bytes(bitfield_bytes)))
        },
        6 => {
            if len != 13 {
                return Err(MsgParseError::TooShortForId);
            }

            match _parse_three_u32(&bytes[1..1 + (INT_LEN * 3)]) {
                (index, begin, end) => Ok((PeerMsg::Request(index, begin, end)))
            }
        },
        7 => {
            if len <= 9 {
                return Err(MsgParseError::TooShortForId);
            }
            let index = BigEndian::read_u32(&bytes[1..(1 + INT_LEN)]);
            let begin = BigEndian::read_u32(&bytes[(1+INT_LEN)..(1+INT_LEN*2)]);
            let block = &bytes[(1+INT_LEN*2)..len];
            let block_data = Vec::from(block);
            Ok((PeerMsg::Piece(index, begin, block_data)))
        },
        8 => {
            if len != 13 {
                return Err(MsgParseError::TooShortForId);
            }

            match _parse_three_u32(&bytes[1..1 + (INT_LEN * 3)]) {
                (index, begin, end) => Ok((PeerMsg::Cancel(index, begin, end)))
            }
        },
        9 => {
            if len != 3 {
                return Err(MsgParseError::TooShortForId);
            }
            let port = BigEndian::read_u32(&bytes[1..(1+PORT_LEN)]);
            Ok(PeerMsg::Port(port))
        },
        _ => Err(MsgParseError::InvalidId)
    };

    result.map(|msg| (msg, len + 4))
}

fn _parse_three_u32(bytes: &[u8]) -> (u32, u32, u32) {
    let index = BigEndian::read_u32(&bytes[0..4]);
    let begin = BigEndian::read_u32(&bytes[4..8]);
    let end = BigEndian::read_u32(&bytes[8..12]);

    (index, begin, end)
}

pub fn parse_handshake(bytes: &[u8]) -> Result<(PeerMsg, usize), MsgParseError> {
    unimplemented!()
}

impl TryFrom<Vec<u8>> for PeerMsg {
    type Err = ();
    fn try_from(vec: Vec<u8>) -> Result<Self, Self::Err> {
        unimplemented!();
    }
}
<|endoftext|>


<commit_before>use xen::hypercall::hypercall2;
use xen::hypercall::HyperCalls;

use ::arch::defs::Ulong;

#[allow(dead_code)]
enum SchedOp {
    Yield = 0,
    Block = 1,
    Shutdown = 2,
    Poll = 3,
    RemoteShutdown = 4,
    ShutdownCode = 5,
    Watchdog = 6,
}

#[allow(dead_code)]
enum ShutdownReason {
    PowerOff = 0,
    Reboot = 1,
    Suspend = 2,
    Crash = 3,
    Watchdog = 4,
}

#[repr(C)]
struct SchedShutdown {
    reason: u32,
}

fn sched_op(op: SchedOp, sched: Ulong) -> i32 {
    hypercall2(HyperCalls::SchedOp, op as Ulong, sched) as i32
}

pub fn yield_cpu() -> i32 {
    sched_op(SchedOp::Yield, 0)
}

fn shutdown(reason: ShutdownReason) -> i32 {
    let r = SchedShutdown {
        reason: reason as u32,
    };

    sched_op(SchedOp::Shutdown, &r as *const SchedShutdown as Ulong)
}

fn shutdown_code(status: Ulong) -> i32 {
    sched_op(SchedOp::ShutdownCode, status)
}

pub fn poweroff(status: Ulong) -> i32 {
    let ret: i32 = shutdown_code(status);

    if ret < 0 {
        return ret
    }

    shutdown(ShutdownReason::PowerOff)
}
<commit_msg>sched: Add crash() function<commit_after>use xen::hypercall::hypercall2;
use xen::hypercall::HyperCalls;

use ::arch::defs::Ulong;

#[allow(dead_code)]
enum SchedOp {
    Yield = 0,
    Block = 1,
    Shutdown = 2,
    Poll = 3,
    RemoteShutdown = 4,
    ShutdownCode = 5,
    Watchdog = 6,
}

#[allow(dead_code)]
enum ShutdownReason {
    PowerOff = 0,
    Reboot = 1,
    Suspend = 2,
    Crash = 3,
    Watchdog = 4,
}

#[repr(C)]
struct SchedShutdown {
    reason: u32,
}

fn sched_op(op: SchedOp, sched: Ulong) -> i32 {
    hypercall2(HyperCalls::SchedOp, op as Ulong, sched) as i32
}

pub fn yield_cpu() -> i32 {
    sched_op(SchedOp::Yield, 0)
}

fn shutdown(reason: ShutdownReason) -> i32 {
    let r = SchedShutdown {
        reason: reason as u32,
    };

    sched_op(SchedOp::Shutdown, &r as *const SchedShutdown as Ulong)
}

fn shutdown_code(status: Ulong) -> i32 {
    sched_op(SchedOp::ShutdownCode, status)
}

pub fn crash() -> i32 {
    shutdown(ShutdownReason::Crash)
}

pub fn poweroff(status: Ulong) -> i32 {
    let ret: i32 = shutdown_code(status);

    if ret < 0 {
        return ret
    }

    shutdown(ShutdownReason::PowerOff)
}
<|endoftext|>


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

use LinkerFlavor;
use super::{LinkArgs, Target, TargetOptions};
use super::emscripten_base::{cmd};

pub fn target() -> Result<Target, String> {
    let mut post_link_args = LinkArgs::new();
    post_link_args.insert(LinkerFlavor::Gcc,
                          vec!["-s".to_string(),
                               "BINARYEN=1".to_string(),
                               "-s".to_string(),
                               "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()]);

    let opts = TargetOptions {
        linker: cmd("emcc"),
        ar: cmd("emar"),

        dynamic_linking: false,
        executables: true,
        // Today emcc emits two files - a .js file to bootstrap and
        // possibly interpret the wasm, and a .wasm file
        exe_suffix: ".js".to_string(),
        linker_is_gnu: true,
        allow_asm: false,
        obj_is_bitcode: true,
        is_like_emscripten: true,
        max_atomic_width: Some(32),
        post_link_args: post_link_args,
        target_family: Some("unix".to_string()),
        .. Default::default()
    };
    Ok(Target {
        llvm_target: "asmjs-unknown-emscripten".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "32".to_string(),
        target_os: "emscripten".to_string(),
        target_env: "".to_string(),
        target_vendor: "unknown".to_string(),
        data_layout: "e-p:32:32-i64:64-v128:32:128-n32-S128".to_string(),
        arch: "wasm32".to_string(),
        linker_flavor: LinkerFlavor::Em,
        options: opts,
    })
}
<commit_msg>Rollup merge of #41303 - CryZe:patch-5, r=japaric<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use LinkerFlavor;
use super::{LinkArgs, Target, TargetOptions};
use super::emscripten_base::{cmd};

pub fn target() -> Result<Target, String> {
    let mut post_link_args = LinkArgs::new();
    post_link_args.insert(LinkerFlavor::Em,
                          vec!["-s".to_string(),
                               "BINARYEN=1".to_string(),
                               "-s".to_string(),
                               "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()]);

    let opts = TargetOptions {
        linker: cmd("emcc"),
        ar: cmd("emar"),

        dynamic_linking: false,
        executables: true,
        // Today emcc emits two files - a .js file to bootstrap and
        // possibly interpret the wasm, and a .wasm file
        exe_suffix: ".js".to_string(),
        linker_is_gnu: true,
        allow_asm: false,
        obj_is_bitcode: true,
        is_like_emscripten: true,
        max_atomic_width: Some(32),
        post_link_args: post_link_args,
        target_family: Some("unix".to_string()),
        .. Default::default()
    };
    Ok(Target {
        llvm_target: "asmjs-unknown-emscripten".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "32".to_string(),
        target_os: "emscripten".to_string(),
        target_env: "".to_string(),
        target_vendor: "unknown".to_string(),
        data_layout: "e-p:32:32-i64:64-v128:32:128-n32-S128".to_string(),
        arch: "wasm32".to_string(),
        linker_flavor: LinkerFlavor::Em,
        options: opts,
    })
}
<|endoftext|>


<commit_before>use clap::{Arg, App, ArgGroup, SubCommand};

pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
    app
        .subcommand(SubCommand::with_name("tw-hook")
                    .about("For use in a taskwarrior hook")
                    .version("0.1")

                    .arg(Arg::with_name("add")
                         .long("add")
                         .short("a")
                         .takes_value(false)
                         .required(false)
                         .help("For use in an on-add hook"))

                    .arg(Arg::with_name("delete")
                         .long("delete")
                         .short("d")
                         .takes_value(false)
                         .required(false)
                         .help("For use in an on-delete hook"))

                    .group(ArgGroup::with_name("taskwarrior hooks")
                           .args(&[ "add",
                                 "delete",
                           ])
                           .required(true))
                    )

                    .subcommand(SubCommand::with_name("list")
                                .about("List all tasks")
                                .version("0.1")

                                .arg(Arg::with_name("verbose")
                                     .long("verbose")
                                     .short("v")
                                     .takes_value(false)
                                     .required(false)
                                     .help("Asks taskwarrior for all the details")
                                    )
                               )
}
<commit_msg>Fix indentation in ui definition<commit_after>use clap::{Arg, App, ArgGroup, SubCommand};

pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
    app
        .subcommand(SubCommand::with_name("tw-hook")
                    .about("For use in a taskwarrior hook")
                    .version("0.1")

                    .arg(Arg::with_name("add")
                         .long("add")
                         .short("a")
                         .takes_value(false)
                         .required(false)
                         .help("For use in an on-add hook"))

                    .arg(Arg::with_name("delete")
                         .long("delete")
                         .short("d")
                         .takes_value(false)
                         .required(false)
                         .help("For use in an on-delete hook"))

                    .group(ArgGroup::with_name("taskwarrior hooks")
                           .args(&[ "add",
                                 "delete",
                           ])
                           .required(true))
                    )

        .subcommand(SubCommand::with_name("list")
                    .about("List all tasks")
                    .version("0.1")

                    .arg(Arg::with_name("verbose")
                         .long("verbose")
                         .short("v")
                         .takes_value(false)
                         .required(false)
                         .help("Asks taskwarrior for all the details")
                        )
                   )
}
<|endoftext|>


<commit_before>use super::{
    ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote, PredicateObligation,
};
use crate::infer::InferCtxt;
use crate::ty::subst::Subst;
use crate::ty::{self, GenericParamDefKind};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_span::symbol::sym;

impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
    fn impl_similar_to(
        &self,
        trait_ref: ty::PolyTraitRef<'tcx>,
        obligation: &PredicateObligation<'tcx>,
    ) -> Option<DefId> {
        let tcx = self.tcx;
        let param_env = obligation.param_env;
        let trait_ref = tcx.erase_late_bound_regions(&trait_ref);
        let trait_self_ty = trait_ref.self_ty();

        let mut self_match_impls = vec![];
        let mut fuzzy_match_impls = vec![];

        self.tcx.for_each_relevant_impl(trait_ref.def_id, trait_self_ty, |def_id| {
            let impl_substs = self.fresh_substs_for_item(obligation.cause.span, def_id);
            let impl_trait_ref = tcx.impl_trait_ref(def_id).unwrap().subst(tcx, impl_substs);

            let impl_self_ty = impl_trait_ref.self_ty();

            if let Ok(..) = self.can_eq(param_env, trait_self_ty, impl_self_ty) {
                self_match_impls.push(def_id);

                if trait_ref
                    .substs
                    .types()
                    .skip(1)
                    .zip(impl_trait_ref.substs.types().skip(1))
                    .all(|(u, v)| self.fuzzy_match_tys(u, v))
                {
                    fuzzy_match_impls.push(def_id);
                }
            }
        });

        let impl_def_id = if self_match_impls.len() == 1 {
            self_match_impls[0]
        } else if fuzzy_match_impls.len() == 1 {
            fuzzy_match_impls[0]
        } else {
            return None;
        };

        tcx.has_attr(impl_def_id, sym::rustc_on_unimplemented).then_some(impl_def_id)
    }

    /// Used to set on_unimplemented's `ItemContext`
    /// to be the enclosing (async) block/function/closure
    fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str> {
        let hir = &self.tcx.hir();
        let node = hir.find(hir_id)?;
        if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) = &node {
            self.describe_generator(*body_id).or_else(|| {
                Some(if let hir::FnHeader { asyncness: hir::IsAsync::Async, .. } = sig.header {
                    "an async function"
                } else {
                    "a function"
                })
            })
        } else if let hir::Node::Expr(hir::Expr {
            kind: hir::ExprKind::Closure(_is_move, _, body_id, _, gen_movability),
            ..
        }) = &node
        {
            self.describe_generator(*body_id).or_else(|| {
                Some(if gen_movability.is_some() { "an async closure" } else { "a closure" })
            })
        } else if let hir::Node::Expr(hir::Expr { .. }) = &node {
            let parent_hid = hir.get_parent_node(hir_id);
            if parent_hid != hir_id {
                return self.describe_enclosure(parent_hid);
            } else {
                None
            }
        } else {
            None
        }
    }

    crate fn on_unimplemented_note(
        &self,
        trait_ref: ty::PolyTraitRef<'tcx>,
        obligation: &PredicateObligation<'tcx>,
    ) -> OnUnimplementedNote {
        let def_id =
            self.impl_similar_to(trait_ref, obligation).unwrap_or_else(|| trait_ref.def_id());
        let trait_ref = *trait_ref.skip_binder();

        let mut flags = vec![];
        flags.push((
            sym::item_context,
            self.describe_enclosure(obligation.cause.body_id).map(|s| s.to_owned()),
        ));

        match obligation.cause.code {
            ObligationCauseCode::BuiltinDerivedObligation(..)
            | ObligationCauseCode::ImplDerivedObligation(..) => {}
            _ => {
                // this is a "direct", user-specified, rather than derived,
                // obligation.
                flags.push((sym::direct, None));
            }
        }

        if let ObligationCauseCode::ItemObligation(item) = obligation.cause.code {
            // FIXME: maybe also have some way of handling methods
            // from other traits? That would require name resolution,
            // which we might want to be some sort of hygienic.
            //
            // Currently I'm leaving it for what I need for `try`.
            if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) {
                let method = self.tcx.item_name(item);
                flags.push((sym::from_method, None));
                flags.push((sym::from_method, Some(method.to_string())));
            }
        }
        if let Some((t, _)) = self.get_parent_trait_ref(&obligation.cause.code) {
            flags.push((sym::parent_trait, Some(t)));
        }

        if let Some(k) = obligation.cause.span.desugaring_kind() {
            flags.push((sym::from_desugaring, None));
            flags.push((sym::from_desugaring, Some(format!("{:?}", k))));
        }
        let generics = self.tcx.generics_of(def_id);
        let self_ty = trait_ref.self_ty();
        // This is also included through the generics list as `Self`,
        // but the parser won't allow you to use it
        flags.push((sym::_Self, Some(self_ty.to_string())));
        if let Some(def) = self_ty.ty_adt_def() {
            // We also want to be able to select self's original
            // signature with no type arguments resolved
            flags.push((sym::_Self, Some(self.tcx.type_of(def.did).to_string())));
        }

        for param in generics.params.iter() {
            let value = match param.kind {
                GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => {
                    trait_ref.substs[param.index as usize].to_string()
                }
                GenericParamDefKind::Lifetime => continue,
            };
            let name = param.name;
            flags.push((name, Some(value)));
        }

        if let Some(true) = self_ty.ty_adt_def().map(|def| def.did.is_local()) {
            flags.push((sym::crate_local, None));
        }

        // Allow targeting all integers using `{integral}`, even if the exact type was resolved
        if self_ty.is_integral() {
            flags.push((sym::_Self, Some("{integral}".to_owned())));
        }

        if let ty::Array(aty, len) = self_ty.kind {
            flags.push((sym::_Self, Some("[]".to_owned())));
            flags.push((sym::_Self, Some(format!("[{}]", aty))));
            if let Some(def) = aty.ty_adt_def() {
                // We also want to be able to select the array's type's original
                // signature with no type arguments resolved
                flags.push((
                    sym::_Self,
                    Some(format!("[{}]", self.tcx.type_of(def.did).to_string())),
                ));
                let tcx = self.tcx;
                if let Some(len) = len.try_eval_usize(tcx, ty::ParamEnv::empty()) {
                    flags.push((
                        sym::_Self,
                        Some(format!("[{}; {}]", self.tcx.type_of(def.did).to_string(), len)),
                    ));
                } else {
                    flags.push((
                        sym::_Self,
                        Some(format!("[{}; _]", self.tcx.type_of(def.did).to_string())),
                    ));
                }
            }
        }

        if let Ok(Some(command)) =
            OnUnimplementedDirective::of_item(self.tcx, trait_ref.def_id, def_id)
        {
            command.evaluate(self.tcx, trait_ref, &flags[..])
        } else {
            OnUnimplementedNote::default()
        }
    }
}
<commit_msg>Handle methods in try diagnostic<commit_after>use super::{
    ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote, PredicateObligation,
};
use crate::infer::InferCtxt;
use crate::ty::subst::Subst;
use crate::ty::{self, GenericParamDefKind};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_span::symbol::sym;

impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
    fn impl_similar_to(
        &self,
        trait_ref: ty::PolyTraitRef<'tcx>,
        obligation: &PredicateObligation<'tcx>,
    ) -> Option<DefId> {
        let tcx = self.tcx;
        let param_env = obligation.param_env;
        let trait_ref = tcx.erase_late_bound_regions(&trait_ref);
        let trait_self_ty = trait_ref.self_ty();

        let mut self_match_impls = vec![];
        let mut fuzzy_match_impls = vec![];

        self.tcx.for_each_relevant_impl(trait_ref.def_id, trait_self_ty, |def_id| {
            let impl_substs = self.fresh_substs_for_item(obligation.cause.span, def_id);
            let impl_trait_ref = tcx.impl_trait_ref(def_id).unwrap().subst(tcx, impl_substs);

            let impl_self_ty = impl_trait_ref.self_ty();

            if let Ok(..) = self.can_eq(param_env, trait_self_ty, impl_self_ty) {
                self_match_impls.push(def_id);

                if trait_ref
                    .substs
                    .types()
                    .skip(1)
                    .zip(impl_trait_ref.substs.types().skip(1))
                    .all(|(u, v)| self.fuzzy_match_tys(u, v))
                {
                    fuzzy_match_impls.push(def_id);
                }
            }
        });

        let impl_def_id = if self_match_impls.len() == 1 {
            self_match_impls[0]
        } else if fuzzy_match_impls.len() == 1 {
            fuzzy_match_impls[0]
        } else {
            return None;
        };

        tcx.has_attr(impl_def_id, sym::rustc_on_unimplemented).then_some(impl_def_id)
    }

    /// Used to set on_unimplemented's `ItemContext`
    /// to be the enclosing (async) block/function/closure
    fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str> {
        let hir = &self.tcx.hir();
        let node = hir.find(hir_id)?;
        if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) = &node {
            self.describe_generator(*body_id).or_else(|| {
                Some(if let hir::FnHeader { asyncness: hir::IsAsync::Async, .. } = sig.header {
                    "an async function"
                } else {
                    "a function"
                })
            })
        } else if let hir::Node::TraitItem(hir::TraitItem {
            kind: hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body_id)),
            ..
        }) = &node
        {
            self.describe_generator(*body_id).or_else(|| Some("a trait method"))
        } else if let hir::Node::ImplItem(hir::ImplItem {
            kind: hir::ImplItemKind::Method(sig, body_id),
            ..
        }) = &node
        {
            self.describe_generator(*body_id).or_else(|| {
                Some(if let hir::FnHeader { asyncness: hir::IsAsync::Async, .. } = sig.header {
                    "an async method"
                } else {
                    "a method"
                })
            })
        } else if let hir::Node::Expr(hir::Expr {
            kind: hir::ExprKind::Closure(_is_move, _, body_id, _, gen_movability),
            ..
        }) = &node
        {
            self.describe_generator(*body_id).or_else(|| {
                Some(if gen_movability.is_some() { "an async closure" } else { "a closure" })
            })
        } else if let hir::Node::Expr(hir::Expr { .. }) = &node {
            let parent_hid = hir.get_parent_node(hir_id);
            if parent_hid != hir_id {
                return self.describe_enclosure(parent_hid);
            } else {
                None
            }
        } else {
            None
        }
    }

    crate fn on_unimplemented_note(
        &self,
        trait_ref: ty::PolyTraitRef<'tcx>,
        obligation: &PredicateObligation<'tcx>,
    ) -> OnUnimplementedNote {
        let def_id =
            self.impl_similar_to(trait_ref, obligation).unwrap_or_else(|| trait_ref.def_id());
        let trait_ref = *trait_ref.skip_binder();

        let mut flags = vec![];
        flags.push((
            sym::item_context,
            self.describe_enclosure(obligation.cause.body_id).map(|s| s.to_owned()),
        ));

        match obligation.cause.code {
            ObligationCauseCode::BuiltinDerivedObligation(..)
            | ObligationCauseCode::ImplDerivedObligation(..) => {}
            _ => {
                // this is a "direct", user-specified, rather than derived,
                // obligation.
                flags.push((sym::direct, None));
            }
        }

        if let ObligationCauseCode::ItemObligation(item) = obligation.cause.code {
            // FIXME: maybe also have some way of handling methods
            // from other traits? That would require name resolution,
            // which we might want to be some sort of hygienic.
            //
            // Currently I'm leaving it for what I need for `try`.
            if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) {
                let method = self.tcx.item_name(item);
                flags.push((sym::from_method, None));
                flags.push((sym::from_method, Some(method.to_string())));
            }
        }
        if let Some((t, _)) = self.get_parent_trait_ref(&obligation.cause.code) {
            flags.push((sym::parent_trait, Some(t)));
        }

        if let Some(k) = obligation.cause.span.desugaring_kind() {
            flags.push((sym::from_desugaring, None));
            flags.push((sym::from_desugaring, Some(format!("{:?}", k))));
        }
        let generics = self.tcx.generics_of(def_id);
        let self_ty = trait_ref.self_ty();
        // This is also included through the generics list as `Self`,
        // but the parser won't allow you to use it
        flags.push((sym::_Self, Some(self_ty.to_string())));
        if let Some(def) = self_ty.ty_adt_def() {
            // We also want to be able to select self's original
            // signature with no type arguments resolved
            flags.push((sym::_Self, Some(self.tcx.type_of(def.did).to_string())));
        }

        for param in generics.params.iter() {
            let value = match param.kind {
                GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => {
                    trait_ref.substs[param.index as usize].to_string()
                }
                GenericParamDefKind::Lifetime => continue,
            };
            let name = param.name;
            flags.push((name, Some(value)));
        }

        if let Some(true) = self_ty.ty_adt_def().map(|def| def.did.is_local()) {
            flags.push((sym::crate_local, None));
        }

        // Allow targeting all integers using `{integral}`, even if the exact type was resolved
        if self_ty.is_integral() {
            flags.push((sym::_Self, Some("{integral}".to_owned())));
        }

        if let ty::Array(aty, len) = self_ty.kind {
            flags.push((sym::_Self, Some("[]".to_owned())));
            flags.push((sym::_Self, Some(format!("[{}]", aty))));
            if let Some(def) = aty.ty_adt_def() {
                // We also want to be able to select the array's type's original
                // signature with no type arguments resolved
                flags.push((
                    sym::_Self,
                    Some(format!("[{}]", self.tcx.type_of(def.did).to_string())),
                ));
                let tcx = self.tcx;
                if let Some(len) = len.try_eval_usize(tcx, ty::ParamEnv::empty()) {
                    flags.push((
                        sym::_Self,
                        Some(format!("[{}; {}]", self.tcx.type_of(def.did).to_string(), len)),
                    ));
                } else {
                    flags.push((
                        sym::_Self,
                        Some(format!("[{}; _]", self.tcx.type_of(def.did).to_string())),
                    ));
                }
            }
        }

        if let Ok(Some(command)) =
            OnUnimplementedDirective::of_item(self.tcx, trait_ref.def_id, def_id)
        {
            command.evaluate(self.tcx, trait_ref, &flags[..])
        } else {
            OnUnimplementedNote::default()
        }
    }
}
<|endoftext|>


<commit_before>//! Codegen the completed AST to the LLVM IR.
//!
//! Some functions here, such as codegen_block and codegen_expr, return a value --
//! the result of the codegen to LLVM -- while others, such as codegen_fn
//! and mono_item, are called only for the side effect of adding a
//! particular definition to the LLVM IR output we're producing.
//!
//! Hopefully useful general knowledge about codegen:
//!
//! * There's no way to find out the `Ty` type of a Value. Doing so
//!   would be "trying to get the eggs out of an omelette" (credit:
//!   pcwalton). You can, instead, find out its `llvm::Type` by calling `val_ty`,
//!   but one `llvm::Type` corresponds to many `Ty`s; for instance, `tup(int, int,
//!   int)` and `rec(x=int, y=int, z=int)` will have the same `llvm::Type`.

use super::ModuleLlvm;

use crate::attributes;
use crate::builder::Builder;
use crate::common;
use crate::context::CodegenCx;
use crate::llvm;
use crate::metadata;
use crate::value::Value;

use rustc_codegen_ssa::base::maybe_create_entry_wrapper;
use rustc_codegen_ssa::mono_item::MonoItemExt;
use rustc_codegen_ssa::traits::*;
use rustc_codegen_ssa::{ModuleCodegen, ModuleKind};
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_middle::dep_graph;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc_middle::middle::cstore::EncodedMetadata;
use rustc_middle::middle::exported_symbols;
use rustc_middle::mir::mono::{Linkage, Visibility};
use rustc_middle::ty::TyCtxt;
use rustc_session::config::DebugInfo;
use rustc_span::symbol::Symbol;

use std::ffi::CString;
use std::time::Instant;

pub fn write_compressed_metadata<'tcx>(
    tcx: TyCtxt<'tcx>,
    metadata: &EncodedMetadata,
    llvm_module: &mut ModuleLlvm,
) {
    use flate2::write::DeflateEncoder;
    use flate2::Compression;
    use std::io::Write;

    let (metadata_llcx, metadata_llmod) = (&*llvm_module.llcx, llvm_module.llmod());
    let mut compressed = tcx.metadata_encoding_version();
    DeflateEncoder::new(&mut compressed, Compression::fast())
        .write_all(&metadata.raw_data)
        .unwrap();

    let llmeta = common::bytes_in_context(metadata_llcx, &compressed);
    let llconst = common::struct_in_context(metadata_llcx, &[llmeta], false);
    let name = exported_symbols::metadata_symbol_name(tcx);
    let buf = CString::new(name).unwrap();
    let llglobal =
        unsafe { llvm::LLVMAddGlobal(metadata_llmod, common::val_ty(llconst), buf.as_ptr()) };
    unsafe {
        llvm::LLVMSetInitializer(llglobal, llconst);
        let section_name = metadata::metadata_section_name(&tcx.sess.target.target);
        let name = SmallCStr::new(section_name);
        llvm::LLVMSetSection(llglobal, name.as_ptr());

        // Also generate a .section directive to force no
        // flags, at least for ELF outputs, so that the
        // metadata doesn't get loaded into memory.
        let directive = format!(".section {}", section_name);
        llvm::LLVMSetModuleInlineAsm2(metadata_llmod, directive.as_ptr().cast(), directive.len())
    }
}

pub struct ValueIter<'ll> {
    cur: Option<&'ll Value>,
    step: unsafe extern "C" fn(&'ll Value) -> Option<&'ll Value>,
}

impl Iterator for ValueIter<'ll> {
    type Item = &'ll Value;

    fn next(&mut self) -> Option<&'ll Value> {
        let old = self.cur;
        if let Some(old) = old {
            self.cur = unsafe { (self.step)(old) };
        }
        old
    }
}

pub fn iter_globals(llmod: &'ll llvm::Module) -> ValueIter<'ll> {
    unsafe { ValueIter { cur: llvm::LLVMGetFirstGlobal(llmod), step: llvm::LLVMGetNextGlobal } }
}

pub fn compile_codegen_unit(
    tcx: TyCtxt<'tcx>,
    cgu_name: Symbol,
) -> (ModuleCodegen<ModuleLlvm>, u64) {
    let prof_timer = tcx.prof.generic_activity("codegen_module");
    let start_time = Instant::now();

    let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx);
    let (module, _) =
        tcx.dep_graph.with_task(dep_node, tcx, cgu_name, module_codegen, dep_graph::hash_result);
    let time_to_codegen = start_time.elapsed();
    drop(prof_timer);

    // We assume that the cost to run LLVM on a CGU is proportional to
    // the time we needed for codegenning it.
    let cost = time_to_codegen.as_secs() * 1_000_000_000 + time_to_codegen.subsec_nanos() as u64;

    fn module_codegen(tcx: TyCtxt<'_>, cgu_name: Symbol) -> ModuleCodegen<ModuleLlvm> {
        let cgu = tcx.codegen_unit(cgu_name);
        // Instantiate monomorphizations without filling out definitions yet...
        let llvm_module = ModuleLlvm::new(tcx, &cgu_name.as_str());
        {
            let cx = CodegenCx::new(tcx, cgu, &llvm_module);
            let mono_items = cx.codegen_unit.items_in_deterministic_order(cx.tcx);
            for &(mono_item, (linkage, visibility)) in &mono_items {
                mono_item.predefine::<Builder<'_, '_, '_>>(&cx, linkage, visibility);
            }

            // ... and now that we have everything pre-defined, fill out those definitions.
            for &(mono_item, _) in &mono_items {
                mono_item.define::<Builder<'_, '_, '_>>(&cx);
            }

            // If this codegen unit contains the main function, also create the
            // wrapper here
            if let Some(entry) = maybe_create_entry_wrapper::<Builder<'_, '_, '_>>(&cx) {
                attributes::sanitize(&cx, CodegenFnAttrFlags::empty(), entry);
            }

            // Run replace-all-uses-with for statics that need it
            for &(old_g, new_g) in cx.statics_to_rauw().borrow().iter() {
                unsafe {
                    let bitcast = llvm::LLVMConstPointerCast(new_g, cx.val_ty(old_g));
                    llvm::LLVMReplaceAllUsesWith(old_g, bitcast);
                    llvm::LLVMDeleteGlobal(old_g);
                }
            }

            // Create the llvm.used variable
            // This variable has type [N x i8*] and is stored in the llvm.metadata section
            if !cx.used_statics().borrow().is_empty() {
                cx.create_used_variable()
            }

            // Finalize debuginfo
            if cx.sess().opts.debuginfo != DebugInfo::None {
                cx.debuginfo_finalize();
            }
        }

        ModuleCodegen {
            name: cgu_name.to_string(),
            module_llvm: llvm_module,
            kind: ModuleKind::Regular,
        }
    }

    (module, cost)
}

pub fn set_link_section(llval: &Value, attrs: &CodegenFnAttrs) {
    let sect = match attrs.link_section {
        Some(name) => name,
        None => return,
    };
    unsafe {
        let buf = SmallCStr::new(&sect.as_str());
        llvm::LLVMSetSection(llval, buf.as_ptr());
    }
}

pub fn linkage_to_llvm(linkage: Linkage) -> llvm::Linkage {
    match linkage {
        Linkage::External => llvm::Linkage::ExternalLinkage,
        Linkage::AvailableExternally => llvm::Linkage::AvailableExternallyLinkage,
        Linkage::LinkOnceAny => llvm::Linkage::LinkOnceAnyLinkage,
        Linkage::LinkOnceODR => llvm::Linkage::LinkOnceODRLinkage,
        Linkage::WeakAny => llvm::Linkage::WeakAnyLinkage,
        Linkage::WeakODR => llvm::Linkage::WeakODRLinkage,
        Linkage::Appending => llvm::Linkage::AppendingLinkage,
        Linkage::Internal => llvm::Linkage::InternalLinkage,
        Linkage::Private => llvm::Linkage::PrivateLinkage,
        Linkage::ExternalWeak => llvm::Linkage::ExternalWeakLinkage,
        Linkage::Common => llvm::Linkage::CommonLinkage,
    }
}

pub fn visibility_to_llvm(linkage: Visibility) -> llvm::Visibility {
    match linkage {
        Visibility::Default => llvm::Visibility::Default,
        Visibility::Hidden => llvm::Visibility::Hidden,
        Visibility::Protected => llvm::Visibility::Protected,
    }
}
<commit_msg>[self-profling] Record the cgu name when doing codegen for a module<commit_after>//! Codegen the completed AST to the LLVM IR.
//!
//! Some functions here, such as codegen_block and codegen_expr, return a value --
//! the result of the codegen to LLVM -- while others, such as codegen_fn
//! and mono_item, are called only for the side effect of adding a
//! particular definition to the LLVM IR output we're producing.
//!
//! Hopefully useful general knowledge about codegen:
//!
//! * There's no way to find out the `Ty` type of a Value. Doing so
//!   would be "trying to get the eggs out of an omelette" (credit:
//!   pcwalton). You can, instead, find out its `llvm::Type` by calling `val_ty`,
//!   but one `llvm::Type` corresponds to many `Ty`s; for instance, `tup(int, int,
//!   int)` and `rec(x=int, y=int, z=int)` will have the same `llvm::Type`.

use super::ModuleLlvm;

use crate::attributes;
use crate::builder::Builder;
use crate::common;
use crate::context::CodegenCx;
use crate::llvm;
use crate::metadata;
use crate::value::Value;

use rustc_codegen_ssa::base::maybe_create_entry_wrapper;
use rustc_codegen_ssa::mono_item::MonoItemExt;
use rustc_codegen_ssa::traits::*;
use rustc_codegen_ssa::{ModuleCodegen, ModuleKind};
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_middle::dep_graph;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc_middle::middle::cstore::EncodedMetadata;
use rustc_middle::middle::exported_symbols;
use rustc_middle::mir::mono::{Linkage, Visibility};
use rustc_middle::ty::TyCtxt;
use rustc_session::config::DebugInfo;
use rustc_span::symbol::Symbol;

use std::ffi::CString;
use std::time::Instant;

pub fn write_compressed_metadata<'tcx>(
    tcx: TyCtxt<'tcx>,
    metadata: &EncodedMetadata,
    llvm_module: &mut ModuleLlvm,
) {
    use flate2::write::DeflateEncoder;
    use flate2::Compression;
    use std::io::Write;

    let (metadata_llcx, metadata_llmod) = (&*llvm_module.llcx, llvm_module.llmod());
    let mut compressed = tcx.metadata_encoding_version();
    DeflateEncoder::new(&mut compressed, Compression::fast())
        .write_all(&metadata.raw_data)
        .unwrap();

    let llmeta = common::bytes_in_context(metadata_llcx, &compressed);
    let llconst = common::struct_in_context(metadata_llcx, &[llmeta], false);
    let name = exported_symbols::metadata_symbol_name(tcx);
    let buf = CString::new(name).unwrap();
    let llglobal =
        unsafe { llvm::LLVMAddGlobal(metadata_llmod, common::val_ty(llconst), buf.as_ptr()) };
    unsafe {
        llvm::LLVMSetInitializer(llglobal, llconst);
        let section_name = metadata::metadata_section_name(&tcx.sess.target.target);
        let name = SmallCStr::new(section_name);
        llvm::LLVMSetSection(llglobal, name.as_ptr());

        // Also generate a .section directive to force no
        // flags, at least for ELF outputs, so that the
        // metadata doesn't get loaded into memory.
        let directive = format!(".section {}", section_name);
        llvm::LLVMSetModuleInlineAsm2(metadata_llmod, directive.as_ptr().cast(), directive.len())
    }
}

pub struct ValueIter<'ll> {
    cur: Option<&'ll Value>,
    step: unsafe extern "C" fn(&'ll Value) -> Option<&'ll Value>,
}

impl Iterator for ValueIter<'ll> {
    type Item = &'ll Value;

    fn next(&mut self) -> Option<&'ll Value> {
        let old = self.cur;
        if let Some(old) = old {
            self.cur = unsafe { (self.step)(old) };
        }
        old
    }
}

pub fn iter_globals(llmod: &'ll llvm::Module) -> ValueIter<'ll> {
    unsafe { ValueIter { cur: llvm::LLVMGetFirstGlobal(llmod), step: llvm::LLVMGetNextGlobal } }
}

pub fn compile_codegen_unit(
    tcx: TyCtxt<'tcx>,
    cgu_name: Symbol,
) -> (ModuleCodegen<ModuleLlvm>, u64) {
    let prof_timer = tcx.prof.generic_activity_with_arg("codegen_module", cgu_name.to_string());
    let start_time = Instant::now();

    let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx);
    let (module, _) =
        tcx.dep_graph.with_task(dep_node, tcx, cgu_name, module_codegen, dep_graph::hash_result);
    let time_to_codegen = start_time.elapsed();
    drop(prof_timer);

    // We assume that the cost to run LLVM on a CGU is proportional to
    // the time we needed for codegenning it.
    let cost = time_to_codegen.as_secs() * 1_000_000_000 + time_to_codegen.subsec_nanos() as u64;

    fn module_codegen(tcx: TyCtxt<'_>, cgu_name: Symbol) -> ModuleCodegen<ModuleLlvm> {
        let cgu = tcx.codegen_unit(cgu_name);
        // Instantiate monomorphizations without filling out definitions yet...
        let llvm_module = ModuleLlvm::new(tcx, &cgu_name.as_str());
        {
            let cx = CodegenCx::new(tcx, cgu, &llvm_module);
            let mono_items = cx.codegen_unit.items_in_deterministic_order(cx.tcx);
            for &(mono_item, (linkage, visibility)) in &mono_items {
                mono_item.predefine::<Builder<'_, '_, '_>>(&cx, linkage, visibility);
            }

            // ... and now that we have everything pre-defined, fill out those definitions.
            for &(mono_item, _) in &mono_items {
                mono_item.define::<Builder<'_, '_, '_>>(&cx);
            }

            // If this codegen unit contains the main function, also create the
            // wrapper here
            if let Some(entry) = maybe_create_entry_wrapper::<Builder<'_, '_, '_>>(&cx) {
                attributes::sanitize(&cx, CodegenFnAttrFlags::empty(), entry);
            }

            // Run replace-all-uses-with for statics that need it
            for &(old_g, new_g) in cx.statics_to_rauw().borrow().iter() {
                unsafe {
                    let bitcast = llvm::LLVMConstPointerCast(new_g, cx.val_ty(old_g));
                    llvm::LLVMReplaceAllUsesWith(old_g, bitcast);
                    llvm::LLVMDeleteGlobal(old_g);
                }
            }

            // Create the llvm.used variable
            // This variable has type [N x i8*] and is stored in the llvm.metadata section
            if !cx.used_statics().borrow().is_empty() {
                cx.create_used_variable()
            }

            // Finalize debuginfo
            if cx.sess().opts.debuginfo != DebugInfo::None {
                cx.debuginfo_finalize();
            }
        }

        ModuleCodegen {
            name: cgu_name.to_string(),
            module_llvm: llvm_module,
            kind: ModuleKind::Regular,
        }
    }

    (module, cost)
}

pub fn set_link_section(llval: &Value, attrs: &CodegenFnAttrs) {
    let sect = match attrs.link_section {
        Some(name) => name,
        None => return,
    };
    unsafe {
        let buf = SmallCStr::new(&sect.as_str());
        llvm::LLVMSetSection(llval, buf.as_ptr());
    }
}

pub fn linkage_to_llvm(linkage: Linkage) -> llvm::Linkage {
    match linkage {
        Linkage::External => llvm::Linkage::ExternalLinkage,
        Linkage::AvailableExternally => llvm::Linkage::AvailableExternallyLinkage,
        Linkage::LinkOnceAny => llvm::Linkage::LinkOnceAnyLinkage,
        Linkage::LinkOnceODR => llvm::Linkage::LinkOnceODRLinkage,
        Linkage::WeakAny => llvm::Linkage::WeakAnyLinkage,
        Linkage::WeakODR => llvm::Linkage::WeakODRLinkage,
        Linkage::Appending => llvm::Linkage::AppendingLinkage,
        Linkage::Internal => llvm::Linkage::InternalLinkage,
        Linkage::Private => llvm::Linkage::PrivateLinkage,
        Linkage::ExternalWeak => llvm::Linkage::ExternalWeakLinkage,
        Linkage::Common => llvm::Linkage::CommonLinkage,
    }
}

pub fn visibility_to_llvm(linkage: Visibility) -> llvm::Visibility {
    match linkage {
        Visibility::Default => llvm::Visibility::Default,
        Visibility::Hidden => llvm::Visibility::Hidden,
        Visibility::Protected => llvm::Visibility::Protected,
    }
}
<|endoftext|>