<commit_before>use bluetooth_utils;
use dbus::MessageItem;
use rustc_serialize::hex::FromHex;
use std::collections::HashMap;
use std::error::Error;

static DEVICE_INTERFACE: &'static str = "org.bluez.Device1";

#[derive(Clone, Debug)]
pub struct BluetoothDevice {
    object_path: String,
}

impl BluetoothDevice {
    pub fn new(object_path: String)
           -> BluetoothDevice {
        BluetoothDevice {
            object_path: object_path
        }
    }

    pub fn get_id(&self) -> String {
        self.object_path.clone()
    }

    fn get_property(&self, prop: &str) -> Result<MessageItem, Box<Error>> {
        bluetooth_utils::get_property(DEVICE_INTERFACE, &self.object_path, prop)
    }

    fn set_property<T>(&self, prop: &str, value: T) -> Result<(), Box<Error>>
    where T: Into<MessageItem> {
        bluetooth_utils::set_property(DEVICE_INTERFACE, &self.object_path, prop, value)
    }

    fn call_method(&self, method: &str, param: Option<[MessageItem; 1]>) -> Result<(), Box<Error>> {
        bluetooth_utils::call_method(DEVICE_INTERFACE, &self.object_path, method, param)
    }

/*
 * Properties
 */
    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n105
    pub fn get_address(&self) -> Result<String, Box<Error>> {
        let address = try!(self.get_property("Address"));
        Ok(String::from(address.inner::<&str>().unwrap()))
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n109
    pub fn get_name(&self) -> Result<String, Box<Error>> {
        let name = try!(self.get_property("Name"));
        Ok(String::from(name.inner::<&str>().unwrap()))
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n121
    pub fn get_icon(&self) -> Result<String, Box<Error>> {
        let icon = try!(self.get_property("Icon"));
        Ok(String::from(icon.inner::<&str>().unwrap()))
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n126
    pub fn get_class(&self) -> Result<u32, Box<Error>> {
        let class = try!(self.get_property("Class"));
        Ok(class.inner::<u32>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n126
    pub fn get_appearance(&self) -> Result<u16, Box<Error>> {
        let appearance = try!(self.get_property("Appearance"));
        Ok(appearance.inner::<u16>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n134
    pub fn get_uuids(&self) -> Result<Vec<String>, Box<Error>> {
        let uuids = try!(self.get_property("UUIDs"));
        let z: &[MessageItem] = uuids.inner().unwrap();
        let mut v: Vec<String> = Vec::new();
        for y in z {
            v.push(String::from(y.inner::<&str>().unwrap()));
        }
        Ok(v)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n139
    pub fn is_paired(&self) -> Result<bool, Box<Error>> {
         let paired = try!(self.get_property("Paired"));
         Ok(paired.inner::<bool>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n143
    pub fn is_connected(&self) -> Result<bool, Box<Error>> {
         let connected = try!(self.get_property("Connected"));
         Ok(connected.inner::<bool>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n149
    pub fn is_trusted(&self) -> Result<bool, Box<Error>> {
        let trusted = try!(self.get_property("Trusted"));
        Ok(trusted.inner::<bool>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n154
    pub fn is_blocked(&self) -> Result<bool, Box<Error>> {
        let blocked = try!(self.get_property("Blocked"));
        Ok(blocked.inner::<bool>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n161
    pub fn get_alias(&self) -> Result<String, Box<Error>> {
        let alias = try!(self.get_property("Alias"));
        Ok(String::from(alias.inner::<&str>().unwrap()))
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n161
    pub fn set_alias(&self, value: String) -> Result<(),Box<Error>> {
        self.set_property("Alias", value)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n174
    pub fn get_adapter(&self) -> Result<String, Box<Error>> {
        let adapter = try!(self.get_property("Adapter"));
        Ok(String::from(adapter.inner::<&str>().unwrap()))
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n178
    pub fn is_legacy_pairing(&self) -> Result<bool, Box<Error>> {
        let legacy_pairing = try!(self.get_property("LegacyPairing"));
        Ok(legacy_pairing.inner::<bool>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n189
    pub fn get_modalias(&self) ->  Result<(String, u32, u32, u32), Box<Error>> {
        let modalias = try!(self.get_property("Modalias"));
        let m = modalias.inner::<&str>().unwrap();
        let ids: Vec<&str> = m.split(":").collect();

        let source = String::from(ids[0]);
        let vendor = ids[1][1..5].from_hex().unwrap();
        let product = ids[1][6..10].from_hex().unwrap();
        let device = ids[1][11..15].from_hex().unwrap();

        Ok((source,
        (vendor[0] as u32) * 16 * 16 + (vendor[1] as u32),
        (product[0] as u32) * 16 * 16 + (product[1] as u32),
        (device[0] as u32) * 16 * 16 + (device[1] as u32)))
    }

    pub fn get_vendor_id_source(&self) -> Result<String, Box<Error>> {
        let (vendor_id_source,_,_,_) = try!(self.get_modalias());
        Ok(vendor_id_source)
    }

    pub fn get_vendor_id(&self) -> Result<u32, Box<Error>> {
        let (_,vendor_id,_,_) = try!(self.get_modalias());
        Ok(vendor_id)
    }

    pub fn get_product_id(&self) -> Result<u32, Box<Error>> {
        let (_,_,product_id,_) = try!(self.get_modalias());
        Ok(product_id)
    }

    pub fn get_device_id(&self) -> Result<u32, Box<Error>> {
        let (_,_,_,device_id) = try!(self.get_modalias());
        Ok(device_id)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n194
    pub fn get_rssi(&self) -> Result<i16, Box<Error>> {
        let rssi = try!(self.get_property("RSSI"));
        Ok(rssi.inner::<i16>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n199
    pub fn get_tx_power(&self) -> Result<i16, Box<Error>> {
        let tx_power = try!(self.get_property("TxPower"));
        Ok(tx_power.inner::<i16>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n204
    pub fn get_manufacturer_data(&self) -> Result<HashMap<u16, Vec<u8>>, Box<Error>> {
        unimplemented!()
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n210
    pub fn get_service_data(&self) -> Result<HashMap<String, Vec<u8>>, Box<Error>> {
        unimplemented!()
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n215
    pub fn get_gatt_services(&self) -> Result<Vec<String>, Box<Error>> {
        bluetooth_utils::list_services(&self.object_path)
    }

/*
 * Methods
 */

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n12
    pub fn connect(&self) -> Result<(), Box<Error>> {
        self.call_method("Connect", None)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n29
    pub fn disconnect(&self) -> Result<(), Box<Error>>{
        self.call_method("Disconnect", None)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n43
    pub fn connect_profile(&self, uuid: String) -> Result<(), Box<Error>>{
        self.call_method("Connectprofile", Some([uuid.into()]))
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n55
    pub fn disconnect_profile(&self, uuid: String) -> Result<(), Box<Error>>{
        self.call_method("DisconnectProfile", Some([uuid.into()]))
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n70
    pub fn pair(&self) -> Result<(), Box<Error>>{
        self.call_method("Pair", None)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n97
    pub fn cancel_pairing(&self) -> Result<(), Box<Error>>{
        self.call_method("CancelPairing", None)
    }
}
<commit_msg>Service and Manufacturer Data support<commit_after>use bluetooth_utils;
use dbus::MessageItem;
use rustc_serialize::hex::FromHex;
use std::collections::HashMap;
use std::error::Error;

static DEVICE_INTERFACE: &'static str = "org.bluez.Device1";

#[derive(Clone, Debug)]
pub struct BluetoothDevice {
    object_path: String,
}

impl BluetoothDevice {
    pub fn new(object_path: String)
           -> BluetoothDevice {
        BluetoothDevice {
            object_path: object_path
        }
    }

    pub fn get_id(&self) -> String {
        self.object_path.clone()
    }

    fn get_property(&self, prop: &str) -> Result<MessageItem, Box<Error>> {
        bluetooth_utils::get_property(DEVICE_INTERFACE, &self.object_path, prop)
    }

    fn set_property<T>(&self, prop: &str, value: T) -> Result<(), Box<Error>>
    where T: Into<MessageItem> {
        bluetooth_utils::set_property(DEVICE_INTERFACE, &self.object_path, prop, value)
    }

    fn call_method(&self, method: &str, param: Option<[MessageItem; 1]>) -> Result<(), Box<Error>> {
        bluetooth_utils::call_method(DEVICE_INTERFACE, &self.object_path, method, param)
    }

/*
 * Properties
 */
    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n105
    pub fn get_address(&self) -> Result<String, Box<Error>> {
        let address = try!(self.get_property("Address"));
        Ok(String::from(address.inner::<&str>().unwrap()))
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n109
    pub fn get_name(&self) -> Result<String, Box<Error>> {
        let name = try!(self.get_property("Name"));
        Ok(String::from(name.inner::<&str>().unwrap()))
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n121
    pub fn get_icon(&self) -> Result<String, Box<Error>> {
        let icon = try!(self.get_property("Icon"));
        Ok(String::from(icon.inner::<&str>().unwrap()))
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n126
    pub fn get_class(&self) -> Result<u32, Box<Error>> {
        let class = try!(self.get_property("Class"));
        Ok(class.inner::<u32>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n126
    pub fn get_appearance(&self) -> Result<u16, Box<Error>> {
        let appearance = try!(self.get_property("Appearance"));
        Ok(appearance.inner::<u16>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n134
    pub fn get_uuids(&self) -> Result<Vec<String>, Box<Error>> {
        let uuids = try!(self.get_property("UUIDs"));
        let z: &[MessageItem] = uuids.inner().unwrap();
        let mut v: Vec<String> = Vec::new();
        for y in z {
            v.push(String::from(y.inner::<&str>().unwrap()));
        }
        Ok(v)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n139
    pub fn is_paired(&self) -> Result<bool, Box<Error>> {
         let paired = try!(self.get_property("Paired"));
         Ok(paired.inner::<bool>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n143
    pub fn is_connected(&self) -> Result<bool, Box<Error>> {
         let connected = try!(self.get_property("Connected"));
         Ok(connected.inner::<bool>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n149
    pub fn is_trusted(&self) -> Result<bool, Box<Error>> {
        let trusted = try!(self.get_property("Trusted"));
        Ok(trusted.inner::<bool>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n154
    pub fn is_blocked(&self) -> Result<bool, Box<Error>> {
        let blocked = try!(self.get_property("Blocked"));
        Ok(blocked.inner::<bool>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n161
    pub fn get_alias(&self) -> Result<String, Box<Error>> {
        let alias = try!(self.get_property("Alias"));
        Ok(String::from(alias.inner::<&str>().unwrap()))
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n161
    pub fn set_alias(&self, value: String) -> Result<(),Box<Error>> {
        self.set_property("Alias", value)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n174
    pub fn get_adapter(&self) -> Result<String, Box<Error>> {
        let adapter = try!(self.get_property("Adapter"));
        Ok(String::from(adapter.inner::<&str>().unwrap()))
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n178
    pub fn is_legacy_pairing(&self) -> Result<bool, Box<Error>> {
        let legacy_pairing = try!(self.get_property("LegacyPairing"));
        Ok(legacy_pairing.inner::<bool>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n189
    pub fn get_modalias(&self) ->  Result<(String, u32, u32, u32), Box<Error>> {
        let modalias = try!(self.get_property("Modalias"));
        let m = modalias.inner::<&str>().unwrap();
        let ids: Vec<&str> = m.split(":").collect();

        let source = String::from(ids[0]);
        let vendor = ids[1][1..5].from_hex().unwrap();
        let product = ids[1][6..10].from_hex().unwrap();
        let device = ids[1][11..15].from_hex().unwrap();

        Ok((source,
        (vendor[0] as u32) * 16 * 16 + (vendor[1] as u32),
        (product[0] as u32) * 16 * 16 + (product[1] as u32),
        (device[0] as u32) * 16 * 16 + (device[1] as u32)))
    }

    pub fn get_vendor_id_source(&self) -> Result<String, Box<Error>> {
        let (vendor_id_source,_,_,_) = try!(self.get_modalias());
        Ok(vendor_id_source)
    }

    pub fn get_vendor_id(&self) -> Result<u32, Box<Error>> {
        let (_,vendor_id,_,_) = try!(self.get_modalias());
        Ok(vendor_id)
    }

    pub fn get_product_id(&self) -> Result<u32, Box<Error>> {
        let (_,_,product_id,_) = try!(self.get_modalias());
        Ok(product_id)
    }

    pub fn get_device_id(&self) -> Result<u32, Box<Error>> {
        let (_,_,_,device_id) = try!(self.get_modalias());
        Ok(device_id)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n194
    pub fn get_rssi(&self) -> Result<i16, Box<Error>> {
        let rssi = try!(self.get_property("RSSI"));
        Ok(rssi.inner::<i16>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n199
    pub fn get_tx_power(&self) -> Result<i16, Box<Error>> {
        let tx_power = try!(self.get_property("TxPower"));
        Ok(tx_power.inner::<i16>().unwrap())
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n204
    pub fn get_manufacturer_data(&self) -> Result<HashMap<u16, Vec<u8>>, Box<Error>> {
        let manufacturer_data_array = try!(self.get_property("ManufacturerData"));
        let mut m = HashMap::new();
        let dict_vec = manufacturer_data_array.inner::<&Vec<MessageItem>>().unwrap();
        for dict in dict_vec {
            let (key, value) = dict.inner::<(&MessageItem, &MessageItem)>().unwrap();
            let v = value.inner::<&MessageItem>().unwrap()
                         .inner::<&Vec<MessageItem>>().unwrap()
                         .into_iter()
                         .map(|b| b.inner::<u8>().unwrap_or(0))
                         .collect();
            m.insert(key.inner::<u16>().unwrap(), v);
        }
        Ok(m)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n210
    pub fn get_service_data(&self) -> Result<HashMap<String, Vec<u8>>, Box<Error>> {
        let service_data_array = try!(self.get_property("ServiceData"));
        let mut m = HashMap::new();
        let dict_vec = service_data_array.inner::<&Vec<MessageItem>>().unwrap();
        for dict in dict_vec {
            let (key, value) = dict.inner::<(&MessageItem, &MessageItem)>().unwrap();
            let v = value.inner::<&MessageItem>().unwrap()
                         .inner::<&Vec<MessageItem>>().unwrap()
                         .into_iter()
                         .map(|b| b.inner::<u8>().unwrap_or(0))
                         .collect();
            m.insert(key.inner::<&str>().unwrap().to_string(), v);
        }
        Ok(m)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n215
    pub fn get_gatt_services(&self) -> Result<Vec<String>, Box<Error>> {
        bluetooth_utils::list_services(&self.object_path)
    }

/*
 * Methods
 */

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n12
    pub fn connect(&self) -> Result<(), Box<Error>> {
        self.call_method("Connect", None)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n29
    pub fn disconnect(&self) -> Result<(), Box<Error>>{
        self.call_method("Disconnect", None)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n43
    pub fn connect_profile(&self, uuid: String) -> Result<(), Box<Error>>{
        self.call_method("Connectprofile", Some([uuid.into()]))
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n55
    pub fn disconnect_profile(&self, uuid: String) -> Result<(), Box<Error>>{
        self.call_method("DisconnectProfile", Some([uuid.into()]))
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n70
    pub fn pair(&self) -> Result<(), Box<Error>>{
        self.call_method("Pair", None)
    }

    // http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt#n97
    pub fn cancel_pairing(&self) -> Result<(), Box<Error>>{
        self.call_method("CancelPairing", None)
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 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 target::TargetOptions;
use std::default::Default;

pub fn opts() -> TargetOptions {
    TargetOptions {
        linker: "cc".to_string(),
        dynamic_linking: true,
        executables: true,
        morestack: true,
        has_rpath: true,
        archive_format: "".to_string(),

        .. Default::default()
    }
}
<commit_msg>switching to gnu archive format<commit_after>// Copyright 2014 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 target::TargetOptions;
use std::default::Default;

pub fn opts() -> TargetOptions {
    TargetOptions {
        linker: "cc".to_string(),
        dynamic_linking: true,
        executables: true,
        morestack: true,
        has_rpath: true,
        archive_format: "gnu".to_string(),

        .. Default::default()
    }
}
<|endoftext|>


<commit_before>use rustc::hir::Mutability;
use rustc::mir::{self, ValidationOp};
use rustc::ty::{self, Ty, TypeFoldable};
use rustc::traits::Reveal;
use rustc::infer::TransNormalize;
use rustc::middle::region::CodeExtent;

use error::{EvalError, EvalResult};
use eval_context::{EvalContext};
use memory::AccessKind;
use value::Value;
use lvalue::{Lvalue, LvalueExtra};

// Validity checks
#[derive(Copy, Clone, Debug)]
pub struct ValidationCtx {
    op: ValidationOp,
    region: Option<CodeExtent>,
    mutbl: Mutability,
}

impl ValidationCtx {
    pub fn new(op: ValidationOp) -> Self {
        ValidationCtx {
            op, region: None, mutbl: Mutability::MutMutable,
        }
    }
}

impl<'a, 'tcx> EvalContext<'a, 'tcx> {
    fn validate_variant(
        &mut self,
        lvalue: Lvalue<'tcx>,
        ty: Ty<'tcx>,
        variant: &ty::VariantDef,
        subst: &ty::subst::Substs<'tcx>,
        vctx: ValidationCtx,
    ) -> EvalResult<'tcx> {
        // TODO: Take visibility/privacy into account.
        for (idx, field) in variant.fields.iter().enumerate() {
            let field_ty = field.ty(self.tcx, subst);
            let field_lvalue = self.lvalue_field(lvalue, idx, ty, field_ty)?;
            self.validate(field_lvalue, field_ty, vctx)?;
        }
        Ok(())
    }

    fn validate_ptr(&mut self, val: Value, pointee_ty: Ty<'tcx>, vctx: ValidationCtx) -> EvalResult<'tcx> {
        // Check alignment and non-NULLness
        let (_, align) = self.size_and_align_of_dst(pointee_ty, val)?;
        let ptr = val.into_ptr(&mut self.memory)?;
        self.memory.check_align(ptr, align)?;

        // Recurse
        let pointee_lvalue = self.val_to_lvalue(val, pointee_ty)?;
        self.validate(pointee_lvalue, pointee_ty, vctx)
    }

    /// Validate the lvalue at the given type. If `release` is true, just do a release of all write locks
    pub(super) fn validate(&mut self, lvalue: Lvalue<'tcx>, mut ty: Ty<'tcx>, mut vctx: ValidationCtx) -> EvalResult<'tcx>
    {
        use rustc::ty::TypeVariants::*;
        use rustc::ty::RegionKind::*;
        use rustc::ty::AdtKind;
        use self::Mutability::*;

        // This is essentially a copy of normalize_associated_type, but without erasure
        if ty.has_projection_types() {
            let param_env = ty::ParamEnv::empty(Reveal::All);
            ty = self.tcx.infer_ctxt().enter(move |infcx| {
                ty.trans_normalize(&infcx, param_env)
            })
        }
        let ty = ty; // no more mutation
        trace!("Validating {:?} at type {}, context {:?}", lvalue, ty, vctx);

        // Decide whether this type *owns* the memory it covers (like integers), or whether it
        // just assembles pieces (that each own their memory) together to a larger whole.
        // TODO: Currently, we don't acquire locks for padding and discriminants. We should.
        let is_owning = match ty.sty {
            TyInt(_) | TyUint(_) | TyRawPtr(_) |
            TyBool | TyFloat(_) | TyChar | TyStr |
            TyRef(..) | TyFnPtr(..) | TyNever => true,
            TyAdt(adt, _) if adt.is_box() => true,
            TySlice(_) | TyAdt(_, _) | TyTuple(..) | TyClosure(..) | TyArray(..) | TyDynamic(..) => false,
            TyParam(_) | TyInfer(_) => bug!("I got an incomplete type for validation"),
            _ => return Err(EvalError::Unimplemented(format!("Unimplemented type encountered when checking validity."))),
        };
        if is_owning {
            match lvalue {
                Lvalue::Ptr { ptr, extra, aligned: _ } => {
                    // Determine the size
                    // FIXME: Can we reuse size_and_align_of_dst for Lvalues?
                    let len = match self.type_size(ty)? {
                        Some(size) => {
                            assert_eq!(extra, LvalueExtra::None, "Got a fat ptr to a sized type");
                            size
                        }
                        None => {
                            // The only unsized typ we concider "owning" is TyStr.
                            assert_eq!(ty.sty, TyStr, "Found a surprising unsized owning type");
                            // The extra must be the length, in bytes.
                            match extra {
                                LvalueExtra::Length(len) => len,
                                _ => bug!("TyStr must have a length as extra"),
                            }
                        }
                    };
                    // Handle locking
                    if len > 0 {
                        let ptr = ptr.to_ptr()?;
                        let access = match vctx.mutbl { MutMutable => AccessKind::Write, MutImmutable => AccessKind::Read };
                        match vctx.op {
                            ValidationOp::Acquire => self.memory.acquire_lock(ptr, len, vctx.region, access)?,
                            ValidationOp::Release => self.memory.release_write_lock_until(ptr, len, None)?,
                            ValidationOp::Suspend(region) => self.memory.release_write_lock_until(ptr, len, Some(region))?,
                        }
                    }
                }
                Lvalue::Local { .. } | Lvalue::Global(..) => {
                    // These are not backed by memory, so we have nothing to do.
                }
            }
        }

        match ty.sty {
            TyInt(_) | TyUint(_) | TyRawPtr(_) => {
                // TODO: Make sure these are not undef.
                // We could do a bounds-check and other sanity checks on the lvalue, but it would be a bug in miri for this to ever fail.
                Ok(())
            }
            TyBool | TyFloat(_) | TyChar | TyStr => {
                // TODO: Check if these are valid bool/float/codepoint/UTF-8, respectively (and in particular, not undef).
                Ok(())
            }
            TyNever => {
                Err(EvalError::ValidationFailure(format!("The empty type is never valid.")))
            }
            TyRef(region, ty::TypeAndMut { ty: pointee_ty, mutbl }) => {
                let val = self.read_lvalue(lvalue)?;
                // Sharing restricts our context
                if mutbl == MutImmutable {
                    // Actually, in case of releasing-validation, this means we are done.
                    if vctx.op != ValidationOp::Acquire {
                        return Ok(());
                    }
                    vctx.mutbl = MutImmutable;
                }
                // Inner lifetimes *outlive* outer ones, so only if we have no lifetime restriction yet,
                // we record the region of this borrow to the context.
                if vctx.region == None {
                    match *region {
                        ReScope(ce) => vctx.region = Some(ce),
                        // It is possible for us to encode erased lifetimes here because the lifetimes in
                        // this functions' Subst will be erased.
                        _ => {},
                    }
                }
                self.validate_ptr(val, pointee_ty, vctx)
            }
            TyAdt(adt, _) if adt.is_box() => {
                let val = self.read_lvalue(lvalue)?;
                self.validate_ptr(val, ty.boxed_ty(), vctx)
            }
            TyFnPtr(_sig) => {
                // TODO: The function names here could need some improvement.
                let ptr = self.read_lvalue(lvalue)?.into_ptr(&mut self.memory)?.to_ptr()?;
                self.memory.get_fn(ptr)?;
                // TODO: Check if the signature matches (should be the same check as what terminator/mod.rs already does on call?).
                Ok(())
            }

            // Compound types
            TySlice(elem_ty) => {
                let len = match lvalue {
                    Lvalue::Ptr { extra: LvalueExtra::Length(len), .. } => len,
                    _ => bug!("acquire_valid of a TySlice given non-slice lvalue: {:?}", lvalue),
                };
                for i in 0..len {
                    let inner_lvalue = self.lvalue_index(lvalue, ty, i)?;
                    self.validate(inner_lvalue, elem_ty, vctx)?;
                }
                Ok(())
            }
            TyArray(elem_ty, len) => {
                for i in 0..len {
                    let inner_lvalue = self.lvalue_index(lvalue, ty, i as u64)?;
                    self.validate(inner_lvalue, elem_ty, vctx)?;
                }
                Ok(())
            }
            TyDynamic(_data, _region) => {
                // Check that this is a valid vtable
                let vtable = match lvalue {
                    Lvalue::Ptr { extra: LvalueExtra::Vtable(vtable), .. } => vtable,
                    _ => bug!("acquire_valid of a TyDynamic given non-trait-object lvalue: {:?}", lvalue),
                };
                self.read_size_and_align_from_vtable(vtable)?;
                // TODO: Check that the vtable contains all the function pointers we expect it to have.
                // TODO: Is there anything we can/should validate here?  Trait objects cannot have any operations performed
                // on them directly.  We cannot, in general, even acquire any locks as the trait object *could*
                // contain an UnsafeCell.  If we call functions to get access to data, we will validate
                // their return values.  So, it doesn't seem like there's anything to do.
                Ok(())
            }
            TyAdt(adt, subst) => {
                if Some(adt.did) == self.tcx.lang_items.unsafe_cell_type() {
                    // No locks for unsafe cells.  Also no other validation, the only field is private anyway.
                    return Ok(());
                }

                match adt.adt_kind() {
                    AdtKind::Enum => {
                        // TODO: Can we get the discriminant without forcing an allocation?
                        let ptr = self.force_allocation(lvalue)?.to_ptr()?;
                        let discr = self.read_discriminant_value(ptr, ty)?;

                        // Get variant index for discriminant
                        let variant_idx = adt.discriminants(self.tcx)
                            .position(|variant_discr| variant_discr.to_u128_unchecked() == discr)
                            .ok_or(EvalError::InvalidDiscriminant)?;
                        let variant = &adt.variants[variant_idx];

                        if variant.fields.len() > 0 {
                            // Downcast to this variant, if needed
                            let lvalue = if adt.variants.len() > 1 {
                                self.eval_lvalue_projection(lvalue, ty, &mir::ProjectionElem::Downcast(adt, variant_idx))?
                            } else {
                                lvalue
                            };

                            // Recursively validate the fields
                            self.validate_variant(lvalue, ty, variant, subst, vctx)
                        } else {
                            // No fields, nothing left to check.  Downcasting may fail, e.g. in case of a CEnum.
                            Ok(())
                        }
                    }
                    AdtKind::Struct => {
                        self.validate_variant(lvalue, ty, adt.struct_variant(), subst, vctx)
                    }
                    AdtKind::Union => {
                        // No guarantees are provided for union types.
                        // TODO: Make sure that all access to union fields is unsafe; otherwise, we may have some checking to do (but what exactly?)
                        Ok(())
                    }
                }
            }
            TyTuple(ref types, _) => {
                for (idx, field_ty) in types.iter().enumerate() {
                    let field_lvalue = self.lvalue_field(lvalue, idx, ty, field_ty)?;
                    self.validate(field_lvalue, field_ty, vctx)?;
                }
                Ok(())
            }
            TyClosure(def_id, ref closure_substs) => {
                for (idx, field_ty) in closure_substs.upvar_tys(def_id, self.tcx).enumerate() {
                    let field_lvalue = self.lvalue_field(lvalue, idx, ty, field_ty)?;
                    self.validate(field_lvalue, field_ty, vctx)?;
                }
                // TODO: Check if the signature matches (should be the same check as what terminator/mod.rs already does on call?).
                // Is there other things we can/should check?  Like vtable pointers?
                Ok(())
            }
            _ => bug!("We already establishd that this is a type we support.")
        }
    }
}
<commit_msg>handle type of function definitions (98)<commit_after>use rustc::hir::Mutability;
use rustc::mir::{self, ValidationOp};
use rustc::ty::{self, Ty, TypeFoldable};
use rustc::traits::Reveal;
use rustc::infer::TransNormalize;
use rustc::middle::region::CodeExtent;

use error::{EvalError, EvalResult};
use eval_context::{EvalContext};
use memory::AccessKind;
use value::Value;
use lvalue::{Lvalue, LvalueExtra};

// Validity checks
#[derive(Copy, Clone, Debug)]
pub struct ValidationCtx {
    op: ValidationOp,
    region: Option<CodeExtent>,
    mutbl: Mutability,
}

impl ValidationCtx {
    pub fn new(op: ValidationOp) -> Self {
        ValidationCtx {
            op, region: None, mutbl: Mutability::MutMutable,
        }
    }
}

impl<'a, 'tcx> EvalContext<'a, 'tcx> {
    fn validate_variant(
        &mut self,
        lvalue: Lvalue<'tcx>,
        ty: Ty<'tcx>,
        variant: &ty::VariantDef,
        subst: &ty::subst::Substs<'tcx>,
        vctx: ValidationCtx,
    ) -> EvalResult<'tcx> {
        // TODO: Take visibility/privacy into account.
        for (idx, field) in variant.fields.iter().enumerate() {
            let field_ty = field.ty(self.tcx, subst);
            let field_lvalue = self.lvalue_field(lvalue, idx, ty, field_ty)?;
            self.validate(field_lvalue, field_ty, vctx)?;
        }
        Ok(())
    }

    fn validate_ptr(&mut self, val: Value, pointee_ty: Ty<'tcx>, vctx: ValidationCtx) -> EvalResult<'tcx> {
        // Check alignment and non-NULLness
        let (_, align) = self.size_and_align_of_dst(pointee_ty, val)?;
        let ptr = val.into_ptr(&mut self.memory)?;
        self.memory.check_align(ptr, align)?;

        // Recurse
        let pointee_lvalue = self.val_to_lvalue(val, pointee_ty)?;
        self.validate(pointee_lvalue, pointee_ty, vctx)
    }

    /// Validate the lvalue at the given type. If `release` is true, just do a release of all write locks
    pub(super) fn validate(&mut self, lvalue: Lvalue<'tcx>, mut ty: Ty<'tcx>, mut vctx: ValidationCtx) -> EvalResult<'tcx>
    {
        use rustc::ty::TypeVariants::*;
        use rustc::ty::RegionKind::*;
        use rustc::ty::AdtKind;
        use self::Mutability::*;

        // This is essentially a copy of normalize_associated_type, but without erasure
        if ty.has_projection_types() {
            let param_env = ty::ParamEnv::empty(Reveal::All);
            ty = self.tcx.infer_ctxt().enter(move |infcx| {
                ty.trans_normalize(&infcx, param_env)
            })
        }
        let ty = ty; // no more mutation
        trace!("Validating {:?} at type {}, context {:?}", lvalue, ty, vctx);

        // Decide whether this type *owns* the memory it covers (like integers), or whether it
        // just assembles pieces (that each own their memory) together to a larger whole.
        // TODO: Currently, we don't acquire locks for padding and discriminants. We should.
        let is_owning = match ty.sty {
            TyInt(_) | TyUint(_) | TyRawPtr(_) |
            TyBool | TyFloat(_) | TyChar | TyStr |
            TyRef(..) | TyFnPtr(..) | TyFnDef(..) | TyNever => true,
            TyAdt(adt, _) if adt.is_box() => true,
            TySlice(_) | TyAdt(_, _) | TyTuple(..) | TyClosure(..) | TyArray(..) | TyDynamic(..) => false,
            TyParam(_) | TyInfer(_) | TyProjection(_) | TyAnon(..) | TyError => bug!("I got an incomplete/unnormalized type for validation"),
        };
        if is_owning {
            match lvalue {
                Lvalue::Ptr { ptr, extra, aligned: _ } => {
                    // Determine the size
                    // FIXME: Can we reuse size_and_align_of_dst for Lvalues?
                    let len = match self.type_size(ty)? {
                        Some(size) => {
                            assert_eq!(extra, LvalueExtra::None, "Got a fat ptr to a sized type");
                            size
                        }
                        None => {
                            // The only unsized typ we concider "owning" is TyStr.
                            assert_eq!(ty.sty, TyStr, "Found a surprising unsized owning type");
                            // The extra must be the length, in bytes.
                            match extra {
                                LvalueExtra::Length(len) => len,
                                _ => bug!("TyStr must have a length as extra"),
                            }
                        }
                    };
                    // Handle locking
                    if len > 0 {
                        let ptr = ptr.to_ptr()?;
                        let access = match vctx.mutbl { MutMutable => AccessKind::Write, MutImmutable => AccessKind::Read };
                        match vctx.op {
                            ValidationOp::Acquire => self.memory.acquire_lock(ptr, len, vctx.region, access)?,
                            ValidationOp::Release => self.memory.release_write_lock_until(ptr, len, None)?,
                            ValidationOp::Suspend(region) => self.memory.release_write_lock_until(ptr, len, Some(region))?,
                        }
                    }
                }
                Lvalue::Local { .. } | Lvalue::Global(..) => {
                    // These are not backed by memory, so we have nothing to do.
                }
            }
        }

        match ty.sty {
            TyInt(_) | TyUint(_) | TyRawPtr(_) => {
                // TODO: Make sure these are not undef.
                // We could do a bounds-check and other sanity checks on the lvalue, but it would be a bug in miri for this to ever fail.
                Ok(())
            }
            TyBool | TyFloat(_) | TyChar | TyStr => {
                // TODO: Check if these are valid bool/float/codepoint/UTF-8, respectively (and in particular, not undef).
                Ok(())
            }
            TyNever => {
                Err(EvalError::ValidationFailure(format!("The empty type is never valid.")))
            }
            TyRef(region, ty::TypeAndMut { ty: pointee_ty, mutbl }) => {
                let val = self.read_lvalue(lvalue)?;
                // Sharing restricts our context
                if mutbl == MutImmutable {
                    // Actually, in case of releasing-validation, this means we are done.
                    if vctx.op != ValidationOp::Acquire {
                        return Ok(());
                    }
                    vctx.mutbl = MutImmutable;
                }
                // Inner lifetimes *outlive* outer ones, so only if we have no lifetime restriction yet,
                // we record the region of this borrow to the context.
                if vctx.region == None {
                    match *region {
                        ReScope(ce) => vctx.region = Some(ce),
                        // It is possible for us to encode erased lifetimes here because the lifetimes in
                        // this functions' Subst will be erased.
                        _ => {},
                    }
                }
                self.validate_ptr(val, pointee_ty, vctx)
            }
            TyAdt(adt, _) if adt.is_box() => {
                let val = self.read_lvalue(lvalue)?;
                self.validate_ptr(val, ty.boxed_ty(), vctx)
            }
            TyFnPtr(_sig) => {
                let ptr = self.read_lvalue(lvalue)?.into_ptr(&mut self.memory)?.to_ptr()?;
                self.memory.get_fn(ptr)?;
                // TODO: Check if the signature matches (should be the same check as what terminator/mod.rs already does on call?).
                Ok(())
            }
            TyFnDef(..) => {
                // This is a zero-sized type with all relevant data sitting in the type.
                // There is nothing to validate.
                Ok(())
            }

            // Compound types
            TySlice(elem_ty) => {
                let len = match lvalue {
                    Lvalue::Ptr { extra: LvalueExtra::Length(len), .. } => len,
                    _ => bug!("acquire_valid of a TySlice given non-slice lvalue: {:?}", lvalue),
                };
                for i in 0..len {
                    let inner_lvalue = self.lvalue_index(lvalue, ty, i)?;
                    self.validate(inner_lvalue, elem_ty, vctx)?;
                }
                Ok(())
            }
            TyArray(elem_ty, len) => {
                for i in 0..len {
                    let inner_lvalue = self.lvalue_index(lvalue, ty, i as u64)?;
                    self.validate(inner_lvalue, elem_ty, vctx)?;
                }
                Ok(())
            }
            TyDynamic(_data, _region) => {
                // Check that this is a valid vtable
                let vtable = match lvalue {
                    Lvalue::Ptr { extra: LvalueExtra::Vtable(vtable), .. } => vtable,
                    _ => bug!("acquire_valid of a TyDynamic given non-trait-object lvalue: {:?}", lvalue),
                };
                self.read_size_and_align_from_vtable(vtable)?;
                // TODO: Check that the vtable contains all the function pointers we expect it to have.
                // TODO: Is there anything we can/should validate here?  Trait objects cannot have any operations performed
                // on them directly.  We cannot, in general, even acquire any locks as the trait object *could*
                // contain an UnsafeCell.  If we call functions to get access to data, we will validate
                // their return values.  So, it doesn't seem like there's anything to do.
                Ok(())
            }
            TyAdt(adt, subst) => {
                if Some(adt.did) == self.tcx.lang_items.unsafe_cell_type() {
                    // No locks for unsafe cells.  Also no other validation, the only field is private anyway.
                    return Ok(());
                }

                match adt.adt_kind() {
                    AdtKind::Enum => {
                        // TODO: Can we get the discriminant without forcing an allocation?
                        let ptr = self.force_allocation(lvalue)?.to_ptr()?;
                        let discr = self.read_discriminant_value(ptr, ty)?;

                        // Get variant index for discriminant
                        let variant_idx = adt.discriminants(self.tcx)
                            .position(|variant_discr| variant_discr.to_u128_unchecked() == discr)
                            .ok_or(EvalError::InvalidDiscriminant)?;
                        let variant = &adt.variants[variant_idx];

                        if variant.fields.len() > 0 {
                            // Downcast to this variant, if needed
                            let lvalue = if adt.variants.len() > 1 {
                                self.eval_lvalue_projection(lvalue, ty, &mir::ProjectionElem::Downcast(adt, variant_idx))?
                            } else {
                                lvalue
                            };

                            // Recursively validate the fields
                            self.validate_variant(lvalue, ty, variant, subst, vctx)
                        } else {
                            // No fields, nothing left to check.  Downcasting may fail, e.g. in case of a CEnum.
                            Ok(())
                        }
                    }
                    AdtKind::Struct => {
                        self.validate_variant(lvalue, ty, adt.struct_variant(), subst, vctx)
                    }
                    AdtKind::Union => {
                        // No guarantees are provided for union types.
                        // TODO: Make sure that all access to union fields is unsafe; otherwise, we may have some checking to do (but what exactly?)
                        Ok(())
                    }
                }
            }
            TyTuple(ref types, _) => {
                for (idx, field_ty) in types.iter().enumerate() {
                    let field_lvalue = self.lvalue_field(lvalue, idx, ty, field_ty)?;
                    self.validate(field_lvalue, field_ty, vctx)?;
                }
                Ok(())
            }
            TyClosure(def_id, ref closure_substs) => {
                for (idx, field_ty) in closure_substs.upvar_tys(def_id, self.tcx).enumerate() {
                    let field_lvalue = self.lvalue_field(lvalue, idx, ty, field_ty)?;
                    self.validate(field_lvalue, field_ty, vctx)?;
                }
                // TODO: Check if the signature matches (should be the same check as what terminator/mod.rs already does on call?).
                // Is there other things we can/should check?  Like vtable pointers?
                Ok(())
            }
            _ => bug!("We already establishd that this is a type we support.")
        }
    }
}
<|endoftext|>


<commit_before>use super::*;
use std::iter::FromIterator;

pub trait Vertex: Copy + Eq{}
impl<T> Vertex for T
	where T: Copy + Eq
{}

pub trait Weight: Copy + Eq{}
impl<T> Weight for T
	where T: Copy + Eq
{}

pub trait VertexIter<V>: IntoIterator<Item=V> + FromIterator<V>
	where
		V: Vertex,
		Self::IntoIter : ExactSizeIterator<Item=V>

{}
impl<T,V> VertexIter<V> for T
	where
		T: IntoIterator<Item=V> + FromIterator<V>,
		T::IntoIter: ExactSizeIterator<Item=V>,
		V: Vertex,
{}

pub trait EdgeIter<V,W>: IntoIterator<Item=BaseEdge<V,W>> + FromIterator<BaseEdge<V,W>>
	where
		V: Vertex,
		W: Weight,
		Self::IntoIter : ExactSizeIterator<Item=BaseEdge<V,W>>
{}
impl<T,V,W> EdgeIter<V,W> for T
	where
		T: IntoIterator<Item=BaseEdge<V,W>> + FromIterator<BaseEdge<V,W>>,
		T::IntoIter: ExactSizeIterator<Item=BaseEdge<V,W>>,
		V: Vertex,
		W: Weight,
{}

///
/// The basic graph interface.
///
/// This is the main trait for all types graphs.
///
/// The vertices in a graph are identified by their value, and must therefore be unique
/// in the graph.
///
/// The edges in a graph are identified by the vertices they connect and their weight.
/// Edges do not have to be unique, but if there are duplicates (i.e. two or more edges connecting
/// the same vertices with the same weights) then any operation intended for one of the edges
/// may happen on any one of them. E.g. If one of the edges is to be removed, then any
/// one of them will be so.
///
///
///
///
///
pub trait BaseGraph
	where
		<Self::VertexIter as IntoIterator>::IntoIter: ExactSizeIterator,
		<Self::EdgeIter as IntoIterator>::IntoIter: ExactSizeIterator,
{
	/// Type of the vertices in the graph.
	type Vertex: Vertex;
	/// Type of the weights in the graph.
	type Weight: Weight;
	/// Type of the collection returned with vertices.
	type VertexIter: VertexIter<Self::Vertex>;
	// Type of the collection returned with edges.
	type EdgeIter: EdgeIter<Self::Vertex, Self::Weight>;

	///
	/// Creates an empty graph. I.e a graph with no vertices and no edges.
	///
	/// Properties:
	///
	/// - `empty().all_vertices().into_iter().next() == None`
	/// - `empty().all_edges().into_iter().next() == None`
	/// - `empty().add_vertex(v) == Ok(())`
	/// - `empty().add_edge(e) == Err(())`
	/// - `empty().remove_vertex(v) == Err(())`
	/// - `empty().remove_edge(e) == Err(())`
	///
	fn empty_graph() -> Self;

	///
	/// Returns copies of all current vertices in the graph.
	///
	fn all_vertices(&self) -> Self::VertexIter;

	///
	/// Returns copies of all current edges in the graph.
	///
	fn all_edges(&self) -> Self::EdgeIter;

	///
	/// Adds the given vertex to graph as long as no equal vertex is already
	/// present i the graph and the graph is capable of storing it.
	///
	/// ###Returns:
	///
	/// - `Ok` if the vertex is valid and has been added.
	/// - `Err` if the vertex is already present in the graph or
	/// the graph doesn't have capacity for it.
	///
	/// ###`Ok` properties :
	///
	/// - All vertices present before the call are also present after it.
	/// - All edges present before the call are also present after it.
	/// - No edge weights are changed.
	/// - No new edges are introduced.
	/// - Only the given vertex is added to the graph.
	///
	/// ###`Err` properties :
	///
	/// - The graph is unchanged.
	///
	///
	fn add_vertex(&mut self, v: Self::Vertex) -> Result<(),()>;

	///
	/// Removes the given vertex from the graph, assuming it is present.
	///
	/// ###Returns:
	///
	/// - `Ok` if the vertex was removed.
	/// - `Err` if the vertex was not present in the graph.
	///
	/// ###`Ok` properties:
	///
	/// - Only the given vertex is removed from the graph.
	/// - Any edge connecting to the removed vertex is also removed.
	/// - All other edges are unchanged.
	/// - No new vertices are introduced.
	/// - No new edges are introduced.
	/// - No edge weights are changed.
	///
	/// ###`Err` properties:
	///
	/// - The graph is unchanged.
	///
	///
	///
	fn remove_vertex(&mut self, v: Self::Vertex) -> Result<(),()>;

	///
	/// Adds the given edge to the graph assuming it connects to valid vertices.
	///
	/// ###Returns
	/// - `Ok` if the edge connects to valid vertices and the edge was added successfully.
	/// - `Err` if the edge connects to invalid vertices or was not added.
	///
	/// ###`Ok` properties:
	///
	/// - Only the given edge is added to the graph.
	/// - Existing edges are unchanged.
	/// - No vertices are introduced or removed.
	///
	/// ###`Err` properties:
	///
	/// - The graph is unchanged.
	///
	fn add_edge(&mut self, e: BaseEdge<Self::Vertex,Self::Weight>) -> Result<(),()>;

	///
	/// Removes the given edge from the graph, assuming it is already present.
	///
	/// ###Returns
	/// - `Ok` if the edge was present before the call and was removed successfully.
	/// - `Err` if the edge was not found in the graph.
	///
	/// ###`Ok` properties:
	///
	/// - Only the given edge is removed.
	/// - No new edges are introduced.
	/// - No edge weights are changed.
	/// - No new vertices are introduced or removed.
	///
	/// ###`Err` properties:
	///
	/// - The graph is unchanged.
	///
	fn remove_edge(&mut self, e: BaseEdge<Self::Vertex,Self::Weight>) -> Result<(),()>;

	///
	/// Creates a graph containing the given vertices and edges. There can be no
	/// duplicate vertices and all edges must connect to the given vertices.
	///
	/// ###Returns:
	///
	/// - `Ok`: If the given graph description is valid, the created graph is returned.
	/// - `Err`: If the given graph description is invalid.
	///
	fn graph(	vertices: Vec<Self::Vertex>,
			 	edges: Vec<(Self::Vertex, Self::Vertex,Self::Weight)>)
		-> Result<Self,()>
		where
			Self: Sized,
	{
		let mut g = Self::empty_graph();

		/* Add all vertices
		 */
		for v in vertices {
			//Make sure the vertex is added
			g.add_vertex(v)?;
		}

		/* Add all edges
		 */
		for (so,si,w) in edges {
			// Make sure the edge is added
			g.add_edge(BaseEdge::new(so,si,w))?;
		}

		Ok(g)
	}

	///
	/// Returns all edges that are connect to both the given vertices.
	///
	/// I.e. all edges where e == (v1,v2,_) or e == (v2,v1,_)
	///
	fn edges_between(&self, v1: Self::Vertex, v2: Self::Vertex) -> Self::EdgeIter{
		let all_edges = self.all_edges().into_iter();

		// Filter out any edge that is not connected to both vertices
		let relevant = all_edges.filter(|edge|{
			(edge.source == v1 && edge.sink == v2) ||
				(edge.source == v2 && edge.sink == v1)
		});

		// Return the result
		relevant.collect()
	}

}

<commit_msg>Added edge_count() and vertex_count() to BaseGraph.<commit_after>use super::*;
use std::iter::FromIterator;

pub trait Vertex: Copy + Eq{}
impl<T> Vertex for T
	where T: Copy + Eq
{}

pub trait Weight: Copy + Eq{}
impl<T> Weight for T
	where T: Copy + Eq
{}

pub trait VertexIter<V>: IntoIterator<Item=V> + FromIterator<V>
	where
		V: Vertex,
		Self::IntoIter : ExactSizeIterator<Item=V>

{}
impl<T,V> VertexIter<V> for T
	where
		T: IntoIterator<Item=V> + FromIterator<V>,
		T::IntoIter: ExactSizeIterator<Item=V>,
		V: Vertex,
{}

pub trait EdgeIter<V,W>: IntoIterator<Item=BaseEdge<V,W>> + FromIterator<BaseEdge<V,W>>
	where
		V: Vertex,
		W: Weight,
		Self::IntoIter : ExactSizeIterator<Item=BaseEdge<V,W>>
{}
impl<T,V,W> EdgeIter<V,W> for T
	where
		T: IntoIterator<Item=BaseEdge<V,W>> + FromIterator<BaseEdge<V,W>>,
		T::IntoIter: ExactSizeIterator<Item=BaseEdge<V,W>>,
		V: Vertex,
		W: Weight,
{}

///
/// The basic graph interface.
///
/// This is the main trait for all types graphs.
///
/// The vertices in a graph are identified by their value, and must therefore be unique
/// in the graph.
///
/// The edges in a graph are identified by the vertices they connect and their weight.
/// Edges do not have to be unique, but if there are duplicates (i.e. two or more edges connecting
/// the same vertices with the same weights) then any operation intended for one of the edges
/// may happen on any one of them. E.g. If one of the edges is to be removed, then any
/// one of them will be so.
///
///
///
///
///
pub trait BaseGraph
	where
		<Self::VertexIter as IntoIterator>::IntoIter: ExactSizeIterator,
		<Self::EdgeIter as IntoIterator>::IntoIter: ExactSizeIterator,
{
	/// Type of the vertices in the graph.
	type Vertex: Vertex;
	/// Type of the weights in the graph.
	type Weight: Weight;
	/// Type of the collection returned with vertices.
	type VertexIter: VertexIter<Self::Vertex>;
	// Type of the collection returned with edges.
	type EdgeIter: EdgeIter<Self::Vertex, Self::Weight>;

	///
	/// Creates an empty graph. I.e a graph with no vertices and no edges.
	///
	/// Properties:
	///
	/// - `empty().all_vertices().into_iter().next() == None`
	/// - `empty().all_edges().into_iter().next() == None`
	/// - `empty().add_vertex(v) == Ok(())`
	/// - `empty().add_edge(e) == Err(())`
	/// - `empty().remove_vertex(v) == Err(())`
	/// - `empty().remove_edge(e) == Err(())`
	///
	fn empty_graph() -> Self;

	///
	/// Returns copies of all current vertices in the graph.
	///
	fn all_vertices(&self) -> Self::VertexIter;

	///
	/// Returns copies of all current edges in the graph.
	///
	fn all_edges(&self) -> Self::EdgeIter;

	///
	/// Adds the given vertex to graph as long as no equal vertex is already
	/// present i the graph and the graph is capable of storing it.
	///
	/// ###Returns:
	///
	/// - `Ok` if the vertex is valid and has been added.
	/// - `Err` if the vertex is already present in the graph or
	/// the graph doesn't have capacity for it.
	///
	/// ###`Ok` properties :
	///
	/// - All vertices present before the call are also present after it.
	/// - All edges present before the call are also present after it.
	/// - No edge weights are changed.
	/// - No new edges are introduced.
	/// - Only the given vertex is added to the graph.
	///
	/// ###`Err` properties :
	///
	/// - The graph is unchanged.
	///
	///
	fn add_vertex(&mut self, v: Self::Vertex) -> Result<(),()>;

	///
	/// Removes the given vertex from the graph, assuming it is present.
	///
	/// ###Returns:
	///
	/// - `Ok` if the vertex was removed.
	/// - `Err` if the vertex was not present in the graph.
	///
	/// ###`Ok` properties:
	///
	/// - Only the given vertex is removed from the graph.
	/// - Any edge connecting to the removed vertex is also removed.
	/// - All other edges are unchanged.
	/// - No new vertices are introduced.
	/// - No new edges are introduced.
	/// - No edge weights are changed.
	///
	/// ###`Err` properties:
	///
	/// - The graph is unchanged.
	///
	///
	///
	fn remove_vertex(&mut self, v: Self::Vertex) -> Result<(),()>;

	///
	/// Adds the given edge to the graph assuming it connects to valid vertices.
	///
	/// ###Returns
	/// - `Ok` if the edge connects to valid vertices and the edge was added successfully.
	/// - `Err` if the edge connects to invalid vertices or was not added.
	///
	/// ###`Ok` properties:
	///
	/// - Only the given edge is added to the graph.
	/// - Existing edges are unchanged.
	/// - No vertices are introduced or removed.
	///
	/// ###`Err` properties:
	///
	/// - The graph is unchanged.
	///
	fn add_edge(&mut self, e: BaseEdge<Self::Vertex,Self::Weight>) -> Result<(),()>;

	///
	/// Removes the given edge from the graph, assuming it is already present.
	///
	/// ###Returns
	/// - `Ok` if the edge was present before the call and was removed successfully.
	/// - `Err` if the edge was not found in the graph.
	///
	/// ###`Ok` properties:
	///
	/// - Only the given edge is removed.
	/// - No new edges are introduced.
	/// - No edge weights are changed.
	/// - No new vertices are introduced or removed.
	///
	/// ###`Err` properties:
	///
	/// - The graph is unchanged.
	///
	fn remove_edge(&mut self, e: BaseEdge<Self::Vertex,Self::Weight>) -> Result<(),()>;

	///
	/// Returns the number of vertices in the graph.
	///
	fn vertex_count(&self) -> usize {
		self.all_vertices().into_iter().len()
	}

	///
	/// Returns the number of edges in the graph.
	///
	fn edge_count(&self) -> usize {
		self.all_edges().into_iter().len()
	}

	///
	/// Creates a graph containing the given vertices and edges. There can be no
	/// duplicate vertices and all edges must connect to the given vertices.
	///
	/// ###Returns:
	///
	/// - `Ok`: If the given graph description is valid, the created graph is returned.
	/// - `Err`: If the given graph description is invalid.
	///
	fn graph(	vertices: Vec<Self::Vertex>,
			 	edges: Vec<(Self::Vertex, Self::Vertex,Self::Weight)>)
		-> Result<Self,()>
		where
			Self: Sized,
	{
		let mut g = Self::empty_graph();

		/* Add all vertices
		 */
		for v in vertices {
			//Make sure the vertex is added
			g.add_vertex(v)?;
		}

		/* Add all edges
		 */
		for (so,si,w) in edges {
			// Make sure the edge is added
			g.add_edge(BaseEdge::new(so,si,w))?;
		}

		Ok(g)
	}

	///
	/// Returns all edges that are connect to both the given vertices.
	///
	/// I.e. all edges where e == (v1,v2,_) or e == (v2,v1,_)
	///
	fn edges_between(&self, v1: Self::Vertex, v2: Self::Vertex) -> Self::EdgeIter{
		let all_edges = self.all_edges().into_iter();

		// Filter out any edge that is not connected to both vertices
		let relevant = all_edges.filter(|edge|{
			(edge.source == v1 && edge.sink == v2) ||
				(edge.source == v2 && edge.sink == v1)
		});

		// Return the result
		relevant.collect()
	}

}

<|endoftext|>


<commit_before>use super::error::Result;
use super::util;
use ansi_term::Colour;
use difference::{Changeset, Difference};
use regex::bytes::{Regex as ByteRegex, RegexBuilder as ByteRegexBuilder};
use regex::Regex;
use std::char;
use std::fs;
use std::io::{self, Write};
use std::path::Path;
use std::str;
use tree_sitter::{Language, LogType, Parser};

lazy_static! {
    static ref HEADER_REGEX: ByteRegex = ByteRegexBuilder::new(r"^===+\r?\n([^=]*)\r?\n===+\r?\n")
        .multi_line(true)
        .build()
        .unwrap();
    static ref DIVIDER_REGEX: ByteRegex = ByteRegexBuilder::new(r"\r?\n---+\r?\n")
        .multi_line(true)
        .build()
        .unwrap();
    static ref WHITESPACE_REGEX: Regex = Regex::new(r"\s+").unwrap();
}

#[derive(Debug, PartialEq, Eq)]
pub enum TestEntry {
    Group {
        name: String,
        children: Vec<TestEntry>,
    },
    Example {
        name: String,
        input: Vec<u8>,
        output: String,
    },
}

pub fn run_tests_at_path(
    language: Language,
    path: &Path,
    debug: bool,
    debug_graph: bool,
    filter: Option<&str>,
) -> Result<()> {
    let test_entry = parse_tests(path)?;
    let mut log_session = None;
    let mut parser = Parser::new();
    parser.set_language(language)?;

    if debug_graph {
        log_session = Some(util::log_graphs(&mut parser, "log.html")?);
    } else if debug {
        parser.set_logger(Some(Box::new(|log_type, message| {
            if log_type == LogType::Lex {
                io::stderr().write(b"  ").unwrap();
            }
            write!(&mut io::stderr(), "{}\n", message).unwrap();
        })));
    }

    let mut failures = Vec::new();
    if let TestEntry::Group { children, .. } = test_entry {
        for child in children {
            run_tests(&mut parser, child, filter, 0, &mut failures)?;
        }
    }

    if failures.len() > 0 {
        println!("");

        if failures.len() == 1 {
            println!("1 failure:")
        } else {
            println!("{} failures:", failures.len())
        }

        print_diff_key();
        for (i, (name, actual, expected)) in failures.iter().enumerate() {
            println!("\n  {}. {}:", i + 1, name);
            print_diff(actual, expected);
        }
    }

    drop(log_session);
    Ok(())
}

pub fn print_diff_key() {
    println!(
        "\n{} / {}",
        Colour::Green.paint("expected"),
        Colour::Red.paint("actual")
    );
}

pub fn print_diff(actual: &String, expected: &String) {
    let changeset = Changeset::new(actual, expected, " ");
    print!("    ");
    for diff in &changeset.diffs {
        match diff {
            Difference::Same(part) => {
                print!("{}{}", part, changeset.split);
            }
            Difference::Add(part) => {
                print!("{}{}", Colour::Green.paint(part), changeset.split);
            }
            Difference::Rem(part) => {
                print!("{}{}", Colour::Red.paint(part), changeset.split);
            }
        }
    }
    println!("");
}

fn run_tests(
    parser: &mut Parser,
    test_entry: TestEntry,
    filter: Option<&str>,
    mut indent_level: i32,
    failures: &mut Vec<(String, String, String)>,
) -> Result<()> {
    match test_entry {
        TestEntry::Example {
            name,
            input,
            output,
        } => {
            if let Some(filter) = filter {
                if !name.contains(filter) {
                    return Ok(());
                }
            }
            let tree = parser
                .parse_utf8(&mut |byte_offset, _| &input[byte_offset..], None)
                .unwrap();
            let actual = tree.root_node().to_sexp();
            for _ in 0..indent_level {
                print!("  ");
            }
            if actual == output {
                println!("✓ {}", Colour::Green.paint(&name));
            } else {
                println!("✗ {}", Colour::Red.paint(&name));
                failures.push((name, actual, output));
            }
        }
        TestEntry::Group { name, children } => {
            for _ in 0..indent_level {
                print!("  ");
            }
            println!("{}:", name);
            indent_level += 1;
            for child in children {
                run_tests(parser, child, filter, indent_level, failures)?;
            }
        }
    }
    Ok(())
}

pub fn parse_tests(path: &Path) -> io::Result<TestEntry> {
    let name = path
        .file_name()
        .and_then(|s| s.to_str())
        .unwrap_or("")
        .to_string();
    if path.is_dir() {
        let mut children = Vec::new();
        for entry in fs::read_dir(path)? {
            let entry = entry?;
            children.push(parse_tests(&entry.path())?);
        }
        Ok(TestEntry::Group { name, children })
    } else {
        let content = fs::read_to_string(path)?;
        Ok(parse_test_content(name, content))
    }
}

fn parse_test_content(name: String, content: String) -> TestEntry {
    let mut children = Vec::new();
    let bytes = content.as_bytes();
    let mut previous_name = String::new();
    let mut previous_header_end = 0;
    for header_match in HEADER_REGEX
        .find_iter(&bytes)
        .map(|m| (m.start(), m.end()))
        .chain(Some((bytes.len(), bytes.len())))
    {
        let (header_start, header_end) = header_match;
        if previous_header_end > 0 {
            if let Some(divider_match) =
                DIVIDER_REGEX.find(&bytes[previous_header_end..header_start])
            {
                let (divider_start, divider_end) = (
                    previous_header_end + divider_match.start(),
                    previous_header_end + divider_match.end(),
                );
                if let Ok(output) = str::from_utf8(&bytes[divider_end..header_start]) {
                    let input = bytes[previous_header_end..divider_start].to_vec();
                    let output = WHITESPACE_REGEX.replace_all(output.trim(), " ").to_string();
                    children.push(TestEntry::Example {
                        name: previous_name,
                        input,
                        output,
                    });
                }
            }
        }
        previous_name = String::from_utf8_lossy(&bytes[header_start..header_end])
            .trim_matches(|c| char::is_whitespace(c) || c == '=')
            .to_string();
        previous_header_end = header_end;
    }
    TestEntry::Group { name, children }
}

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

    #[test]
    fn test_parse_test_content() {
        let entry = parse_test_content(
            "the-filename".to_string(),
            r#"
===============
The first test
===============

a b c

---

(a
    (b c))

================
The second test
================
d
---
(d)
        "#
            .trim()
            .to_string(),
        );

        assert_eq!(
            entry,
            TestEntry::Group {
                name: "the-filename".to_string(),
                children: vec![
                    TestEntry::Example {
                        name: "The first test".to_string(),
                        input: "\na b c\n".as_bytes().to_vec(),
                        output: "(a (b c))".to_string(),
                    },
                    TestEntry::Example {
                        name: "The second test".to_string(),
                        input: "d".as_bytes().to_vec(),
                        output: "(d)".to_string(),
                    },
                ]
            }
        );
    }
}
<commit_msg>Fix test subcommand bugs<commit_after>use super::error::Result;
use super::util;
use ansi_term::Colour;
use difference::{Changeset, Difference};
use regex::bytes::{Regex as ByteRegex, RegexBuilder as ByteRegexBuilder};
use regex::Regex;
use std::char;
use std::fs;
use std::io::{self, Write};
use std::path::Path;
use std::str;
use tree_sitter::{Language, LogType, Parser};

lazy_static! {
    static ref HEADER_REGEX: ByteRegex = ByteRegexBuilder::new(r"^===+\r?\n([^=]*)\r?\n===+\r?\n")
        .multi_line(true)
        .build()
        .unwrap();
    static ref DIVIDER_REGEX: ByteRegex = ByteRegexBuilder::new(r"\r?\n---+\r?\n")
        .multi_line(true)
        .build()
        .unwrap();
    static ref WHITESPACE_REGEX: Regex = Regex::new(r"\s+").unwrap();
}

#[derive(Debug, PartialEq, Eq)]
pub enum TestEntry {
    Group {
        name: String,
        children: Vec<TestEntry>,
    },
    Example {
        name: String,
        input: Vec<u8>,
        output: String,
    },
}

pub fn run_tests_at_path(
    language: Language,
    path: &Path,
    debug: bool,
    debug_graph: bool,
    filter: Option<&str>,
) -> Result<()> {
    let test_entry = parse_tests(path)?;
    let mut _log_session = None;
    let mut parser = Parser::new();
    parser.set_language(language)?;

    if debug_graph {
        _log_session = Some(util::log_graphs(&mut parser, "log.html")?);
    } else if debug {
        parser.set_logger(Some(Box::new(|log_type, message| {
            if log_type == LogType::Lex {
                io::stderr().write(b"  ").unwrap();
            }
            write!(&mut io::stderr(), "{}\n", message).unwrap();
        })));
    }

    let mut failures = Vec::new();
    if let TestEntry::Group { children, .. } = test_entry {
        for child in children {
            run_tests(&mut parser, child, filter, 0, &mut failures)?;
        }
    }

    if failures.len() > 0 {
        println!("");

        if failures.len() == 1 {
            println!("1 failure:")
        } else {
            println!("{} failures:", failures.len())
        }

        print_diff_key();
        for (i, (name, actual, expected)) in failures.iter().enumerate() {
            println!("\n  {}. {}:", i + 1, name);
            print_diff(actual, expected);
        }
    }

    Ok(())
}

pub fn print_diff_key() {
    println!(
        "\n{} / {}",
        Colour::Green.paint("expected"),
        Colour::Red.paint("actual")
    );
}

pub fn print_diff(actual: &String, expected: &String) {
    let changeset = Changeset::new(actual, expected, " ");
    print!("    ");
    for diff in &changeset.diffs {
        match diff {
            Difference::Same(part) => {
                print!("{}{}", part, changeset.split);
            }
            Difference::Add(part) => {
                print!("{}{}", Colour::Green.paint(part), changeset.split);
            }
            Difference::Rem(part) => {
                print!("{}{}", Colour::Red.paint(part), changeset.split);
            }
        }
    }
    println!("");
}

fn run_tests(
    parser: &mut Parser,
    test_entry: TestEntry,
    filter: Option<&str>,
    mut indent_level: i32,
    failures: &mut Vec<(String, String, String)>,
) -> Result<()> {
    match test_entry {
        TestEntry::Example {
            name,
            input,
            output,
        } => {
            if let Some(filter) = filter {
                if !name.contains(filter) {
                    return Ok(());
                }
            }
            let tree = parser
                .parse_utf8(&mut |byte_offset, _| &input[byte_offset..], None)
                .unwrap();
            let actual = tree.root_node().to_sexp();
            for _ in 0..indent_level {
                print!("  ");
            }
            if actual == output {
                println!("✓ {}", Colour::Green.paint(&name));
            } else {
                println!("✗ {}", Colour::Red.paint(&name));
                failures.push((name, actual, output));
            }
        }
        TestEntry::Group { name, children } => {
            for _ in 0..indent_level {
                print!("  ");
            }
            println!("{}:", name);
            indent_level += 1;
            for child in children {
                run_tests(parser, child, filter, indent_level, failures)?;
            }
        }
    }
    Ok(())
}

pub fn parse_tests(path: &Path) -> io::Result<TestEntry> {
    let name = path
        .file_name()
        .and_then(|s| s.to_str())
        .unwrap_or("")
        .to_string();
    if path.is_dir() {
        let mut children = Vec::new();
        for entry in fs::read_dir(path)? {
            let entry = entry?;
            children.push(parse_tests(&entry.path())?);
        }
        Ok(TestEntry::Group { name, children })
    } else {
        let content = fs::read_to_string(path)?;
        Ok(parse_test_content(name, content))
    }
}

fn parse_test_content(name: String, content: String) -> TestEntry {
    let mut children = Vec::new();
    let bytes = content.as_bytes();
    let mut previous_name = String::new();
    let mut previous_header_end = 0;
    for header_match in HEADER_REGEX
        .find_iter(&bytes)
        .map(|m| (m.start(), m.end()))
        .chain(Some((bytes.len(), bytes.len())))
    {
        let (header_start, header_end) = header_match;
        if previous_header_end > 0 {
            if let Some(divider_match) =
                DIVIDER_REGEX.find(&bytes[previous_header_end..header_start])
            {
                let (divider_start, divider_end) = (
                    previous_header_end + divider_match.start(),
                    previous_header_end + divider_match.end(),
                );
                if let Ok(output) = str::from_utf8(&bytes[divider_end..header_start]) {
                    let input = bytes[previous_header_end..divider_start].to_vec();
                    let output = WHITESPACE_REGEX.replace_all(output.trim(), " ").to_string();
                    let output = output.replace(" )", ")");
                    children.push(TestEntry::Example {
                        name: previous_name,
                        input,
                        output,
                    });
                }
            }
        }
        previous_name = String::from_utf8_lossy(&bytes[header_start..header_end])
            .trim_matches(|c| char::is_whitespace(c) || c == '=')
            .to_string();
        previous_header_end = header_end;
    }
    TestEntry::Group { name, children }
}

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

    #[test]
    fn test_parse_test_content() {
        let entry = parse_test_content(
            "the-filename".to_string(),
            r#"
===============
The first test
===============

a b c

---

(a
    (b c))

================
The second test
================
d
---
(d)
        "#
            .trim()
            .to_string(),
        );

        assert_eq!(
            entry,
            TestEntry::Group {
                name: "the-filename".to_string(),
                children: vec![
                    TestEntry::Example {
                        name: "The first test".to_string(),
                        input: "\na b c\n".as_bytes().to_vec(),
                        output: "(a (b c))".to_string(),
                    },
                    TestEntry::Example {
                        name: "The second test".to_string(),
                        input: "d".as_bytes().to_vec(),
                        output: "(d)".to_string(),
                    },
                ]
            }
        );
    }
}
<|endoftext|>


<commit_before>/* AES ECB/CBC mode oracle
 *
 * Dmitry Vasiliev <dima@hlabs.org>
 */

extern crate serialize;

extern crate aes_lib;

use std::rand::random;
use std::fmt;
use std::collections::HashMap;
use serialize::base64::FromBase64;

use aes_lib::{AES_BLOCK_SIZE, encrypt_aes_ecb};

type Dict = HashMap<Vec<u8>, u8>;

#[deriving(PartialEq, Eq)]
enum Mode {
    ECB,
    CBC
}

impl fmt::Show for Mode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ECB => write!(f, "ECB"),
            CBC => write!(f, "CBC"),
        }
    }
}

struct Decryptor {
    unknown: Vec<u8>,
    key: Vec<u8>,
}

impl Decryptor {
    fn new() -> Decryptor {
        let unknown = unknown_string();
        let key = random_bytes(AES_BLOCK_SIZE);
        Decryptor{unknown: unknown, key: key}
    }

    #[inline]
    fn encrypt(&self, string: &[u8]) -> Vec<u8> {
        let data = string.to_vec() + self.unknown;
        encrypt_aes_ecb(data.as_slice(), self.key.as_slice())
    }

    fn guess_block_size(&self) -> Option<uint> {
        let mut prev = self.encrypt(['A' as u8].as_slice());
        for len in range(1, 256) {
            let s = Vec::from_elem(len + 1, 'A' as u8);
            let enc = self.encrypt(s.as_slice());
            if prev.slice_to(len) == enc.slice_to(len) {
                return Some(len);
            }
            prev = enc;
        }
        None
    }

    fn guess_aes_mode(&self, block_size: uint) -> Mode {
        let s = Vec::from_elem(block_size * 2, 'A' as u8);
        let enc = self.encrypt(s.as_slice());
        if enc.slice_to(block_size) == enc.slice(block_size, block_size * 2) {
            ECB
        } else {
            CBC
        }
    }

    fn make_dict(&self, block_size: uint) -> Dict {
        let mut dict = HashMap::with_capacity(256);
        let mut input = Vec::from_elem(block_size, 'A' as u8);
        for c in range(0, 255) {
            *input.last_mut().unwrap() = c;
            let enc = self.encrypt(input.as_slice());
            dict.insert(enc.slice_to(block_size).to_vec(), c);
        }
        dict
    }

    fn decrypt(&self, block_size: uint) -> Vec<u8> {
        let dict = self.make_dict(block_size);
        let mut input = Vec::from_elem(block_size, 'A' as u8);
        self.unknown.iter().map(|&c| {
            *input.last_mut().unwrap() = c;
            let enc = self.encrypt(input.as_slice());
            dict[enc.slice_to(block_size).to_vec()]
            }).collect()
    }
}

fn random_bytes(len: uint) -> Vec<u8> {
    Vec::from_fn(len, |_| random::<u8>())
}

fn unknown_string() -> Vec<u8> {
    let data = "Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWctdG9wIGRvd24gc28gbXkg
aGFpciBjYW4gYmxvdwpUaGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBq
dXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5vLCBJIGp1c3QgZHJvdmUg
YnkK";
    data.from_base64().unwrap()
}

fn main() {
    let decryptor = Decryptor::new();
    let block_size = decryptor.guess_block_size().unwrap();
    println!("Block size: {}", block_size);
    let mode = decryptor.guess_aes_mode(block_size);
    println!("AES mode: {}", mode);
    let dec = decryptor.decrypt(block_size);
    println!("Text: {}", String::from_utf8(dec).unwrap());
}
<commit_msg>Fix module comment<commit_after>/* Byte at a time AES ECB decryption (Simple)
 *
 * Dmitry Vasiliev <dima@hlabs.org>
 */

extern crate serialize;

extern crate aes_lib;

use std::rand::random;
use std::fmt;
use std::collections::HashMap;
use serialize::base64::FromBase64;

use aes_lib::{AES_BLOCK_SIZE, encrypt_aes_ecb};

type Dict = HashMap<Vec<u8>, u8>;

#[deriving(PartialEq, Eq)]
enum Mode {
    ECB,
    CBC
}

impl fmt::Show for Mode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ECB => write!(f, "ECB"),
            CBC => write!(f, "CBC"),
        }
    }
}

struct Decryptor {
    unknown: Vec<u8>,
    key: Vec<u8>,
}

impl Decryptor {
    fn new() -> Decryptor {
        let unknown = unknown_string();
        let key = random_bytes(AES_BLOCK_SIZE);
        Decryptor{unknown: unknown, key: key}
    }

    #[inline]
    fn encrypt(&self, string: &[u8]) -> Vec<u8> {
        let data = string.to_vec() + self.unknown;
        encrypt_aes_ecb(data.as_slice(), self.key.as_slice())
    }

    fn guess_block_size(&self) -> Option<uint> {
        let mut prev = self.encrypt(['A' as u8].as_slice());
        for len in range(1, 256) {
            let s = Vec::from_elem(len + 1, 'A' as u8);
            let enc = self.encrypt(s.as_slice());
            if prev.slice_to(len) == enc.slice_to(len) {
                return Some(len);
            }
            prev = enc;
        }
        None
    }

    fn guess_aes_mode(&self, block_size: uint) -> Mode {
        let s = Vec::from_elem(block_size * 2, 'A' as u8);
        let enc = self.encrypt(s.as_slice());
        if enc.slice_to(block_size) == enc.slice(block_size, block_size * 2) {
            ECB
        } else {
            CBC
        }
    }

    fn make_dict(&self, block_size: uint) -> Dict {
        let mut dict = HashMap::with_capacity(256);
        let mut input = Vec::from_elem(block_size, 'A' as u8);
        for c in range(0, 255) {
            *input.last_mut().unwrap() = c;
            let enc = self.encrypt(input.as_slice());
            dict.insert(enc.slice_to(block_size).to_vec(), c);
        }
        dict
    }

    fn decrypt(&self, block_size: uint) -> Vec<u8> {
        let dict = self.make_dict(block_size);
        let mut input = Vec::from_elem(block_size, 'A' as u8);
        self.unknown.iter().map(|&c| {
            *input.last_mut().unwrap() = c;
            let enc = self.encrypt(input.as_slice());
            dict[enc.slice_to(block_size).to_vec()]
            }).collect()
    }
}

fn random_bytes(len: uint) -> Vec<u8> {
    Vec::from_fn(len, |_| random::<u8>())
}

fn unknown_string() -> Vec<u8> {
    let data = "Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWctdG9wIGRvd24gc28gbXkg
aGFpciBjYW4gYmxvdwpUaGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBq
dXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5vLCBJIGp1c3QgZHJvdmUg
YnkK";
    data.from_base64().unwrap()
}

fn main() {
    let decryptor = Decryptor::new();
    let block_size = decryptor.guess_block_size().unwrap();
    println!("Block size: {}", block_size);
    let mode = decryptor.guess_aes_mode(block_size);
    println!("AES mode: {}", mode);
    let dec = decryptor.decrypt(block_size);
    println!("Text: {}", String::from_utf8(dec).unwrap());
}
<|endoftext|>