<commit_before>//! Determining which types for which we can emit `#[derive(Debug)]`.
use super::MonotoneFramework;
use ir::context::{BindgenContext, ItemId};
use ir::item::ItemSet;
use std::collections::HashSet;
use std::collections::HashMap;
use ir::traversal::EdgeKind;
use ir::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
use ir::ty::TypeKind;
use ir::comp::Field;
use ir::traversal::Trace;
use ir::comp::FieldMethods;
use ir::layout::Layout;
use ir::derive::CanTriviallyDeriveDebug;
use ir::comp::CompKind;

/// An analysis that finds for each IR item whether debug cannot be derived.
///
/// We use the monotone constraint function `cannot_derive_debug`, defined as
/// follows:
///
/// * If T is Opaque and layout of the type is known, get this layout as opaque
///   type and check whether it can be derived using trivial checks.
/// * If T is Array type, debug cannot be derived if the length of the array is
///   larger than the limit or the type of data the array contains cannot derive
///   debug.
/// * If T is a type alias, a templated alias or an indirection to another type,
///   debug cannot be derived if the type T refers to cannot be derived debug.
/// * If T is a compound type, debug cannot be derived if any of its base member
///   or field cannot be derived debug.
/// * If T is a pointer, T cannot be derived debug if T is a function pointer
///   and the function signature cannot be derived debug.
/// * If T is an instantiation of an abstract template definition, T cannot be
///   derived debug if any of the template arguments or template definition
///   cannot derive debug.
#[derive(Debug, Clone)]
pub struct CannotDeriveDebug<'ctx, 'gen>
    where 'gen: 'ctx
{
    ctx: &'ctx BindgenContext<'gen>,

    // The incremental result of this analysis's computation. Everything in this
    // set cannot derive debug.
    cannot_derive_debug: HashSet<ItemId>,

    // Dependencies saying that if a key ItemId has been inserted into the
    // `cannot_derive_debug` set, then each of the ids in Vec<ItemId> need to be
    // considered again.
    //
    // This is a subset of the natural IR graph with reversed edges, where we
    // only include the edges from the IR graph that can affect whether a type
    // can derive debug or not.
    dependencies: HashMap<ItemId, Vec<ItemId>>,
}

impl<'ctx, 'gen> CannotDeriveDebug<'ctx, 'gen> {
    fn consider_edge(kind: EdgeKind) -> bool {
        match kind {
            // These are the only edges that can affect whether a type can derive
            // debug or not.
            EdgeKind::BaseMember |
            EdgeKind::Field |
            EdgeKind::TypeReference |
            EdgeKind::VarType |
            EdgeKind::TemplateArgument |
            EdgeKind::TemplateDeclaration |
            EdgeKind::TemplateParameterDefinition => true,

            EdgeKind::Constructor |
            EdgeKind::Destructor |
            EdgeKind::FunctionReturn |
            EdgeKind::FunctionParameter |
            EdgeKind::InnerType |
            EdgeKind::InnerVar |
            EdgeKind::Method => false,
            EdgeKind::Generic => false,
        }
    }

    fn insert(&mut self, id: ItemId) -> bool {
        let was_not_already_in_set = self.cannot_derive_debug.insert(id);
        assert!(
            was_not_already_in_set,
            "We shouldn't try and insert {:?} twice because if it was \
             already in the set, `constrain` should have exited early.",
            id
        );
        true
    }
}

impl<'ctx, 'gen> MonotoneFramework for CannotDeriveDebug<'ctx, 'gen> {
    type Node = ItemId;
    type Extra = &'ctx BindgenContext<'gen>;
    type Output = HashSet<ItemId>;

    fn new(ctx: &'ctx BindgenContext<'gen>) -> CannotDeriveDebug<'ctx, 'gen> {
        let cannot_derive_debug = HashSet::new();
        let mut dependencies = HashMap::new();
        let whitelisted_items: HashSet<_> = ctx.whitelisted_items().iter().cloned().collect();

        let whitelisted_and_blacklisted_items: ItemSet = whitelisted_items.iter()
            .cloned()
            .flat_map(|i| {
                let mut reachable = vec![i];
                i.trace(ctx, &mut |s, _| {
                    reachable.push(s);
                }, &());
                reachable
            })
            .collect();

        for item in whitelisted_and_blacklisted_items {
            dependencies.entry(item).or_insert(vec![]);

            {
                // We reverse our natural IR graph edges to find dependencies
                // between nodes.
                item.trace(ctx, &mut |sub_item: ItemId, edge_kind| {
                    if Self::consider_edge(edge_kind) {
                        dependencies.entry(sub_item)
                            .or_insert(vec![])
                            .push(item);
                    }
                }, &());
            }
        }

        CannotDeriveDebug {
            ctx: ctx,
            cannot_derive_debug: cannot_derive_debug,
            dependencies: dependencies,
        }
    }

    fn initial_worklist(&self) -> Vec<ItemId> {
        self.ctx.whitelisted_items().iter().cloned().collect()
    }

    fn constrain(&mut self, id: ItemId) -> bool {
        if self.cannot_derive_debug.contains(&id) {
            return false;
        }

        let item = self.ctx.resolve_item(id);
        let ty = match item.as_type() {
            None => return false,
            Some(ty) => ty
        };

        match *ty.kind() {
            // handle the simple case
            // These can derive debug without further information
            TypeKind::Void |
            TypeKind::NullPtr |
            TypeKind::Int(..) |
            TypeKind::Float(..) |
            TypeKind::Complex(..) |
            TypeKind::Function(..) |
            TypeKind::Enum(..) |
            TypeKind::Reference(..) |
            TypeKind::BlockPointer |
            TypeKind::Named |
            TypeKind::UnresolvedTypeRef(..) |
            TypeKind::ObjCInterface(..) |
            TypeKind::ObjCId |
            TypeKind::ObjCSel => {
                return false;
            },
            TypeKind::Opaque => {
                if ty.layout(self.ctx)
                    .map_or(true, |l| l.opaque().can_trivially_derive_debug(self.ctx, ())) {
                        return false;
                    } else {
                        return self.insert(id);
                    }
            },
            TypeKind::Array(t, len) => {
                if len <= RUST_DERIVE_IN_ARRAY_LIMIT {
                    if self.cannot_derive_debug.contains(&t) {
                        return self.insert(id);
                    }
                    return false;
                } else {
                    return self.insert(id);
                }
            },
            TypeKind::ResolvedTypeRef(t) |
            TypeKind::TemplateAlias(t, _) |
            TypeKind::Alias(t) => {
                if self.cannot_derive_debug.contains(&t) {
                    return self.insert(id);
                }
                return false;
            },
            TypeKind::Comp(ref info) => {
                if info.has_non_type_template_params() {
                    if ty.layout(self.ctx).map_or(true,
                                                  |l| l.opaque().can_trivially_derive_debug(self.ctx, ())) {
                        return false;
                    } else {
                        return self.insert(id);
                    }
                }
                if info.kind() == CompKind::Union {
                    if self.ctx.options().unstable_rust {
                        return self.insert(id);
                    }

                    if ty.layout(self.ctx).map_or(true,
                                                  |l| l.opaque().can_trivially_derive_debug(self.ctx, ())) {
                        return false;
                    } else {
                        return self.insert(id);
                    }
                }
                let bases_cannot_derive = info.base_members()
                    .iter()
                    .any(|base| self.cannot_derive_debug.contains(&base.ty));
                if bases_cannot_derive {
                    return self.insert(id);
                }
                let fields_cannot_derive = info.fields()
                    .iter()
                    .any(|f| {
                        match f {
                            &Field::DataMember(ref data) => self.cannot_derive_debug.contains(&data.ty()),
                            &Field::Bitfields(ref bfu) => bfu.bitfields()
                                .iter().any(|b| {
                                    self.cannot_derive_debug.contains(&b.ty())
                                })
                        }
                    });
                if fields_cannot_derive {
                    return self.insert(id);
                }
                false
            },
            TypeKind::Pointer(inner) => {
                let inner_type = self.ctx.resolve_type(inner);
                if let TypeKind::Function(ref sig) =
                    *inner_type.canonical_type(self.ctx).kind() {
                        if sig.can_trivially_derive_debug(&self.ctx, ()) {
                            return false;
                        } else {
                            return self.insert(id);
                        }
                    }
                false
            },
            TypeKind::TemplateInstantiation(ref template) => {
                let args_cannot_derive = template.template_arguments()
                    .iter()
                    .any(|arg| self.cannot_derive_debug.contains(&arg));
                if args_cannot_derive {
                    return self.insert(id);
                }
                let ty_cannot_derive = template.template_definition()
                    .into_resolver()
                    .through_type_refs()
                    .through_type_aliases()
                    .resolve(self.ctx)
                    .as_type()
                    .expect("Instantiations of a non-type?")
                    .as_comp()
                    .and_then(|c| {
                        // For non-type template parameters, we generate an opaque
                        // blob, and in this case the instantiation has a better
                        // idea of the layout than the definition does.
                        if c.has_non_type_template_params() {
                            let opaque = ty.layout(self.ctx)
                                .or_else(|| self.ctx.resolve_type(template.template_definition()).layout(self.ctx))
                                .unwrap_or(Layout::zero())
                                .opaque();
                            Some(!opaque.can_trivially_derive_debug(&self.ctx, ()))
                        } else {
                            None
                        }
                    })
                    .unwrap_or_else(|| self.cannot_derive_debug.contains(&template.template_definition()));
                if ty_cannot_derive {
                    return self.insert(id);
                }
                false
            },
        }
    }

    fn each_depending_on<F>(&self, id: ItemId, mut f: F)
        where F: FnMut(ItemId),
    {
        if let Some(edges) = self.dependencies.get(&id) {
            for item in edges {
                trace!("enqueue {:?} into worklist", item);
                f(*item);
            }
        }
    }
}

impl<'ctx, 'gen> From<CannotDeriveDebug<'ctx, 'gen>> for HashSet<ItemId> {
    fn from(analysis: CannotDeriveDebug<'ctx, 'gen>) -> Self {
        analysis.cannot_derive_debug
    }
}
<commit_msg>Use object literal short hand for `CannotDeriveDebug`<commit_after>//! Determining which types for which we can emit `#[derive(Debug)]`.
use super::MonotoneFramework;
use ir::context::{BindgenContext, ItemId};
use ir::item::ItemSet;
use std::collections::HashSet;
use std::collections::HashMap;
use ir::traversal::EdgeKind;
use ir::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
use ir::ty::TypeKind;
use ir::comp::Field;
use ir::traversal::Trace;
use ir::comp::FieldMethods;
use ir::layout::Layout;
use ir::derive::CanTriviallyDeriveDebug;
use ir::comp::CompKind;

/// An analysis that finds for each IR item whether debug cannot be derived.
///
/// We use the monotone constraint function `cannot_derive_debug`, defined as
/// follows:
///
/// * If T is Opaque and layout of the type is known, get this layout as opaque
///   type and check whether it can be derived using trivial checks.
/// * If T is Array type, debug cannot be derived if the length of the array is
///   larger than the limit or the type of data the array contains cannot derive
///   debug.
/// * If T is a type alias, a templated alias or an indirection to another type,
///   debug cannot be derived if the type T refers to cannot be derived debug.
/// * If T is a compound type, debug cannot be derived if any of its base member
///   or field cannot be derived debug.
/// * If T is a pointer, T cannot be derived debug if T is a function pointer
///   and the function signature cannot be derived debug.
/// * If T is an instantiation of an abstract template definition, T cannot be
///   derived debug if any of the template arguments or template definition
///   cannot derive debug.
#[derive(Debug, Clone)]
pub struct CannotDeriveDebug<'ctx, 'gen>
    where 'gen: 'ctx
{
    ctx: &'ctx BindgenContext<'gen>,

    // The incremental result of this analysis's computation. Everything in this
    // set cannot derive debug.
    cannot_derive_debug: HashSet<ItemId>,

    // Dependencies saying that if a key ItemId has been inserted into the
    // `cannot_derive_debug` set, then each of the ids in Vec<ItemId> need to be
    // considered again.
    //
    // This is a subset of the natural IR graph with reversed edges, where we
    // only include the edges from the IR graph that can affect whether a type
    // can derive debug or not.
    dependencies: HashMap<ItemId, Vec<ItemId>>,
}

impl<'ctx, 'gen> CannotDeriveDebug<'ctx, 'gen> {
    fn consider_edge(kind: EdgeKind) -> bool {
        match kind {
            // These are the only edges that can affect whether a type can derive
            // debug or not.
            EdgeKind::BaseMember |
            EdgeKind::Field |
            EdgeKind::TypeReference |
            EdgeKind::VarType |
            EdgeKind::TemplateArgument |
            EdgeKind::TemplateDeclaration |
            EdgeKind::TemplateParameterDefinition => true,

            EdgeKind::Constructor |
            EdgeKind::Destructor |
            EdgeKind::FunctionReturn |
            EdgeKind::FunctionParameter |
            EdgeKind::InnerType |
            EdgeKind::InnerVar |
            EdgeKind::Method => false,
            EdgeKind::Generic => false,
        }
    }

    fn insert(&mut self, id: ItemId) -> bool {
        let was_not_already_in_set = self.cannot_derive_debug.insert(id);
        assert!(
            was_not_already_in_set,
            "We shouldn't try and insert {:?} twice because if it was \
             already in the set, `constrain` should have exited early.",
            id
        );
        true
    }
}

impl<'ctx, 'gen> MonotoneFramework for CannotDeriveDebug<'ctx, 'gen> {
    type Node = ItemId;
    type Extra = &'ctx BindgenContext<'gen>;
    type Output = HashSet<ItemId>;

    fn new(ctx: &'ctx BindgenContext<'gen>) -> CannotDeriveDebug<'ctx, 'gen> {
        let cannot_derive_debug = HashSet::new();
        let mut dependencies = HashMap::new();
        let whitelisted_items: HashSet<_> = ctx.whitelisted_items().iter().cloned().collect();

        let whitelisted_and_blacklisted_items: ItemSet = whitelisted_items.iter()
            .cloned()
            .flat_map(|i| {
                let mut reachable = vec![i];
                i.trace(ctx, &mut |s, _| {
                    reachable.push(s);
                }, &());
                reachable
            })
            .collect();

        for item in whitelisted_and_blacklisted_items {
            dependencies.entry(item).or_insert(vec![]);

            {
                // We reverse our natural IR graph edges to find dependencies
                // between nodes.
                item.trace(ctx, &mut |sub_item: ItemId, edge_kind| {
                    if Self::consider_edge(edge_kind) {
                        dependencies.entry(sub_item)
                            .or_insert(vec![])
                            .push(item);
                    }
                }, &());
            }
        }

        CannotDeriveDebug {
            ctx,
            cannot_derive_debug,
            dependencies,
        }
    }

    fn initial_worklist(&self) -> Vec<ItemId> {
        self.ctx.whitelisted_items().iter().cloned().collect()
    }

    fn constrain(&mut self, id: ItemId) -> bool {
        if self.cannot_derive_debug.contains(&id) {
            return false;
        }

        let item = self.ctx.resolve_item(id);
        let ty = match item.as_type() {
            None => return false,
            Some(ty) => ty
        };

        match *ty.kind() {
            // handle the simple case
            // These can derive debug without further information
            TypeKind::Void |
            TypeKind::NullPtr |
            TypeKind::Int(..) |
            TypeKind::Float(..) |
            TypeKind::Complex(..) |
            TypeKind::Function(..) |
            TypeKind::Enum(..) |
            TypeKind::Reference(..) |
            TypeKind::BlockPointer |
            TypeKind::Named |
            TypeKind::UnresolvedTypeRef(..) |
            TypeKind::ObjCInterface(..) |
            TypeKind::ObjCId |
            TypeKind::ObjCSel => {
                return false;
            },
            TypeKind::Opaque => {
                if ty.layout(self.ctx)
                    .map_or(true, |l| l.opaque().can_trivially_derive_debug(self.ctx, ())) {
                        return false;
                    } else {
                        return self.insert(id);
                    }
            },
            TypeKind::Array(t, len) => {
                if len <= RUST_DERIVE_IN_ARRAY_LIMIT {
                    if self.cannot_derive_debug.contains(&t) {
                        return self.insert(id);
                    }
                    return false;
                } else {
                    return self.insert(id);
                }
            },
            TypeKind::ResolvedTypeRef(t) |
            TypeKind::TemplateAlias(t, _) |
            TypeKind::Alias(t) => {
                if self.cannot_derive_debug.contains(&t) {
                    return self.insert(id);
                }
                return false;
            },
            TypeKind::Comp(ref info) => {
                if info.has_non_type_template_params() {
                    if ty.layout(self.ctx).map_or(true,
                                                  |l| l.opaque().can_trivially_derive_debug(self.ctx, ())) {
                        return false;
                    } else {
                        return self.insert(id);
                    }
                }
                if info.kind() == CompKind::Union {
                    if self.ctx.options().unstable_rust {
                        return self.insert(id);
                    }

                    if ty.layout(self.ctx).map_or(true,
                                                  |l| l.opaque().can_trivially_derive_debug(self.ctx, ())) {
                        return false;
                    } else {
                        return self.insert(id);
                    }
                }
                let bases_cannot_derive = info.base_members()
                    .iter()
                    .any(|base| self.cannot_derive_debug.contains(&base.ty));
                if bases_cannot_derive {
                    return self.insert(id);
                }
                let fields_cannot_derive = info.fields()
                    .iter()
                    .any(|f| {
                        match f {
                            &Field::DataMember(ref data) => self.cannot_derive_debug.contains(&data.ty()),
                            &Field::Bitfields(ref bfu) => bfu.bitfields()
                                .iter().any(|b| {
                                    self.cannot_derive_debug.contains(&b.ty())
                                })
                        }
                    });
                if fields_cannot_derive {
                    return self.insert(id);
                }
                false
            },
            TypeKind::Pointer(inner) => {
                let inner_type = self.ctx.resolve_type(inner);
                if let TypeKind::Function(ref sig) =
                    *inner_type.canonical_type(self.ctx).kind() {
                        if sig.can_trivially_derive_debug(&self.ctx, ()) {
                            return false;
                        } else {
                            return self.insert(id);
                        }
                    }
                false
            },
            TypeKind::TemplateInstantiation(ref template) => {
                let args_cannot_derive = template.template_arguments()
                    .iter()
                    .any(|arg| self.cannot_derive_debug.contains(&arg));
                if args_cannot_derive {
                    return self.insert(id);
                }
                let ty_cannot_derive = template.template_definition()
                    .into_resolver()
                    .through_type_refs()
                    .through_type_aliases()
                    .resolve(self.ctx)
                    .as_type()
                    .expect("Instantiations of a non-type?")
                    .as_comp()
                    .and_then(|c| {
                        // For non-type template parameters, we generate an opaque
                        // blob, and in this case the instantiation has a better
                        // idea of the layout than the definition does.
                        if c.has_non_type_template_params() {
                            let opaque = ty.layout(self.ctx)
                                .or_else(|| self.ctx.resolve_type(template.template_definition()).layout(self.ctx))
                                .unwrap_or(Layout::zero())
                                .opaque();
                            Some(!opaque.can_trivially_derive_debug(&self.ctx, ()))
                        } else {
                            None
                        }
                    })
                    .unwrap_or_else(|| self.cannot_derive_debug.contains(&template.template_definition()));
                if ty_cannot_derive {
                    return self.insert(id);
                }
                false
            },
        }
    }

    fn each_depending_on<F>(&self, id: ItemId, mut f: F)
        where F: FnMut(ItemId),
    {
        if let Some(edges) = self.dependencies.get(&id) {
            for item in edges {
                trace!("enqueue {:?} into worklist", item);
                f(*item);
            }
        }
    }
}

impl<'ctx, 'gen> From<CannotDeriveDebug<'ctx, 'gen>> for HashSet<ItemId> {
    fn from(analysis: CannotDeriveDebug<'ctx, 'gen>) -> Self {
        analysis.cannot_derive_debug
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::common::type_not_allowed;
use libra_types::transaction::{ArgumentABI, ScriptABI, TypeArgumentABI};
use move_core_types::language_storage::TypeTag;

use std::{
    io::{Result, Write},
    path::PathBuf,
};

/// Output transaction builders in Python for the given ABIs.
pub fn output(out: &mut dyn Write, abis: &[ScriptABI]) -> Result<()> {
    output_preamble(out, None, None)?;
    for abi in abis {
        output_builder(out, abi)?;
    }
    Ok(())
}

fn output_with_optional_packages(
    out: &mut dyn Write,
    abis: &[ScriptABI],
    serde_package_name: Option<String>,
    libra_package_name: Option<String>,
) -> Result<()> {
    output_preamble(out, serde_package_name, libra_package_name)?;
    for abi in abis {
        output_builder(out, abi)?;
    }
    Ok(())
}

fn quote_from_package(package_name: Option<String>) -> String {
    match package_name {
        None => "".to_string(),
        Some(name) => format!("from {} ", name),
    }
}

fn quote_from_package_and_module(package_name: Option<String>, module_name: &str) -> String {
    match package_name {
        None => format!("from {} ", module_name),
        Some(name) => format!("from {}.{} ", name, module_name),
    }
}

fn output_preamble(
    out: &mut dyn Write,
    serde_package_name: Option<String>,
    libra_package_name: Option<String>,
) -> Result<()> {
    writeln!(
        out,
        r#"import typing
{}import serde_types as st
{}import Script, TypeTag, AccountAddress, TransactionArgument__Bool, TransactionArgument__U8, TransactionArgument__U64, TransactionArgument__U128, TransactionArgument__Address, TransactionArgument__U8Vector
"#,
        quote_from_package(serde_package_name),
        quote_from_package_and_module(libra_package_name, "libra_types"),
    )
}

fn output_builder(out: &mut dyn Write, abi: &ScriptABI) -> Result<()> {
    writeln!(
        out,
        "\ndef encode_{}_script({}) -> Script:",
        abi.name(),
        [
            quote_type_parameters(abi.ty_args()),
            quote_parameters(abi.args()),
        ]
        .concat()
        .join(", ")
    )?;
    writeln!(out, "{}", quote_doc(abi.doc()))?;
    writeln!(
        out,
        r#"    return Script(
        code={},
        ty_args=[{}],
        args=[{}],
    )"#,
        quote_code(abi.code()),
        quote_type_arguments(abi.ty_args()),
        quote_arguments(abi.args()),
    )?;
    Ok(())
}

fn quote_doc(doc: &str) -> String {
    let doc = crate::common::prepare_doc_string(doc);
    let s: Vec<_> = doc.splitn(2, |c| c == '.').collect();
    if s.len() <= 1 || s[1].is_empty() {
        format!("    \"\"\"{}.\"\"\"", s[0])
    } else {
        format!(
            r#"    """{}.

{}    """"#,
            s[0],
            textwrap::indent(s[1], "    "),
        )
    }
}

fn quote_type_parameters(ty_args: &[TypeArgumentABI]) -> Vec<String> {
    ty_args
        .iter()
        .map(|ty_arg| format!("{}: TypeTag", ty_arg.name()))
        .collect()
}

fn quote_parameters(args: &[ArgumentABI]) -> Vec<String> {
    args.iter()
        .map(|arg| format!("{}: {}", arg.name(), quote_type(arg.type_tag())))
        .collect()
}

fn quote_code(code: &[u8]) -> String {
    format!(
        "b\"{}\"",
        code.iter()
            .map(|x| format!("\\x{:02x}", x))
            .collect::<Vec<_>>()
            .join("")
    )
}

fn quote_type_arguments(ty_args: &[TypeArgumentABI]) -> String {
    ty_args
        .iter()
        .map(|ty_arg| ty_arg.name().to_string())
        .collect::<Vec<_>>()
        .join(", ")
}

fn quote_arguments(args: &[ArgumentABI]) -> String {
    args.iter()
        .map(|arg| quote_transaction_argument(arg.type_tag(), arg.name()))
        .collect::<Vec<_>>()
        .join(", ")
}

fn quote_type(type_tag: &TypeTag) -> String {
    use TypeTag::*;
    match type_tag {
        Bool => "st.bool".into(),
        U8 => "st.uint8".into(),
        U64 => "st.uint64".into(),
        U128 => "st.uint128".into(),
        Address => "AccountAddress".into(),
        Vector(type_tag) => match type_tag.as_ref() {
            U8 => "bytes".into(),
            _ => type_not_allowed(type_tag),
        },

        Struct(_) | Signer => type_not_allowed(type_tag),
    }
}

fn quote_transaction_argument(type_tag: &TypeTag, name: &str) -> String {
    use TypeTag::*;
    match type_tag {
        Bool => format!("TransactionArgument__Bool({})", name),
        U8 => format!("TransactionArgument__U8({})", name),
        U64 => format!("TransactionArgument__U64({})", name),
        U128 => format!("TransactionArgument__U128({})", name),
        Address => format!("TransactionArgument__Address({})", name),
        Vector(type_tag) => match type_tag.as_ref() {
            U8 => format!("TransactionArgument__U8Vector({})", name),
            _ => type_not_allowed(type_tag),
        },

        Struct(_) | Signer => type_not_allowed(type_tag),
    }
}

pub struct Installer {
    install_dir: PathBuf,
    serde_package_name: Option<String>,
    libra_package_name: Option<String>,
}

impl Installer {
    pub fn new(
        install_dir: PathBuf,
        serde_package_name: Option<String>,
        libra_package_name: Option<String>,
    ) -> Self {
        Installer {
            install_dir,
            serde_package_name,
            libra_package_name,
        }
    }

    fn open_module_init_file(&self, name: &str) -> Result<std::fs::File> {
        let dir_path = self.install_dir.join(name);
        std::fs::create_dir_all(&dir_path)?;
        std::fs::File::create(dir_path.join("__init__.py"))
    }
}

impl crate::SourceInstaller for Installer {
    type Error = Box<dyn std::error::Error>;

    fn install_transaction_builders(
        &self,
        name: &str,
        abis: &[ScriptABI],
    ) -> std::result::Result<(), Self::Error> {
        let mut file = self.open_module_init_file(name)?;
        output_with_optional_packages(
            &mut file,
            abis,
            self.serde_package_name.clone(),
            self.libra_package_name.clone(),
        )?;
        Ok(())
    }
}
<commit_msg>[transaction builder generator] python: create PythonEmitter<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::common::type_not_allowed;
use libra_types::transaction::{ArgumentABI, ScriptABI, TypeArgumentABI};
use move_core_types::language_storage::TypeTag;
use serde_generate::indent::{IndentConfig, IndentedWriter};

use std::{
    io::{Result, Write},
    path::PathBuf,
};

/// Output transaction builders in Python for the given ABIs.
pub fn output(out: &mut dyn Write, abis: &[ScriptABI]) -> Result<()> {
    output_with_optional_packages(out, abis, None, None)
}

fn output_with_optional_packages(
    out: &mut dyn Write,
    abis: &[ScriptABI],
    serde_package_name: Option<String>,
    libra_package_name: Option<String>,
) -> Result<()> {
    let mut emitter = PythonEmitter {
        out: IndentedWriter::new(out, IndentConfig::Space(4)),
        serde_package_name,
        libra_package_name,
    };
    emitter.output_preamble()?;
    for abi in abis {
        emitter.output_builder(abi)?;
    }
    Ok(())
}

/// Shared state for the Python code generator.
struct PythonEmitter<T> {
    /// Writer.
    out: IndentedWriter<T>,
    /// Package where to find the serde module (if any).
    serde_package_name: Option<String>,
    /// Package where to find the libra module (if any).
    libra_package_name: Option<String>,
}

impl<T> PythonEmitter<T>
where
    T: Write,
{
    fn quote_from_package(package_name: &Option<String>) -> String {
        match package_name {
            None => "".to_string(),
            Some(name) => format!("from {} ", name),
        }
    }

    fn quote_from_package_and_module(package_name: &Option<String>, module_name: &str) -> String {
        match package_name {
            None => format!("from {} ", module_name),
            Some(name) => format!("from {}.{} ", name, module_name),
        }
    }

    fn output_preamble(&mut self) -> Result<()> {
        writeln!(
            self.out,
            r#"import typing
{}import serde_types as st
{}import Script, TypeTag, AccountAddress, TransactionArgument__Bool, TransactionArgument__U8, TransactionArgument__U64, TransactionArgument__U128, TransactionArgument__Address, TransactionArgument__U8Vector
"#,
            Self::quote_from_package(&self.serde_package_name),
            Self::quote_from_package_and_module(&self.libra_package_name, "libra_types"),
        )
    }

    fn output_builder(&mut self, abi: &ScriptABI) -> Result<()> {
        writeln!(
            self.out,
            "\ndef encode_{}_script({}) -> Script:",
            abi.name(),
            [
                Self::quote_type_parameters(abi.ty_args()),
                Self::quote_parameters(abi.args()),
            ]
            .concat()
            .join(", ")
        )?;
        self.out.indent();
        writeln!(self.out, "{}", Self::quote_doc(abi.doc()))?;
        writeln!(
            self.out,
            r#"return Script(
    code={},
    ty_args=[{}],
    args=[{}],
)"#,
            Self::quote_code(abi.code()),
            Self::quote_type_arguments(abi.ty_args()),
            Self::quote_arguments(abi.args()),
        )?;
        self.out.unindent();
        Ok(())
    }

    fn quote_doc(doc: &str) -> String {
        let doc = crate::common::prepare_doc_string(doc);
        let s: Vec<_> = doc.splitn(2, |c| c == '.').collect();
        if s.len() <= 1 || s[1].is_empty() {
            format!("\"\"\"{}.\"\"\"", s[0])
        } else {
            format!(
                r#""""{}.

{}
""""#,
                s[0], s[1],
            )
        }
    }

    fn quote_type_parameters(ty_args: &[TypeArgumentABI]) -> Vec<String> {
        ty_args
            .iter()
            .map(|ty_arg| format!("{}: TypeTag", ty_arg.name()))
            .collect()
    }

    fn quote_parameters(args: &[ArgumentABI]) -> Vec<String> {
        args.iter()
            .map(|arg| format!("{}: {}", arg.name(), Self::quote_type(arg.type_tag())))
            .collect()
    }

    fn quote_code(code: &[u8]) -> String {
        format!(
            "b\"{}\"",
            code.iter()
                .map(|x| format!("\\x{:02x}", x))
                .collect::<Vec<_>>()
                .join("")
        )
    }

    fn quote_type_arguments(ty_args: &[TypeArgumentABI]) -> String {
        ty_args
            .iter()
            .map(|ty_arg| ty_arg.name().to_string())
            .collect::<Vec<_>>()
            .join(", ")
    }

    fn quote_arguments(args: &[ArgumentABI]) -> String {
        args.iter()
            .map(|arg| Self::quote_transaction_argument(arg.type_tag(), arg.name()))
            .collect::<Vec<_>>()
            .join(", ")
    }

    fn quote_type(type_tag: &TypeTag) -> String {
        use TypeTag::*;
        match type_tag {
            Bool => "st.bool".into(),
            U8 => "st.uint8".into(),
            U64 => "st.uint64".into(),
            U128 => "st.uint128".into(),
            Address => "AccountAddress".into(),
            Vector(type_tag) => match type_tag.as_ref() {
                U8 => "bytes".into(),
                _ => type_not_allowed(type_tag),
            },

            Struct(_) | Signer => type_not_allowed(type_tag),
        }
    }

    fn quote_transaction_argument(type_tag: &TypeTag, name: &str) -> String {
        use TypeTag::*;
        match type_tag {
            Bool => format!("TransactionArgument__Bool({})", name),
            U8 => format!("TransactionArgument__U8({})", name),
            U64 => format!("TransactionArgument__U64({})", name),
            U128 => format!("TransactionArgument__U128({})", name),
            Address => format!("TransactionArgument__Address({})", name),
            Vector(type_tag) => match type_tag.as_ref() {
                U8 => format!("TransactionArgument__U8Vector({})", name),
                _ => type_not_allowed(type_tag),
            },

            Struct(_) | Signer => type_not_allowed(type_tag),
        }
    }
}

pub struct Installer {
    install_dir: PathBuf,
    serde_package_name: Option<String>,
    libra_package_name: Option<String>,
}

impl Installer {
    pub fn new(
        install_dir: PathBuf,
        serde_package_name: Option<String>,
        libra_package_name: Option<String>,
    ) -> Self {
        Installer {
            install_dir,
            serde_package_name,
            libra_package_name,
        }
    }

    fn open_module_init_file(&self, name: &str) -> Result<std::fs::File> {
        let dir_path = self.install_dir.join(name);
        std::fs::create_dir_all(&dir_path)?;
        std::fs::File::create(dir_path.join("__init__.py"))
    }
}

impl crate::SourceInstaller for Installer {
    type Error = Box<dyn std::error::Error>;

    fn install_transaction_builders(
        &self,
        name: &str,
        abis: &[ScriptABI],
    ) -> std::result::Result<(), Self::Error> {
        let mut file = self.open_module_init_file(name)?;
        output_with_optional_packages(
            &mut file,
            abis,
            self.serde_package_name.clone(),
            self.libra_package_name.clone(),
        )?;
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::num;
use addressable::Addressable;

struct Area<'self, ADDR> {
	base: ADDR,
	last: ADDR,
	handler: &'self mut Addressable<ADDR>,
}

pub struct Memory<'self, ADDR> {
	priv areas: ~[Area<'self, ADDR>],
}

impl<'self, ADDR> Memory<'self, ADDR> {
	pub fn new () -> Memory<ADDR> {
		Memory { areas: ~[] }
	}

	pub fn add<T: Send+Addressable<ADDR>> (&mut self, base: ADDR, last: ADDR, handler: &'self mut T) {
		self.areas.push(Area { base: base, last: last, handler: handler as &'self mut Addressable<ADDR> });
	}
}

impl<'self, ADDR: Int> Addressable<ADDR> for Memory<'self, ADDR> {
	pub fn get (&self, addr: ADDR) -> u8 {
		for self.areas.rev_iter().advance() |area| {
			if addr >= area.base && addr <= area.last {
				return area.handler.get(addr - area.base);
			}
		}
		fail!("memory: Read from unmapped memory area ($%x)", num::cast(addr));
	}

	pub fn set (&mut self, addr: ADDR, data: u8) {
		for self.areas.mut_rev_iter().advance() |area| {
			if addr >= area.base && addr <= area.last {
				area.handler.set(addr - area.base, data);
				return;
			}
		}
		fail!("memory: Write to unmapped memory area ($%x)", num::cast(addr));
	}
}

#[cfg(test)]
mod tests {
	use super::*;
	use addressable::Addressable;
	use ram::Ram;

	#[test]
	fn test_read_write () {
		let mut m: Memory<u16> = Memory::new();
		let mut ram1: Ram<u16> = Ram::new_sized(0x0400);
		let mut ram2: Ram<u16> = Ram::new_sized(0x0400);
		m.add(0x0000, 0x0400, &mut ram1);
		m.add(0x0200, 0x0600, &mut ram2);
		m.set(0x0300, 123);
		assert_eq!(m.get(0x0300), 123);
	}
}
<commit_msg>Refactored memory handler to use closures<commit_after>use addressable::Addressable;

struct Memory<'self, ADDR> {
	getfn: &'self fn(ADDR) -> u8,
	setfn: &'self fn(ADDR, u8),
}

impl<'self, ADDR> Memory<'self, ADDR> {
	pub fn new (getfn: &'self fn(ADDR) -> u8, setfn: &'self fn(ADDR, u8)) -> Memory<'self, ADDR> {
		Memory { getfn: getfn, setfn: setfn }
	}
}

impl<'self, ADDR: Int> Addressable<ADDR> for Memory<'self, ADDR> {
	pub fn get (&self, addr: ADDR) -> u8 {
		(self.getfn)(addr)
	}

	pub fn set (&mut self, addr: ADDR, data: u8) {
		(self.setfn)(addr, data);
	}
}

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

	#[test]
	fn test_get_set () {
		let mut ram: Ram<u16> = Ram::new_sized(0x0400);
		let mut mem = Memory::new(|addr| { ram.get(addr) }, |addr, data| { ram.set(addr, data); });
		mem.set(0x0200, 123);
		assert_eq!(mem.get(0x0200), 123);
		assert_eq!(ram.get(0x0200), 123);
		ram.set(0x0200, 234);
		assert_eq!(mem.get(0x0200), 234);
		assert_eq!(ram.get(0x0200), 234);
	}
}
<|endoftext|>


<commit_before>//! Data for tracking user information.
use std::borrow::ToOwned;
use std::cmp::Ordering;
use std::cmp::Ordering::{Less, Equal, Greater};
use std::str::FromStr;

/// IRC User data.
#[derive(Clone, Debug)]
pub struct User {
    /// The user's nickname.
    nickname: String,
    /// The user's username.
    username: Option<String>,
    /// The user's hostname.
    hostname: Option<String>,
    /// The user's highest access level.
    highest_access_level: AccessLevel,
    /// All of the user's current access levels.
    access_levels: Vec<AccessLevel>,
}

impl User {
    /// Creates a new User.
    pub fn new(string: &str) -> User {
        let ranks: Vec<_> = AccessLevelIterator::new(string).collect();
        let mut state = &string[ranks.len()..];
        let nickname = state.find('!').map_or(state, |i| &state[..i]).to_owned();
        state = state.find('!').map_or("", |i| &state[i+1..]);
        let username = state.find('@').map(|i| state[..i].to_owned());
        let hostname = state.find('@').map(|i| state[i+1..].to_owned());
        User {
            nickname: nickname,
            username: username,
            hostname: hostname,
            access_levels: {
                let mut ranks = ranks.clone();
                ranks.push(AccessLevel::Member);
                ranks
            },
            highest_access_level: {
                let mut max = AccessLevel::Member;
                for rank in ranks.into_iter() {
                    if rank > max {
                        max = rank
                    }
                }
                max
            },
        }
    }

    /// Gets the nickname of the user.
    pub fn get_nickname(&self) -> &str {
        &self.nickname
    }

    /// Gets the username of the user, if it's known.
    /// This requires the IRCv3.2 extension `userhost-in-name`.
    pub fn get_username(&self) -> Option<&str> {
        self.username.as_ref().map(|s| &s[..])
    }

    /// Gets the hostname of the user, if it's known.
    /// This requires the IRCv3.2 extension `userhost-in-name`.
    pub fn get_hostname(&self) -> Option<&str> {
        self.hostname.as_ref().map(|s| &s[..])
    }

    /// Gets the user's highest access level.
    pub fn highest_access_level(&self) -> AccessLevel {
        self.highest_access_level
    }

    /// Gets all the user's access levels.
    pub fn access_levels(&self) -> Vec<AccessLevel> {
        self.access_levels.clone()
    }

    /// Updates the user's access level.
    pub fn update_access_level(&mut self, mode: &str) {
        match mode {
            "+q" => self.add_access_level(AccessLevel::Owner),
            "-q" => self.sub_access_level(AccessLevel::Owner),
            "+a" => self.add_access_level(AccessLevel::Admin),
            "-a" => self.sub_access_level(AccessLevel::Admin),
            "+o" => self.add_access_level(AccessLevel::Oper),
            "-o" => self.sub_access_level(AccessLevel::Oper),
            "+h" => self.add_access_level(AccessLevel::HalfOp),
            "-h" => self.sub_access_level(AccessLevel::HalfOp),
            "+v" => self.add_access_level(AccessLevel::Voice),
            "-v" => self.sub_access_level(AccessLevel::Voice),
            _    => {},
       }
    }

    /// Adds an access level to the list, and updates the highest level if necessary.
    fn add_access_level(&mut self, level: AccessLevel) {
        if level > self.highest_access_level() {
            self.highest_access_level = level
        }
        self.access_levels.push(level.clone())
    }

    /// Removes an access level from the list, and updates the highest level if necessary.
    fn sub_access_level(&mut self, level: AccessLevel) {
        if let Some(n) = self.access_levels.iter().position(|x| *x == level) {
            self.access_levels.swap_remove(n);
        }
        if level == self.highest_access_level() {
            self.highest_access_level = {
                let mut max = AccessLevel::Member;
                for level in self.access_levels.iter() {
                    if level > &max {
                        max = level.clone()
                    }
                }
                max
            }
        }
    }
}

impl PartialEq for User {
    fn eq(&self, other: &User) -> bool {
        self.nickname == other.nickname && self.username == other.username &&
        self.hostname == other.hostname
    }
}

/// The user's access level.
#[derive(Copy, PartialEq, Clone, Debug)]
pub enum AccessLevel {
    /// The channel owner (~).
    Owner,
    /// A channel administrator (&).
    Admin,
    /// A channel operator (@),
    Oper,
    /// A channel half-oper (%),
    HalfOp,
    /// A user with voice (+),
    Voice,
    /// A normal user,
    Member,
}

impl PartialOrd for AccessLevel {
    fn partial_cmp(&self, other: &AccessLevel) -> Option<Ordering> {
        if self == other { return Some(Equal) }
        match self {
            &AccessLevel::Owner => Some(Greater),
            &AccessLevel::Admin => {
                if other == &AccessLevel::Owner {
                    Some(Less)
                } else {
                    Some(Greater)
                }
            },
            &AccessLevel::Oper => {
                if other == &AccessLevel::Owner || other == &AccessLevel::Admin {
                    Some(Less)
                } else {
                    Some(Greater)
                }
            },
            &AccessLevel::HalfOp => {
                if other == &AccessLevel::Voice || other == &AccessLevel::Member {
                    Some(Greater)
                } else {
                    Some(Less)
                }
            },
            &AccessLevel::Voice => {
                if other == &AccessLevel::Member {
                    Some(Greater)
                } else {
                    Some(Less)
                }
            },
            &AccessLevel::Member => Some(Less),
        }
    }
}

impl FromStr for AccessLevel {
    type Err = &'static str;
    fn from_str(s: &str) -> Result<AccessLevel, &'static str> {
        match s.chars().next() {
            Some('~') => Ok(AccessLevel::Owner),
            Some('&') => Ok(AccessLevel::Admin),
            Some('@') => Ok(AccessLevel::Oper),
            Some('%') => Ok(AccessLevel::HalfOp),
            Some('+') => Ok(AccessLevel::Voice),
            None => Err("No access level in an empty string."),
             _  =>Err("Failed to parse access level."),
        }
    }
}

/// An iterator used to parse access levels from strings.
struct AccessLevelIterator<'a> {
    value: &'a str,
}

impl<'a> AccessLevelIterator<'a> {
    pub fn new(value: &'a str) -> AccessLevelIterator<'a> {
        AccessLevelIterator { value: value }
    }
}

impl<'a> Iterator for AccessLevelIterator<'a> {
    type Item = AccessLevel;
    fn next(&mut self) -> Option<AccessLevel> {
        let ret = self.value.parse();
        if self.value.len() > 0 {
            self.value = &self.value[1..];
        }
        ret.ok()
    }
}

#[cfg(test)]
mod test {
    use super::{AccessLevel, User};
    use super::AccessLevel::*;

    #[test]
    fn parse_access_level() {
        assert!("member".parse::<AccessLevel>().is_err());
        assert_eq!("~owner".parse::<AccessLevel>().unwrap(), Owner);
        assert_eq!("&admin".parse::<AccessLevel>().unwrap(), Admin);
        assert_eq!("@oper".parse::<AccessLevel>().unwrap(), Oper);
        assert_eq!("%halfop".parse::<AccessLevel>().unwrap(), HalfOp);
        assert_eq!("+voice".parse::<AccessLevel>().unwrap(), Voice);
        assert!("".parse::<AccessLevel>().is_err());
    }

    #[test]
    fn create_user() {
        let user = User::new("~owner");
        let exp = User {
            nickname: format!("owner"),
            username: None,
            hostname: None,
            highest_access_level: Owner,
            access_levels: vec![Owner, Member],
        };
        assert_eq!(user, exp);
        assert_eq!(user.highest_access_level, exp.highest_access_level);
        assert_eq!(user.access_levels, exp.access_levels);
    }

    #[test]
    fn create_user_complex() {
        let user = User::new("~&+user");
        let exp = User {
            nickname: format!("user"),
            username: None,
            hostname: None,
            highest_access_level: Owner,
            access_levels: vec![Owner, Admin, Voice, Member]
        };
        assert_eq!(user, exp);
        assert_eq!(user.highest_access_level, exp.highest_access_level);
        assert_eq!(user.access_levels, exp.access_levels);

    }

    #[test]
    fn get_nickname() {
        let user = User::new("~owner");
        assert_eq!(user.get_nickname(), "owner");
    }

    #[test]
    fn access_level() {
        let user = User::new("~owner");
        assert_eq!(user.highest_access_level(), Owner);
    }

    #[test]
    fn update_user_rank() {
        let mut user = User::new("user");
        assert_eq!(user.highest_access_level, Member);
        user.update_access_level("+q");
        assert_eq!(user.highest_access_level, Owner);
        user.update_access_level("-q");
        assert_eq!(user.highest_access_level, Member);
        user.update_access_level("+a");
        assert_eq!(user.highest_access_level, Admin);
        user.update_access_level("-a");
        assert_eq!(user.highest_access_level, Member);
        user.update_access_level("+o");
        assert_eq!(user.highest_access_level, Oper);
        user.update_access_level("-o");
        assert_eq!(user.highest_access_level, Member);
        user.update_access_level("+h");
        assert_eq!(user.highest_access_level, HalfOp);
        user.update_access_level("-h");
        assert_eq!(user.highest_access_level, Member);
        user.update_access_level("+v");
        assert_eq!(user.highest_access_level, Voice);
        user.update_access_level("-v");
        assert_eq!(user.highest_access_level, Member);
    }

    #[test]
    fn derank_user_in_full() {
        let mut user = User::new("~&@%+user");
        assert_eq!(user.highest_access_level, Owner);
        assert_eq!(user.access_levels, vec![Owner, Admin, Oper, HalfOp, Voice, Member]);
        user.update_access_level("-h");
        assert_eq!(user.highest_access_level, Owner);
        assert_eq!(user.access_levels, vec![Owner, Admin, Oper, Member, Voice]);
        user.update_access_level("-q");
        assert_eq!(user.highest_access_level, Admin);
        assert_eq!(user.access_levels, vec![Voice, Admin, Oper, Member]);
        user.update_access_level("-a");
        assert_eq!(user.highest_access_level, Oper);
        assert_eq!(user.access_levels, vec![Voice, Member, Oper]);
        user.update_access_level("-o");
        assert_eq!(user.highest_access_level, Voice);
        assert_eq!(user.access_levels, vec![Voice, Member]);
        user.update_access_level("-v");
        assert_eq!(user.highest_access_level, Member);
        assert_eq!(user.access_levels, vec![Member]);
    }
}
<commit_msg>Added unit tests for new username/hostname parsing.<commit_after>//! Data for tracking user information.
use std::borrow::ToOwned;
use std::cmp::Ordering;
use std::cmp::Ordering::{Less, Equal, Greater};
use std::str::FromStr;

/// IRC User data.
#[derive(Clone, Debug)]
pub struct User {
    /// The user's nickname.
    nickname: String,
    /// The user's username.
    username: Option<String>,
    /// The user's hostname.
    hostname: Option<String>,
    /// The user's highest access level.
    highest_access_level: AccessLevel,
    /// All of the user's current access levels.
    access_levels: Vec<AccessLevel>,
}

impl User {
    /// Creates a new User.
    pub fn new(string: &str) -> User {
        let ranks: Vec<_> = AccessLevelIterator::new(string).collect();
        let mut state = &string[ranks.len()..];
        let nickname = state.find('!').map_or(state, |i| &state[..i]).to_owned();
        state = state.find('!').map_or("", |i| &state[i+1..]);
        let username = state.find('@').map(|i| state[..i].to_owned());
        let hostname = state.find('@').map(|i| state[i+1..].to_owned());
        User {
            nickname: nickname,
            username: username,
            hostname: hostname,
            access_levels: {
                let mut ranks = ranks.clone();
                ranks.push(AccessLevel::Member);
                ranks
            },
            highest_access_level: {
                let mut max = AccessLevel::Member;
                for rank in ranks.into_iter() {
                    if rank > max {
                        max = rank
                    }
                }
                max
            },
        }
    }

    /// Gets the nickname of the user.
    pub fn get_nickname(&self) -> &str {
        &self.nickname
    }

    /// Gets the username of the user, if it's known.
    /// This requires the IRCv3.2 extension `userhost-in-name`.
    pub fn get_username(&self) -> Option<&str> {
        self.username.as_ref().map(|s| &s[..])
    }

    /// Gets the hostname of the user, if it's known.
    /// This requires the IRCv3.2 extension `userhost-in-name`.
    pub fn get_hostname(&self) -> Option<&str> {
        self.hostname.as_ref().map(|s| &s[..])
    }

    /// Gets the user's highest access level.
    pub fn highest_access_level(&self) -> AccessLevel {
        self.highest_access_level
    }

    /// Gets all the user's access levels.
    pub fn access_levels(&self) -> Vec<AccessLevel> {
        self.access_levels.clone()
    }

    /// Updates the user's access level.
    pub fn update_access_level(&mut self, mode: &str) {
        match mode {
            "+q" => self.add_access_level(AccessLevel::Owner),
            "-q" => self.sub_access_level(AccessLevel::Owner),
            "+a" => self.add_access_level(AccessLevel::Admin),
            "-a" => self.sub_access_level(AccessLevel::Admin),
            "+o" => self.add_access_level(AccessLevel::Oper),
            "-o" => self.sub_access_level(AccessLevel::Oper),
            "+h" => self.add_access_level(AccessLevel::HalfOp),
            "-h" => self.sub_access_level(AccessLevel::HalfOp),
            "+v" => self.add_access_level(AccessLevel::Voice),
            "-v" => self.sub_access_level(AccessLevel::Voice),
            _    => {},
       }
    }

    /// Adds an access level to the list, and updates the highest level if necessary.
    fn add_access_level(&mut self, level: AccessLevel) {
        if level > self.highest_access_level() {
            self.highest_access_level = level
        }
        self.access_levels.push(level.clone())
    }

    /// Removes an access level from the list, and updates the highest level if necessary.
    fn sub_access_level(&mut self, level: AccessLevel) {
        if let Some(n) = self.access_levels.iter().position(|x| *x == level) {
            self.access_levels.swap_remove(n);
        }
        if level == self.highest_access_level() {
            self.highest_access_level = {
                let mut max = AccessLevel::Member;
                for level in self.access_levels.iter() {
                    if level > &max {
                        max = level.clone()
                    }
                }
                max
            }
        }
    }
}

impl PartialEq for User {
    fn eq(&self, other: &User) -> bool {
        self.nickname == other.nickname && self.username == other.username &&
        self.hostname == other.hostname
    }
}

/// The user's access level.
#[derive(Copy, PartialEq, Clone, Debug)]
pub enum AccessLevel {
    /// The channel owner (~).
    Owner,
    /// A channel administrator (&).
    Admin,
    /// A channel operator (@),
    Oper,
    /// A channel half-oper (%),
    HalfOp,
    /// A user with voice (+),
    Voice,
    /// A normal user,
    Member,
}

impl PartialOrd for AccessLevel {
    fn partial_cmp(&self, other: &AccessLevel) -> Option<Ordering> {
        if self == other { return Some(Equal) }
        match self {
            &AccessLevel::Owner => Some(Greater),
            &AccessLevel::Admin => {
                if other == &AccessLevel::Owner {
                    Some(Less)
                } else {
                    Some(Greater)
                }
            },
            &AccessLevel::Oper => {
                if other == &AccessLevel::Owner || other == &AccessLevel::Admin {
                    Some(Less)
                } else {
                    Some(Greater)
                }
            },
            &AccessLevel::HalfOp => {
                if other == &AccessLevel::Voice || other == &AccessLevel::Member {
                    Some(Greater)
                } else {
                    Some(Less)
                }
            },
            &AccessLevel::Voice => {
                if other == &AccessLevel::Member {
                    Some(Greater)
                } else {
                    Some(Less)
                }
            },
            &AccessLevel::Member => Some(Less),
        }
    }
}

impl FromStr for AccessLevel {
    type Err = &'static str;
    fn from_str(s: &str) -> Result<AccessLevel, &'static str> {
        match s.chars().next() {
            Some('~') => Ok(AccessLevel::Owner),
            Some('&') => Ok(AccessLevel::Admin),
            Some('@') => Ok(AccessLevel::Oper),
            Some('%') => Ok(AccessLevel::HalfOp),
            Some('+') => Ok(AccessLevel::Voice),
            None => Err("No access level in an empty string."),
             _  =>Err("Failed to parse access level."),
        }
    }
}

/// An iterator used to parse access levels from strings.
struct AccessLevelIterator<'a> {
    value: &'a str,
}

impl<'a> AccessLevelIterator<'a> {
    pub fn new(value: &'a str) -> AccessLevelIterator<'a> {
        AccessLevelIterator { value: value }
    }
}

impl<'a> Iterator for AccessLevelIterator<'a> {
    type Item = AccessLevel;
    fn next(&mut self) -> Option<AccessLevel> {
        let ret = self.value.parse();
        if self.value.len() > 0 {
            self.value = &self.value[1..];
        }
        ret.ok()
    }
}

#[cfg(test)]
mod test {
    use super::{AccessLevel, User};
    use super::AccessLevel::*;

    #[test]
    fn parse_access_level() {
        assert!("member".parse::<AccessLevel>().is_err());
        assert_eq!("~owner".parse::<AccessLevel>().unwrap(), Owner);
        assert_eq!("&admin".parse::<AccessLevel>().unwrap(), Admin);
        assert_eq!("@oper".parse::<AccessLevel>().unwrap(), Oper);
        assert_eq!("%halfop".parse::<AccessLevel>().unwrap(), HalfOp);
        assert_eq!("+voice".parse::<AccessLevel>().unwrap(), Voice);
        assert!("".parse::<AccessLevel>().is_err());
    }

    #[test]
    fn create_user() {
        let user = User::new("~owner");
        let exp = User {
            nickname: format!("owner"),
            username: None,
            hostname: None,
            highest_access_level: Owner,
            access_levels: vec![Owner, Member],
        };
        assert_eq!(user, exp);
        assert_eq!(user.highest_access_level, exp.highest_access_level);
        assert_eq!(user.access_levels, exp.access_levels);
    }

    #[test]
    fn create_user_complex() {
        let user = User::new("~&+user");
        let exp = User {
            nickname: format!("user"),
            username: None,
            hostname: None,
            highest_access_level: Owner,
            access_levels: vec![Owner, Admin, Voice, Member]
        };
        assert_eq!(user, exp);
        assert_eq!(user.highest_access_level, exp.highest_access_level);
        assert_eq!(user.access_levels, exp.access_levels);

    }

    #[test]
    fn get_nickname() {
        let user = User::new("~owner");
        assert_eq!(user.get_nickname(), "owner");
    }

    #[test]
    fn get_username() {
        let user = User::new("user!username@hostname");
        assert_eq!(user.get_username(), Some("username"));
        let user = User::new("user");
        assert_eq!(user.get_username(), None);
    }

    #[test]
    fn get_hostname() {
        let user = User::new("user!username@hostname");
        assert_eq!(user.get_hostname(), Some("hostname"));
        let user = User::new("user");
        assert_eq!(user.get_hostname(), None);
    }

    #[test]
    fn access_level() {
        let user = User::new("~owner");
        assert_eq!(user.highest_access_level(), Owner);
    }

    #[test]
    fn update_user_rank() {
        let mut user = User::new("user");
        assert_eq!(user.highest_access_level, Member);
        user.update_access_level("+q");
        assert_eq!(user.highest_access_level, Owner);
        user.update_access_level("-q");
        assert_eq!(user.highest_access_level, Member);
        user.update_access_level("+a");
        assert_eq!(user.highest_access_level, Admin);
        user.update_access_level("-a");
        assert_eq!(user.highest_access_level, Member);
        user.update_access_level("+o");
        assert_eq!(user.highest_access_level, Oper);
        user.update_access_level("-o");
        assert_eq!(user.highest_access_level, Member);
        user.update_access_level("+h");
        assert_eq!(user.highest_access_level, HalfOp);
        user.update_access_level("-h");
        assert_eq!(user.highest_access_level, Member);
        user.update_access_level("+v");
        assert_eq!(user.highest_access_level, Voice);
        user.update_access_level("-v");
        assert_eq!(user.highest_access_level, Member);
    }

    #[test]
    fn derank_user_in_full() {
        let mut user = User::new("~&@%+user");
        assert_eq!(user.highest_access_level, Owner);
        assert_eq!(user.access_levels, vec![Owner, Admin, Oper, HalfOp, Voice, Member]);
        user.update_access_level("-h");
        assert_eq!(user.highest_access_level, Owner);
        assert_eq!(user.access_levels, vec![Owner, Admin, Oper, Member, Voice]);
        user.update_access_level("-q");
        assert_eq!(user.highest_access_level, Admin);
        assert_eq!(user.access_levels, vec![Voice, Admin, Oper, Member]);
        user.update_access_level("-a");
        assert_eq!(user.highest_access_level, Oper);
        assert_eq!(user.access_levels, vec![Voice, Member, Oper]);
        user.update_access_level("-o");
        assert_eq!(user.highest_access_level, Voice);
        assert_eq!(user.access_levels, vec![Voice, Member]);
        user.update_access_level("-v");
        assert_eq!(user.highest_access_level, Member);
        assert_eq!(user.access_levels, vec![Member]);
    }
}
<|endoftext|>


<commit_before>use super::paths;
use pulldown_cmark::{html, Options, Parser};
use std::fs;

// Removes any previously generated output
pub fn clean() {
    paths::remove_dir(&paths::public());
}

// Generates a static HTML bundle from markdown notes
pub fn build() {
    paths::create_dir(&paths::public());

    match fs::read_dir(&paths::notes()) {
        Ok(markdown_files) => {
            let mut markdown_links_to_routes = Vec::new();

            for markdown_file in markdown_files {
                let markdown_file = match &markdown_file {
                    Ok(markdown_file) => markdown_file.path(),
                    Err(error) => panic!("There was a problem: {:?}", error),
                };

                let markdown_file_contents = match fs::read_to_string(&markdown_file) {
                    Ok(contents) => contents,
                    Err(error) => panic!("There was a problem: {:?}", error),
                };

                let route = &paths::file_stem(markdown_file);
                paths::create_dir(&paths::public().join(route));
                paths::create_file(
                    &paths::public().join(route).join("index.html"),
                    &markdown_to_html(&markdown_file_contents),
                );

                let title = match markdown_file_contents.lines().next() {
                    Some(title) => &title[2..],
                    None => panic!("Cannot find a title in {}.", &route),
                };
                markdown_links_to_routes.push(format!("- [{}](/{})", title, route).to_string());
            }

            let markdown_home = markdown_links_to_routes.join("\n");

            paths::create_file(
                &paths::public().join("index.html"),
                &markdown_to_html(&markdown_home),
            );
        }
        Err(error) => panic!("There was a problem: {:?}", error),
    };
}

// Adds a CNAME file for the host (GitHub Pages) and registrar (Hover) to use my custom domain name (trevordmiller.com)
pub fn configure() {
    paths::create_file(&paths::cname(), "trevordmiller.com");
}

// Pushes output to my GitHub Pages repo (https://github.com/trevordmiller/trevordmiller.github.io)
pub fn deploy() {}

fn markdown_to_html(markdown: &str) -> std::string::String {
    let parser = Parser::new_ext(markdown, Options::empty());
    let mut html = String::new();
    html::push_html(&mut html, parser);

    format!(
        "
        <!DOCTYPE html>

                <meta charset=\"utf-8\">
                <meta name=\"author\" content=\"Trevor D. Miller\">
                <meta name=\"description\" content=\"Personal website.\">
                <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">
                <title>trevordmiller.com</title>

                        trevordmiller.com

                        {}

Code

Resume

Videos

    ",
    &html
        )
}
<commit_msg>Conoslidate website shared navigation<commit_after>use super::paths;
use pulldown_cmark::{html, Options, Parser};
use std::fs;

// Removes any previously generated output
pub fn clean() {
    paths::remove_dir(&paths::public());
}

// Generates a static HTML bundle from markdown notes
pub fn build() {
    paths::create_dir(&paths::public());

    match fs::read_dir(&paths::notes()) {
        Ok(markdown_files) => {
            let mut markdown_links_to_routes = Vec::new();

            for markdown_file in markdown_files {
                let markdown_file = match &markdown_file {
                    Ok(markdown_file) => markdown_file.path(),
                    Err(error) => panic!("There was a problem: {:?}", error),
                };

                let markdown_file_contents = match fs::read_to_string(&markdown_file) {
                    Ok(contents) => contents,
                    Err(error) => panic!("There was a problem: {:?}", error),
                };

                let route = &paths::file_stem(markdown_file);
                paths::create_dir(&paths::public().join(route));
                paths::create_file(
                    &paths::public().join(route).join("index.html"),
                    &markdown_to_html(&markdown_file_contents),
                );

                let title = match markdown_file_contents.lines().next() {
                    Some(title) => &title[2..],
                    None => panic!("Cannot find a title in {}.", &route),
                };
                markdown_links_to_routes.push(format!("- [{}](/{})", title, route).to_string());
            }

            let markdown_home = markdown_links_to_routes.join("\n");

            paths::create_file(
                &paths::public().join("index.html"),
                &markdown_to_html(&markdown_home),
            );
        }
        Err(error) => panic!("There was a problem: {:?}", error),
    };
}

// Adds a CNAME file for the host (GitHub Pages) and registrar (Hover) to use my custom domain name (trevordmiller.com)
pub fn configure() {
    paths::create_file(&paths::cname(), "trevordmiller.com");
}

// Pushes output to my GitHub Pages repo (https://github.com/trevordmiller/trevordmiller.github.io)
pub fn deploy() {}

fn markdown_to_html(markdown: &str) -> std::string::String {
    let parser = Parser::new_ext(markdown, Options::empty());
    let mut html = String::new();
    html::push_html(&mut html, parser);

    format!(
        "
        <!DOCTYPE html>

                <meta charset=\"utf-8\">
                <meta name=\"author\" content=\"Trevor D. Miller\">
                <meta name=\"description\" content=\"Personal website.\">
                <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">
                <title>trevordmiller.com</title>

                        Home
                        GitHub
                        LinkedIn

                        {}

    ",
        &html
    )
}
<|endoftext|>


<commit_before>
import std::str;
import middle::trans;
import trans::decl_cdecl_fn;
import middle::trans_common::T_f32;
import middle::trans_common::T_f64;
import middle::trans_common::T_fn;
import middle::trans_common::T_bool;
import middle::trans_common::T_i1;
import middle::trans_common::T_i8;
import middle::trans_common::T_i32;
import middle::trans_common::T_int;
import middle::trans_common::T_vec;
import middle::trans_common::T_nil;
import middle::trans_common::T_opaque_chan_ptr;
import middle::trans_common::T_opaque_vec;
import middle::trans_common::T_opaque_port_ptr;
import middle::trans_common::T_ptr;
import middle::trans_common::T_size_t;
import middle::trans_common::T_void;
import lib::llvm::type_names;
import lib::llvm::llvm::ModuleRef;
import lib::llvm::llvm::ValueRef;
import lib::llvm::llvm::TypeRef;

type upcalls =
    {_fail: ValueRef,
     malloc: ValueRef,
     free: ValueRef,
     shared_malloc: ValueRef,
     shared_free: ValueRef,
     mark: ValueRef,
     get_type_desc: ValueRef,
     vec_grow: ValueRef,
     vec_push: ValueRef,
     cmp_type: ValueRef,
     log_type: ValueRef,
     dynastack_mark: ValueRef,
     dynastack_alloc: ValueRef,
     dynastack_free: ValueRef,
     rust_personality: ValueRef};

fn declare_upcalls(_tn: type_names, tydesc_type: TypeRef,
                   taskptr_type: TypeRef, llmod: ModuleRef) -> @upcalls {
    fn decl(llmod: ModuleRef, name: str, tys: [TypeRef], rv: TypeRef) ->
       ValueRef {
        let arg_tys: [TypeRef] = [];
        for t: TypeRef in tys { arg_tys += [t]; }
        let fn_ty = T_fn(arg_tys, rv);
        ret trans::decl_cdecl_fn(llmod, "upcall_" + name, fn_ty);
    }
    fn decl_with_taskptr(taskptr_type: TypeRef, llmod: ModuleRef, name: str,
                         tys: [TypeRef], rv: TypeRef) -> ValueRef {
        ret decl(llmod, name, [taskptr_type] + tys, rv);
    }
    let dv = bind decl_with_taskptr(taskptr_type, llmod, _, _, T_void());
    let d = bind decl_with_taskptr(taskptr_type, llmod, _, _, _);
    let dr = bind decl(llmod, _, _, _);

    ret @{_fail: dv("fail", [T_ptr(T_i8()), T_ptr(T_i8()), T_size_t()]),
          malloc:
              d("malloc", [T_size_t(), T_ptr(tydesc_type)], T_ptr(T_i8())),
          free: dv("free", [T_ptr(T_i8()), T_int()]),
          shared_malloc:
              d("shared_malloc", [T_size_t(), T_ptr(tydesc_type)],
                T_ptr(T_i8())),
          shared_free: dv("shared_free", [T_ptr(T_i8())]),
          mark: d("mark", [T_ptr(T_i8())], T_int()),
          get_type_desc:
              d("get_type_desc",
                [T_ptr(T_nil()), T_size_t(), T_size_t(), T_size_t(),
                 T_ptr(T_ptr(tydesc_type)), T_int()], T_ptr(tydesc_type)),
          vec_grow:
              d("vec_grow", [T_ptr(T_ptr(T_opaque_vec())), T_int()],
                T_void()),
          vec_push:
              d("vec_push",
                [T_ptr(T_ptr(T_opaque_vec())), T_ptr(tydesc_type),
                 T_ptr(T_i8())], T_void()),
          cmp_type:
              dr("cmp_type",
                 [T_ptr(T_i1()), taskptr_type, T_ptr(tydesc_type),
                  T_ptr(T_ptr(tydesc_type)), T_ptr(T_i8()), T_ptr(T_i8()),
                  T_i8()], T_void()),
          log_type:
              dr("log_type",
                 [taskptr_type, T_ptr(tydesc_type), T_ptr(T_i8()), T_i32()],
                 T_void()),
          dynastack_mark: d("dynastack_mark", [], T_ptr(T_i8())),
          dynastack_alloc:
              d("dynastack_alloc_2", [T_size_t(), T_ptr(tydesc_type)],
                T_ptr(T_i8())),
          dynastack_free: d("dynastack_free", [T_ptr(T_i8())], T_void()),
          rust_personality: dr("rust_personality", [], T_i32())
         };
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<commit_msg>rustc: Add upcall stubs for the new C stack upcalls<commit_after>
import std::str;
import middle::trans;
import trans::decl_cdecl_fn;
import middle::trans_common::T_f32;
import middle::trans_common::T_f64;
import middle::trans_common::T_fn;
import middle::trans_common::T_bool;
import middle::trans_common::T_i1;
import middle::trans_common::T_i8;
import middle::trans_common::T_i32;
import middle::trans_common::T_int;
import middle::trans_common::T_vec;
import middle::trans_common::T_nil;
import middle::trans_common::T_opaque_chan_ptr;
import middle::trans_common::T_opaque_vec;
import middle::trans_common::T_opaque_port_ptr;
import middle::trans_common::T_ptr;
import middle::trans_common::T_size_t;
import middle::trans_common::T_void;
import lib::llvm::type_names;
import lib::llvm::llvm::ModuleRef;
import lib::llvm::llvm::ValueRef;
import lib::llvm::llvm::TypeRef;

type upcalls =
    {_fail: ValueRef,
     malloc: ValueRef,
     free: ValueRef,
     shared_malloc: ValueRef,
     shared_free: ValueRef,
     mark: ValueRef,
     get_type_desc: ValueRef,
     vec_grow: ValueRef,
     vec_push: ValueRef,
     cmp_type: ValueRef,
     log_type: ValueRef,
     dynastack_mark: ValueRef,
     dynastack_alloc: ValueRef,
     dynastack_free: ValueRef,
     alloc_c_stack: ValueRef,
     call_c_stack: ValueRef,
     rust_personality: ValueRef};

fn declare_upcalls(_tn: type_names, tydesc_type: TypeRef,
                   taskptr_type: TypeRef, llmod: ModuleRef) -> @upcalls {
    fn decl(llmod: ModuleRef, name: str, tys: [TypeRef], rv: TypeRef) ->
       ValueRef {
        let arg_tys: [TypeRef] = [];
        for t: TypeRef in tys { arg_tys += [t]; }
        let fn_ty = T_fn(arg_tys, rv);
        ret trans::decl_cdecl_fn(llmod, "upcall_" + name, fn_ty);
    }
    fn decl_with_taskptr(taskptr_type: TypeRef, llmod: ModuleRef, name: str,
                         tys: [TypeRef], rv: TypeRef) -> ValueRef {
        ret decl(llmod, name, [taskptr_type] + tys, rv);
    }
    let dv = bind decl_with_taskptr(taskptr_type, llmod, _, _, T_void());
    let d = bind decl_with_taskptr(taskptr_type, llmod, _, _, _);
    let dr = bind decl(llmod, _, _, _);

    ret @{_fail: dv("fail", [T_ptr(T_i8()), T_ptr(T_i8()), T_size_t()]),
          malloc:
              d("malloc", [T_size_t(), T_ptr(tydesc_type)], T_ptr(T_i8())),
          free: dv("free", [T_ptr(T_i8()), T_int()]),
          shared_malloc:
              d("shared_malloc", [T_size_t(), T_ptr(tydesc_type)],
                T_ptr(T_i8())),
          shared_free: dv("shared_free", [T_ptr(T_i8())]),
          mark: d("mark", [T_ptr(T_i8())], T_int()),
          get_type_desc:
              d("get_type_desc",
                [T_ptr(T_nil()), T_size_t(), T_size_t(), T_size_t(),
                 T_ptr(T_ptr(tydesc_type)), T_int()], T_ptr(tydesc_type)),
          vec_grow:
              d("vec_grow", [T_ptr(T_ptr(T_opaque_vec())), T_int()],
                T_void()),
          vec_push:
              d("vec_push",
                [T_ptr(T_ptr(T_opaque_vec())), T_ptr(tydesc_type),
                 T_ptr(T_i8())], T_void()),
          cmp_type:
              dr("cmp_type",
                 [T_ptr(T_i1()), taskptr_type, T_ptr(tydesc_type),
                  T_ptr(T_ptr(tydesc_type)), T_ptr(T_i8()), T_ptr(T_i8()),
                  T_i8()], T_void()),
          log_type:
              dr("log_type",
                 [taskptr_type, T_ptr(tydesc_type), T_ptr(T_i8()), T_i32()],
                 T_void()),
          dynastack_mark: d("dynastack_mark", [], T_ptr(T_i8())),
          dynastack_alloc:
              d("dynastack_alloc_2", [T_size_t(), T_ptr(tydesc_type)],
                T_ptr(T_i8())),
          dynastack_free: d("dynastack_free", [T_ptr(T_i8())], T_void()),
          alloc_c_stack: dr("alloc_c_stack", [T_size_t()], T_ptr(T_i8())),
          call_c_stack: dr("call_c_stack", [T_ptr(T_i8()), T_ptr(T_i8())],
                           T_void()),
          rust_personality: dr("rust_personality", [], T_i32())
         };
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<|endoftext|>


<commit_before>// arc1.rs
// Make this code compile by filling in a value for `shared_numbers` where the
// TODO comment is and create an initial binding for `child_numbers`
// somewhere. Try not to create any copies of the `numbers` Vec!
// Execute `rustlings hint arc1` for hints :)

// I AM NOT DONE

use std::sync::Arc;
use std::thread;

fn main() {
    let numbers: Vec<_> = (0..100u32).collect();
    let shared_numbers = // TODO
    let mut joinhandles = Vec::new();

    for offset in 0..8 {
        joinhandles.push(thread::spawn(move || {
            let mut i = offset;
            let mut sum = 0;
            while i < child_numbers.len() {
                sum += child_numbers[i];
                i += 5;
            }
            println!("Sum of offset {} is {}", offset, sum);
        }));
    }
    for handle in joinhandles.into_iter() {
        handle.join().unwrap();
    }
}
<commit_msg>fix(arc1): Passively introduce attributes (#429)<commit_after>// arc1.rs
// Make this code compile by filling in a value for `shared_numbers` where the
// TODO comment is and create an initial binding for `child_numbers`
// somewhere. Try not to create any copies of the `numbers` Vec!
// Execute `rustlings hint arc1` for hints :)

// I AM NOT DONE

#![forbid(unused_imports)] // Do not change this, (or the next) line.
use std::sync::Arc;
use std::thread;

fn main() {
    let numbers: Vec<_> = (0..100u32).collect();
    let shared_numbers = // TODO
    let mut joinhandles = Vec::new();

    for offset in 0..8 {
        joinhandles.push(thread::spawn(move || {
            let mut i = offset;
            let mut sum = 0;
            while i < child_numbers.len() {
                sum += child_numbers[i];
                i += 5;
            }
            println!("Sum of offset {} is {}", offset, sum);
        }));
    }
    for handle in joinhandles.into_iter() {
        handle.join().unwrap();
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use mem_map::*;
use cartridge::Cartridge;
use memory::Memory;
use gpu::Gpu;
use device::Device;
use apu::Apu;

pub trait Interconnect {
    fn read_byte(&self, addr: u16) -> u8;
    fn read_halfword(&self, addr: u16) -> u16;

    fn write_byte(&mut self, addr: u16, val: u8);
    fn write_halfword(&mut self, addr: u16, val: u16);

    fn step(&mut self, cycles: u16, device: &mut Device);

    fn get_width(&self) -> usize;
    fn get_height(&self) -> usize;
}

pub struct GBInterconnect {
    cartridge: Cartridge,
    gpu: Gpu,
    apu: Apu,

    internal_ram: Memory,
    high_ram: Memory,
    ie_register: u8,
}

pub struct MockInterconnect {
    memory: HashMap<u16, u8>,
}

impl GBInterconnect {
    pub fn new(cartridge: Cartridge) -> GBInterconnect {
        GBInterconnect {
            cartridge: cartridge,
            gpu: Gpu::new(),
            apu: Apu::new(),

            internal_ram: Memory::new(INTERNAL_RAM_LENGTH),
            high_ram: Memory::new(HIGH_RAM_END),
            ie_register: 0,
        }
    }
}

impl Interconnect for GBInterconnect {
    fn read_byte(&self, addr: u16) -> u8 {
        match addr {
            ROM0_START...ROM0_END => self.cartridge.read_byte(addr - ROM0_START),
            VRAM_START...VRAM_END => self.gpu.read_vram(addr - VRAM_START),
            INTERNAL_RAM_START...INTERNAL_RAM_END => {
                self.internal_ram.read_byte(addr - INTERNAL_RAM_START)
            }
            IRAM_ECHO_START...IRAM_ECHO_END => self.internal_ram.read_byte(addr - IRAM_ECHO_START),
            HIGH_RAM_START...HIGH_RAM_END => self.high_ram.read_byte(addr - HIGH_RAM_START),
            OAM_START...OAM_END => self.gpu.read_oam(addr - OAM_START),
            0xff10...0xff3f => self.apu.read_reg(addr),
            0xff40...0xff4b => self.gpu.read_reg(addr),
            0xffff => self.ie_register,
            _ => panic!("Read from unrecognized memory segment {:04x}", addr),
        }
    }

    fn write_byte(&mut self, addr: u16, val: u8) {
        match addr {
            VRAM_START...VRAM_END => self.gpu.write_vram(addr - VRAM_START, val),
            INTERNAL_RAM_START...INTERNAL_RAM_END => {
                self.internal_ram.write_byte(addr - INTERNAL_RAM_START, val)
            }
            IRAM_ECHO_START...IRAM_ECHO_END => {
                self.internal_ram.write_byte(addr - IRAM_ECHO_START, val)
            }
            HIGH_RAM_START...HIGH_RAM_END => self.high_ram.write_byte(addr - HIGH_RAM_START, val),
            OAM_START...OAM_END => self.gpu.write_oam(addr - OAM_START, val),
            0xff10...0xff3f => self.apu.write_reg(addr, val),
            0xff40...0xff4b => self.gpu.write_reg(addr, val),
            0xffff => self.ie_register = val,
            _ => {
                panic!("Write to unrecognized memory segment {:04x} = {:02x}",
                       addr,
                       val)
            }
        }
    }

    fn read_halfword(&self, addr: u16) -> u16 {
        let lsb = self.read_byte(addr);
        let msb = self.read_byte(addr + 1);

        ((msb as u16) << 8) | (lsb as u16)
    }

    fn write_halfword(&mut self, addr: u16, val: u16) {
        let lsb = (val & 0xff) as u8;
        let msb = (val >> 8) as u8;

        self.write_byte(addr, lsb);
        self.write_byte(addr + 1, msb);
    }

    fn step(&mut self, cycles: u16, device: &mut Device) {
        self.gpu.step(cycles, device);
    }

    fn get_width(&self) -> usize {
        self.gpu.get_width()
    }

    fn get_height(&self) -> usize {
        self.gpu.get_height()
    }
}

impl MockInterconnect {
    pub fn new(instructions: &[u8]) -> MockInterconnect {
        let mut memory = HashMap::new();

        for (i, instr) in instructions.iter().enumerate() {
            memory.insert(i as u16, *instr);
        }

        MockInterconnect { memory: memory }
    }

    pub fn set_mem(&mut self, addr: u16, val: u8) {
        self.memory.insert(addr, val);
    }
}

impl Interconnect for MockInterconnect {
    fn read_byte(&self, addr: u16) -> u8 {
        *self.memory.get(&addr).unwrap_or(&0)
    }

    fn read_halfword(&self, addr: u16) -> u16 {
        let lsb = self.read_byte(addr);
        let msb = self.read_byte(addr + 1);

        ((msb as u16) << 8) | (lsb as u16)

    }

    fn write_byte(&mut self, addr: u16, val: u8) {
        self.memory.insert(addr, val);
    }

    fn write_halfword(&mut self, addr: u16, val: u16) {
        let lsb = (val & 0xff) as u8;
        let msb = (val >> 8) as u8;

        self.write_byte(addr, lsb);
        self.write_byte(addr + 1, msb);
    }

    fn step(&mut self, _: u16, _: &mut Device) {}

    fn get_width(&self) -> usize {
        0
    }

    fn get_height(&self) -> usize {
        0
    }
}
<commit_msg>Disable the boot rom once it's finished<commit_after>use std::collections::HashMap;
use mem_map::*;
use cartridge::Cartridge;
use memory::Memory;
use gpu::Gpu;
use device::Device;
use apu::Apu;

pub trait Interconnect {
    fn read_byte(&self, addr: u16) -> u8;
    fn read_halfword(&self, addr: u16) -> u16;

    fn write_byte(&mut self, addr: u16, val: u8);
    fn write_halfword(&mut self, addr: u16, val: u16);

    fn step(&mut self, cycles: u16, device: &mut Device);

    fn get_width(&self) -> usize;
    fn get_height(&self) -> usize;
}

pub struct GBInterconnect {
    cartridge: Cartridge,
    gpu: Gpu,
    apu: Apu,

    internal_ram: Memory,
    high_ram: Memory,
    ie_register: u8,
}

pub struct MockInterconnect {
    memory: HashMap<u16, u8>,
}

impl GBInterconnect {
    pub fn new(cartridge: Cartridge) -> GBInterconnect {
        GBInterconnect {
            cartridge: cartridge,
            gpu: Gpu::new(),
            apu: Apu::new(),

            internal_ram: Memory::new(INTERNAL_RAM_LENGTH),
            high_ram: Memory::new(HIGH_RAM_END),
            ie_register: 0,
        }
    }
}

impl Interconnect for GBInterconnect {
    fn read_byte(&self, addr: u16) -> u8 {
        match addr {
            ROM0_START...ROM0_END => self.cartridge.read_byte(addr - ROM0_START),
            VRAM_START...VRAM_END => self.gpu.read_vram(addr - VRAM_START),
            INTERNAL_RAM_START...INTERNAL_RAM_END => {
                self.internal_ram.read_byte(addr - INTERNAL_RAM_START)
            }
            IRAM_ECHO_START...IRAM_ECHO_END => self.internal_ram.read_byte(addr - IRAM_ECHO_START),
            HIGH_RAM_START...HIGH_RAM_END => self.high_ram.read_byte(addr - HIGH_RAM_START),
            OAM_START...OAM_END => self.gpu.read_oam(addr - OAM_START),
            0xff10...0xff3f => self.apu.read_reg(addr),
            0xff40...0xff4b => self.gpu.read_reg(addr),
            0xffff => self.ie_register,
            _ => panic!("Read from unrecognized memory segment {:04x}", addr),
        }
    }

    fn write_byte(&mut self, addr: u16, val: u8) {
        match addr {
            VRAM_START...VRAM_END => self.gpu.write_vram(addr - VRAM_START, val),
            INTERNAL_RAM_START...INTERNAL_RAM_END => {
                self.internal_ram.write_byte(addr - INTERNAL_RAM_START, val)
            }
            IRAM_ECHO_START...IRAM_ECHO_END => {
                self.internal_ram.write_byte(addr - IRAM_ECHO_START, val)
            }
            HIGH_RAM_START...HIGH_RAM_END => self.high_ram.write_byte(addr - HIGH_RAM_START, val),
            OAM_START...OAM_END => self.gpu.write_oam(addr - OAM_START, val),
            0xff10...0xff3f => self.apu.write_reg(addr, val),
            0xff40...0xff4b => self.gpu.write_reg(addr, val),
            0xff50 => self.cartridge.disable_boot_rom(),
            0xffff => self.ie_register = val,
            _ => {
                panic!("Write to unrecognized memory segment {:04x} = {:02x}",
                       addr,
                       val)
            }
        }
    }

    fn read_halfword(&self, addr: u16) -> u16 {
        let lsb = self.read_byte(addr);
        let msb = self.read_byte(addr + 1);

        ((msb as u16) << 8) | (lsb as u16)
    }

    fn write_halfword(&mut self, addr: u16, val: u16) {
        let lsb = (val & 0xff) as u8;
        let msb = (val >> 8) as u8;

        self.write_byte(addr, lsb);
        self.write_byte(addr + 1, msb);
    }

    fn step(&mut self, cycles: u16, device: &mut Device) {
        self.gpu.step(cycles, device);
    }

    fn get_width(&self) -> usize {
        self.gpu.get_width()
    }

    fn get_height(&self) -> usize {
        self.gpu.get_height()
    }
}

impl MockInterconnect {
    pub fn new(instructions: &[u8]) -> MockInterconnect {
        let mut memory = HashMap::new();

        for (i, instr) in instructions.iter().enumerate() {
            memory.insert(i as u16, *instr);
        }

        MockInterconnect { memory: memory }
    }

    pub fn set_mem(&mut self, addr: u16, val: u8) {
        self.memory.insert(addr, val);
    }
}

impl Interconnect for MockInterconnect {
    fn read_byte(&self, addr: u16) -> u8 {
        *self.memory.get(&addr).unwrap_or(&0)
    }

    fn read_halfword(&self, addr: u16) -> u16 {
        let lsb = self.read_byte(addr);
        let msb = self.read_byte(addr + 1);

        ((msb as u16) << 8) | (lsb as u16)

    }

    fn write_byte(&mut self, addr: u16, val: u8) {
        self.memory.insert(addr, val);
    }

    fn write_halfword(&mut self, addr: u16, val: u16) {
        let lsb = (val & 0xff) as u8;
        let msb = (val >> 8) as u8;

        self.write_byte(addr, lsb);
        self.write_byte(addr + 1, msb);
    }

    fn step(&mut self, _: u16, _: &mut Device) {}

    fn get_width(&self) -> usize {
        0
    }

    fn get_height(&self) -> usize {
        0
    }
}
<|endoftext|>