<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::fmt;
use std::io::Write;

use syn;

use crate::bindgen::cargo::cargo_metadata::Dependency;
use crate::bindgen::config::Config;
use crate::bindgen::writer::SourceWriter;

#[derive(PartialEq, Eq)]
enum DefineKey<'a> {
    Boolean(&'a str),
    Named(&'a str, &'a str),
}

impl<'a> DefineKey<'a> {
    fn load(key: &str) -> DefineKey {
        // TODO: dirty parser
        if key.contains('=') {
            let mut splits = key.trim().split('=');

            let name = if let Some(name) = splits.next() {
                name.trim()
            } else {
                return DefineKey::Boolean(key);
            };

            let value = if let Some(value) = splits.next() {
                value.trim()
            } else {
                return DefineKey::Boolean(key);
            };

            if splits.next().is_some() {
                return DefineKey::Boolean(key);
            }

            DefineKey::Named(name, value)
        } else {
            DefineKey::Boolean(key)
        }
    }
}

#[derive(Debug, Clone)]
pub enum Cfg {
    Boolean(String),
    Named(String, String),
    Any(Vec<Cfg>),
    All(Vec<Cfg>),
    Not(Box<Cfg>),
}

impl fmt::Display for Cfg {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Cfg::Boolean(key) => write!(f, "{}", key),
            Cfg::Named(key, value) => write!(f, "{} = {:?}", key, value),
            Cfg::Any(cfgs) => {
                write!(f, "any(")?;
                for (index, cfg) in cfgs.iter().enumerate() {
                    if index > 0 {
                        write!(f, ", ")?;
                    }
                    write!(f, "{}", cfg)?;
                }
                write!(f, ")")
            }
            Cfg::All(cfgs) => {
                write!(f, "all(")?;
                for (index, cfg) in cfgs.iter().enumerate() {
                    if index > 0 {
                        write!(f, ", ")?;
                    }
                    write!(f, "{}", cfg)?;
                }
                write!(f, ")")
            }
            Cfg::Not(cfg) => write!(f, "not({})", cfg),
        }
    }
}

impl Cfg {
    pub fn join(cfgs: &[Cfg]) -> Option<Cfg> {
        if cfgs.is_empty() {
            None
        } else {
            Some(Cfg::All(cfgs.to_owned()))
        }
    }

    pub fn append(parent: Option<&Cfg>, child: Option<Cfg>) -> Option<Cfg> {
        match (parent, child) {
            (None, None) => None,
            (None, Some(child)) => Some(child),
            (Some(parent), None) => Some(parent.clone()),
            (Some(parent), Some(child)) => Some(Cfg::All(vec![parent.clone(), child])),
        }
    }

    pub fn load(attrs: &[syn::Attribute]) -> Option<Cfg> {
        let mut configs = Vec::new();

        for attr in attrs {
            if let Ok(syn::Meta::List(syn::MetaList { path, nested, .. })) = attr.parse_meta() {
                if !path.is_ident("cfg") || nested.len() != 1 {
                    continue;
                }

                if let Some(config) = Cfg::load_single(nested.first().unwrap()) {
                    configs.push(config);
                }
            }
        }

        match configs.len() {
            0 => None,
            1 => Some(configs.pop().unwrap()),
            _ => Some(Cfg::All(configs)),
        }
    }

    pub fn load_metadata(dependency: &Dependency) -> Option<Cfg> {
        dependency
            .target
            .as_ref()
            .map(|target| {
                syn::parse_str::<syn::Meta>(target)
                    .expect("error parsing dependency's target metadata")
            })
            .and_then(|target| {
                if let syn::Meta::List(syn::MetaList { path, nested, .. }) = target {
                    if !path.is_ident("cfg") || nested.len() != 1 {
                        return None;
                    }
                    Cfg::load_single(nested.first().unwrap())
                } else {
                    None
                }
            })
    }

    fn load_single(item: &syn::NestedMeta) -> Option<Cfg> {
        match *item {
            syn::NestedMeta::Meta(syn::Meta::Path(ref path)) => Some(Cfg::Boolean(format!(
                "{}",
                path.segments.first().unwrap().ident
            ))),
            syn::NestedMeta::Meta(syn::Meta::NameValue(syn::MetaNameValue {
                ref path,
                ref lit,
                ..
            })) => match lit {
                &syn::Lit::Str(ref value) => Some(Cfg::Named(
                    format!("{}", path.segments.first().unwrap().ident),
                    value.value(),
                )),
                _ => None,
            },
            syn::NestedMeta::Meta(syn::Meta::List(syn::MetaList {
                ref path,
                ref nested,
                ..
            })) => {
                if path.is_ident("any") {
                    if let Some(configs) = Cfg::load_list(nested.iter()) {
                        Some(Cfg::Any(configs))
                    } else {
                        None
                    }
                } else if path.is_ident("all") {
                    if let Some(configs) = Cfg::load_list(nested.iter()) {
                        Some(Cfg::All(configs))
                    } else {
                        None
                    }
                } else if path.is_ident("not") {
                    if nested.len() != 1 {
                        return None;
                    }

                    if let Some(config) = Cfg::load_single(&nested[0]) {
                        Some(Cfg::Not(Box::new(config)))
                    } else {
                        None
                    }
                } else {
                    None
                }
            }
            _ => None,
        }
    }

    fn load_list<'a, I: Iterator<Item = &'a syn::NestedMeta>>(attrs: I) -> Option<Vec<Cfg>> {
        let mut configs = Vec::new();

        for attr in attrs {
            if let Some(config) = Cfg::load_single(attr) {
                configs.push(config);
            } else {
                return None;
            }
        }

        if configs.is_empty() {
            None
        } else {
            Some(configs)
        }
    }
}

pub trait ToCondition: Sized {
    fn to_condition(&self, config: &Config) -> Option<Condition>;
}

impl<'a> ToCondition for Option<Cfg> {
    fn to_condition(&self, config: &Config) -> Option<Condition> {
        self.as_ref()?.to_condition(config)
    }
}

impl<'a> ToCondition for Cfg {
    fn to_condition(&self, config: &Config) -> Option<Condition> {
        match *self {
            Cfg::Boolean(ref cfg_name) => {
                let define = config
                    .defines
                    .iter()
                    .find(|(key, ..)| DefineKey::Boolean(&cfg_name) == DefineKey::load(key));
                if let Some((_, define)) = define {
                    Some(Condition::Define(define.to_owned()))
                } else {
                    warn!(
                        "Missing `[defines]` entry for `{}` in cbindgen config.",
                        self,
                    );
                    None
                }
            }
            Cfg::Named(ref cfg_name, ref cfg_value) => {
                let define = config.defines.iter().find(|(key, ..)| {
                    DefineKey::Named(&cfg_name, &cfg_value) == DefineKey::load(key)
                });
                if let Some((_, define)) = define {
                    Some(Condition::Define(define.to_owned()))
                } else {
                    warn!(
                        "Missing `[defines]` entry for `{}` in cbindgen config.",
                        self,
                    );
                    None
                }
            }
            Cfg::Any(ref children) => {
                let conditions: Vec<_> = children
                    .iter()
                    .filter_map(|x| x.to_condition(config))
                    .collect();
                match conditions.len() {
                    0 => None,
                    1 => conditions.into_iter().next(),
                    _ => Some(Condition::Any(conditions)),
                }
            }
            Cfg::All(ref children) => {
                let cfgs: Vec<_> = children
                    .iter()
                    .filter_map(|x| x.to_condition(config))
                    .collect();
                match cfgs.len() {
                    0 => None,
                    1 => cfgs.into_iter().next(),
                    _ => Some(Condition::All(cfgs)),
                }
            }
            Cfg::Not(ref child) => child
                .to_condition(config)
                .map(|cfg| Condition::Not(Box::new(cfg))),
        }
    }
}

#[derive(Debug, Clone)]
pub enum Condition {
    Define(String),
    Any(Vec<Condition>),
    All(Vec<Condition>),
    Not(Box<Condition>),
}

impl Condition {
    fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
        match *self {
            Condition::Define(ref define) => {
                out.write("defined(");
                write!(out, "{}", define);
                out.write(")");
            }
            Condition::Any(ref conditions) => {
                out.write("(");
                for (i, condition) in conditions.iter().enumerate() {
                    if i != 0 {
                        out.write(" || ");
                    }
                    condition.write(config, out);
                }
                out.write(")");
            }
            Condition::All(ref conditions) => {
                out.write("(");
                for (i, condition) in conditions.iter().enumerate() {
                    if i != 0 {
                        out.write(" && ");
                    }
                    condition.write(config, out);
                }
                out.write(")");
            }
            Condition::Not(ref condition) => {
                out.write("!");
                condition.write(config, out);
            }
        }
    }
}

pub trait ConditionWrite {
    fn write_before<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>);
    fn write_after<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>);
}

impl ConditionWrite for Option<Condition> {
    fn write_before<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
        if let Some(ref cfg) = *self {
            out.push_set_spaces(0);
            out.write("#if ");
            cfg.write(config, out);
            out.pop_set_spaces();
            out.new_line();
        }
    }

    fn write_after<F: Write>(&self, _config: &Config, out: &mut SourceWriter<F>) {
        if self.is_some() {
            out.new_line();
            out.push_set_spaces(0);
            out.write("#endif");
            out.pop_set_spaces();
        }
    }
}
<commit_msg>ir: cfg: Deindent some code.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::fmt;
use std::io::Write;

use syn;

use crate::bindgen::cargo::cargo_metadata::Dependency;
use crate::bindgen::config::Config;
use crate::bindgen::writer::SourceWriter;

#[derive(PartialEq, Eq)]
enum DefineKey<'a> {
    Boolean(&'a str),
    Named(&'a str, &'a str),
}

impl<'a> DefineKey<'a> {
    fn load(key: &str) -> DefineKey {
        // TODO: dirty parser
        if !key.contains('=') {
            return DefineKey::Boolean(key);
        }

        let mut splits = key.trim().split('=');

        let name = match splits.next() {
            Some(n) => n.trim(),
            None => return DefineKey::Boolean(key),
        };

        let value = match splits.next() {
            Some(v) => v.trim(),
            None => return DefineKey::Boolean(key),
        };

        if splits.next().is_some() {
            return DefineKey::Boolean(key);
        }

        DefineKey::Named(name, value)
    }
}

#[derive(Debug, Clone)]
pub enum Cfg {
    Boolean(String),
    Named(String, String),
    Any(Vec<Cfg>),
    All(Vec<Cfg>),
    Not(Box<Cfg>),
}

impl fmt::Display for Cfg {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Cfg::Boolean(key) => write!(f, "{}", key),
            Cfg::Named(key, value) => write!(f, "{} = {:?}", key, value),
            Cfg::Any(cfgs) => {
                write!(f, "any(")?;
                for (index, cfg) in cfgs.iter().enumerate() {
                    if index > 0 {
                        write!(f, ", ")?;
                    }
                    write!(f, "{}", cfg)?;
                }
                write!(f, ")")
            }
            Cfg::All(cfgs) => {
                write!(f, "all(")?;
                for (index, cfg) in cfgs.iter().enumerate() {
                    if index > 0 {
                        write!(f, ", ")?;
                    }
                    write!(f, "{}", cfg)?;
                }
                write!(f, ")")
            }
            Cfg::Not(cfg) => write!(f, "not({})", cfg),
        }
    }
}

impl Cfg {
    pub fn join(cfgs: &[Cfg]) -> Option<Cfg> {
        if cfgs.is_empty() {
            None
        } else {
            Some(Cfg::All(cfgs.to_owned()))
        }
    }

    pub fn append(parent: Option<&Cfg>, child: Option<Cfg>) -> Option<Cfg> {
        match (parent, child) {
            (None, None) => None,
            (None, Some(child)) => Some(child),
            (Some(parent), None) => Some(parent.clone()),
            (Some(parent), Some(child)) => Some(Cfg::All(vec![parent.clone(), child])),
        }
    }

    pub fn load(attrs: &[syn::Attribute]) -> Option<Cfg> {
        let mut configs = Vec::new();

        for attr in attrs {
            if let Ok(syn::Meta::List(syn::MetaList { path, nested, .. })) = attr.parse_meta() {
                if !path.is_ident("cfg") || nested.len() != 1 {
                    continue;
                }

                if let Some(config) = Cfg::load_single(nested.first().unwrap()) {
                    configs.push(config);
                }
            }
        }

        match configs.len() {
            0 => None,
            1 => Some(configs.pop().unwrap()),
            _ => Some(Cfg::All(configs)),
        }
    }

    pub fn load_metadata(dependency: &Dependency) -> Option<Cfg> {
        dependency
            .target
            .as_ref()
            .map(|target| {
                syn::parse_str::<syn::Meta>(target)
                    .expect("error parsing dependency's target metadata")
            })
            .and_then(|target| {
                if let syn::Meta::List(syn::MetaList { path, nested, .. }) = target {
                    if !path.is_ident("cfg") || nested.len() != 1 {
                        return None;
                    }
                    Cfg::load_single(nested.first().unwrap())
                } else {
                    None
                }
            })
    }

    fn load_single(item: &syn::NestedMeta) -> Option<Cfg> {
        match *item {
            syn::NestedMeta::Meta(syn::Meta::Path(ref path)) => Some(Cfg::Boolean(format!(
                "{}",
                path.segments.first().unwrap().ident
            ))),
            syn::NestedMeta::Meta(syn::Meta::NameValue(syn::MetaNameValue {
                ref path,
                ref lit,
                ..
            })) => match lit {
                &syn::Lit::Str(ref value) => Some(Cfg::Named(
                    format!("{}", path.segments.first().unwrap().ident),
                    value.value(),
                )),
                _ => None,
            },
            syn::NestedMeta::Meta(syn::Meta::List(syn::MetaList {
                ref path,
                ref nested,
                ..
            })) => {
                if path.is_ident("any") {
                    if let Some(configs) = Cfg::load_list(nested.iter()) {
                        Some(Cfg::Any(configs))
                    } else {
                        None
                    }
                } else if path.is_ident("all") {
                    if let Some(configs) = Cfg::load_list(nested.iter()) {
                        Some(Cfg::All(configs))
                    } else {
                        None
                    }
                } else if path.is_ident("not") {
                    if nested.len() != 1 {
                        return None;
                    }

                    if let Some(config) = Cfg::load_single(&nested[0]) {
                        Some(Cfg::Not(Box::new(config)))
                    } else {
                        None
                    }
                } else {
                    None
                }
            }
            _ => None,
        }
    }

    fn load_list<'a, I: Iterator<Item = &'a syn::NestedMeta>>(attrs: I) -> Option<Vec<Cfg>> {
        let mut configs = Vec::new();

        for attr in attrs {
            if let Some(config) = Cfg::load_single(attr) {
                configs.push(config);
            } else {
                return None;
            }
        }

        if configs.is_empty() {
            None
        } else {
            Some(configs)
        }
    }
}

pub trait ToCondition: Sized {
    fn to_condition(&self, config: &Config) -> Option<Condition>;
}

impl<'a> ToCondition for Option<Cfg> {
    fn to_condition(&self, config: &Config) -> Option<Condition> {
        self.as_ref()?.to_condition(config)
    }
}

impl<'a> ToCondition for Cfg {
    fn to_condition(&self, config: &Config) -> Option<Condition> {
        match *self {
            Cfg::Boolean(ref cfg_name) => {
                let define = config
                    .defines
                    .iter()
                    .find(|(key, ..)| DefineKey::Boolean(&cfg_name) == DefineKey::load(key));
                if let Some((_, define)) = define {
                    Some(Condition::Define(define.to_owned()))
                } else {
                    warn!(
                        "Missing `[defines]` entry for `{}` in cbindgen config.",
                        self,
                    );
                    None
                }
            }
            Cfg::Named(ref cfg_name, ref cfg_value) => {
                let define = config.defines.iter().find(|(key, ..)| {
                    DefineKey::Named(&cfg_name, &cfg_value) == DefineKey::load(key)
                });
                if let Some((_, define)) = define {
                    Some(Condition::Define(define.to_owned()))
                } else {
                    warn!(
                        "Missing `[defines]` entry for `{}` in cbindgen config.",
                        self,
                    );
                    None
                }
            }
            Cfg::Any(ref children) => {
                let conditions: Vec<_> = children
                    .iter()
                    .filter_map(|x| x.to_condition(config))
                    .collect();
                match conditions.len() {
                    0 => None,
                    1 => conditions.into_iter().next(),
                    _ => Some(Condition::Any(conditions)),
                }
            }
            Cfg::All(ref children) => {
                let cfgs: Vec<_> = children
                    .iter()
                    .filter_map(|x| x.to_condition(config))
                    .collect();
                match cfgs.len() {
                    0 => None,
                    1 => cfgs.into_iter().next(),
                    _ => Some(Condition::All(cfgs)),
                }
            }
            Cfg::Not(ref child) => child
                .to_condition(config)
                .map(|cfg| Condition::Not(Box::new(cfg))),
        }
    }
}

#[derive(Debug, Clone)]
pub enum Condition {
    Define(String),
    Any(Vec<Condition>),
    All(Vec<Condition>),
    Not(Box<Condition>),
}

impl Condition {
    fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
        match *self {
            Condition::Define(ref define) => {
                out.write("defined(");
                write!(out, "{}", define);
                out.write(")");
            }
            Condition::Any(ref conditions) => {
                out.write("(");
                for (i, condition) in conditions.iter().enumerate() {
                    if i != 0 {
                        out.write(" || ");
                    }
                    condition.write(config, out);
                }
                out.write(")");
            }
            Condition::All(ref conditions) => {
                out.write("(");
                for (i, condition) in conditions.iter().enumerate() {
                    if i != 0 {
                        out.write(" && ");
                    }
                    condition.write(config, out);
                }
                out.write(")");
            }
            Condition::Not(ref condition) => {
                out.write("!");
                condition.write(config, out);
            }
        }
    }
}

pub trait ConditionWrite {
    fn write_before<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>);
    fn write_after<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>);
}

impl ConditionWrite for Option<Condition> {
    fn write_before<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
        if let Some(ref cfg) = *self {
            out.push_set_spaces(0);
            out.write("#if ");
            cfg.write(config, out);
            out.pop_set_spaces();
            out.new_line();
        }
    }

    fn write_after<F: Write>(&self, _config: &Config, out: &mut SourceWriter<F>) {
        if self.is_some() {
            out.new_line();
            out.push_set_spaces(0);
            out.write("#endif");
            out.pop_set_spaces();
        }
    }
}
<|endoftext|>


<commit_before>use cpu;
use cpu::Cpu;

pub fn ldr_1(cpu: &mut Cpu, data: cpu::ThumbInstrLoadStore_1) -> cpu::InstrStatus {
    let base_val = cpu.regs[bf!(data.rn) as usize];
    let immed_5 = bf!(data.immed_5) as u32;

    let addr = base_val + immed_5 * 4;
    // TODO: determine behavior based on CP15 r1 bit_U (22)
    cpu.regs[bf!(data.rd) as usize] = cpu.memory.read::<u32>(addr);

    cpu::InstrStatus::InBlock
}

pub fn ldr_3(cpu: &mut Cpu, data: cpu::ThumbInstrLoadStore_3) -> cpu::InstrStatus {
    let immed_8 = bf!(data.immed_8) as u32;
    let addr = (cpu.regs[15] & 0xFFFFFFFC) + immed_8 * 4;
    cpu.regs[bf!(data.rd) as usize] = cpu.memory.read::<u32>(addr);

    cpu::InstrStatus::InBlock
}

#[inline(always)]
pub fn ldr_4(cpu: &mut Cpu, data: cpu::ThumbInstrLoadStore_3) -> cpu::InstrStatus {
    let arminst: u32 = 0b1110010110001101_0000_00_00000000_00
                                          | ((bf!(data.rd) as u32) << 12)
                                                  | ((bf!(data.immed_8) as u32) << 2);
    cpu::instructions_arm::str(cpu, cpu::ArmInstrLoadStore::new(arminst))
}

#[inline(always)]
pub fn ldrb_1(cpu: &mut Cpu, data: cpu::ThumbInstrLoadStore_1) -> cpu::InstrStatus {
    let arminst: u32 = 0b111001011101_0000_0000_0000000_00000
                                      | ((bf!(data.rn) as u32) << 16)
                                           | ((bf!(data.rd) as u32) << 12)
                                                        | ((bf!(data.immed_5) as u32) << 0);
    cpu::instructions_arm::ldrb(cpu, cpu::ArmInstrLoadStore::new(arminst))
}

pub fn ldrh_1(cpu: &mut Cpu, data: cpu::ThumbInstrLoadStore_1) -> cpu::InstrStatus {
    let base_val = cpu.regs[bf!(data.rn) as usize];
    let immed_5 = bf!(data.immed_5) as u32;

    let addr = base_val + immed_5 * 2;
    // TODO: determine behavior based on CP15 r1 bit_U (22)
    cpu.regs[bf!(data.rd) as usize] = cpu.memory.read::<u16>(addr) as u32;

    cpu::InstrStatus::InBlock
}

pub fn pop(cpu: &mut Cpu, data: cpu::ThumbInstrPOP) -> cpu::InstrStatus {
    let register_list = bf!(data.register_list);
    let r_bit = bf!(data.r_bit);

    let mut addr = cpu.regs[13];

    for i in 0..7 {
        if bit!(register_list, i) == 1 {
            cpu.regs[i] = cpu.memory.read::<u32>(addr);
            addr += 4;
        }
    }

    let ret = if r_bit == 1 {
        let val = cpu.memory.read::<u32>(addr);
        addr += 4;

        bf!((cpu.cpsr).thumb_bit = bit!(val, 0));
        cpu.branch(val & 0xFFFFFFFE);

        cpu::InstrStatus::Branched
    } else {
        cpu::InstrStatus::InBlock
    };

    cpu.regs[13] = addr;
    ret
}

pub fn push(cpu: &mut Cpu, data: cpu::ThumbInstrPUSH) -> cpu::InstrStatus {
    let register_list = bf!(data.register_list);
    let r_bit = bf!(data.r_bit);

    let num_registers = register_list.count_ones() + r_bit as u32;
    cpu.regs[13] -= num_registers * 4;
    let mut addr = cpu.regs[13];

    for i in 0..7 {
        if bit!(register_list, i) == 1 {
            cpu.memory.write::<u32>(addr, cpu.regs[i]);
            addr += 4;
        }
    }

    if r_bit == 1 {
        cpu.memory.write::<u32>(addr, cpu.regs[14]);
    }

    cpu::InstrStatus::InBlock
}

pub fn str_1(cpu: &mut Cpu, data: cpu::ThumbInstrLoadStore_1) -> cpu::InstrStatus {
    let base_val = cpu.regs[bf!(data.rn) as usize];
    let immed_5 = bf!(data.immed_5) as u32;

    let addr = base_val + immed_5 * 4;
    // TODO: determine behavior based on CP15 r1 bit_U (22)
    cpu.memory.write::<u32>(addr, cpu.regs[bf!(data.rd) as usize]);

    cpu::InstrStatus::InBlock
}

#[inline(always)]
pub fn str_3(cpu: &mut Cpu, data: cpu::ThumbInstrLoadStore_3) -> cpu::InstrStatus {
    let arminst: u32 = 0b1110010110001101_0000_00_00000000_00
                                          | ((bf!(data.rd) as u32) << 12)
                                                           | ((bf!(data.immed_8) as u32) << 0);
    cpu::instructions_arm::str(cpu, cpu::ArmInstrLoadStore::new(arminst))
}

pub fn strh_1(cpu: &mut Cpu, data: cpu::ThumbInstrLoadStore_1) -> cpu::InstrStatus {
    let base_val = cpu.regs[bf!(data.rn) as usize];
    let immed_5 = bf!(data.immed_5) as u32;

    let addr = base_val + immed_5 * 2;
    // TODO: determine behavior based on CP15 r1 bit_U (22)
    cpu.memory.write::<u16>(addr, cpu.regs[bf!(data.rd) as usize] as u16);

    cpu::InstrStatus::InBlock
}
<commit_msg>THUMB: revert to ARM interpreter for PUSH/POP<commit_after>use cpu;
use cpu::Cpu;

pub fn ldr_1(cpu: &mut Cpu, data: cpu::ThumbInstrLoadStore_1) -> cpu::InstrStatus {
    let base_val = cpu.regs[bf!(data.rn) as usize];
    let immed_5 = bf!(data.immed_5) as u32;

    let addr = base_val + immed_5 * 4;
    // TODO: determine behavior based on CP15 r1 bit_U (22)
    cpu.regs[bf!(data.rd) as usize] = cpu.memory.read::<u32>(addr);

    cpu::InstrStatus::InBlock
}

pub fn ldr_3(cpu: &mut Cpu, data: cpu::ThumbInstrLoadStore_3) -> cpu::InstrStatus {
    let immed_8 = bf!(data.immed_8) as u32;
    let addr = (cpu.regs[15] & 0xFFFFFFFC) + immed_8 * 4;
    cpu.regs[bf!(data.rd) as usize] = cpu.memory.read::<u32>(addr);

    cpu::InstrStatus::InBlock
}

#[inline(always)]
pub fn ldr_4(cpu: &mut Cpu, data: cpu::ThumbInstrLoadStore_3) -> cpu::InstrStatus {
    let arminst: u32 = 0b1110010110001101_0000_00_00000000_00
                                          | ((bf!(data.rd) as u32) << 12)
                                                  | ((bf!(data.immed_8) as u32) << 2);
    cpu::instructions_arm::str(cpu, cpu::ArmInstrLoadStore::new(arminst))
}

#[inline(always)]
pub fn ldrb_1(cpu: &mut Cpu, data: cpu::ThumbInstrLoadStore_1) -> cpu::InstrStatus {
    let arminst: u32 = 0b111001011101_0000_0000_0000000_00000
                                      | ((bf!(data.rn) as u32) << 16)
                                           | ((bf!(data.rd) as u32) << 12)
                                                        | ((bf!(data.immed_5) as u32) << 0);
    cpu::instructions_arm::ldrb(cpu, cpu::ArmInstrLoadStore::new(arminst))
}

pub fn ldrh_1(cpu: &mut Cpu, data: cpu::ThumbInstrLoadStore_1) -> cpu::InstrStatus {
    let base_val = cpu.regs[bf!(data.rn) as usize];
    let immed_5 = bf!(data.immed_5) as u32;

    let addr = base_val + immed_5 * 2;
    // TODO: determine behavior based on CP15 r1 bit_U (22)
    cpu.regs[bf!(data.rd) as usize] = cpu.memory.read::<u16>(addr) as u32;

    cpu::InstrStatus::InBlock
}

pub fn pop(cpu: &mut Cpu, data: cpu::ThumbInstrPOP) -> cpu::InstrStatus {
    let arminst: u32 = 0b1110100010111101_0_0000000_00000000
                                          | ((bf!(data.r_bit) as u32) << 15)
                                                    | ((bf!(data.register_list) as u32) << 0);
    cpu::instructions_arm::ldm(cpu, cpu::ArmInstrLoadStoreMulti::new(arminst))
}

pub fn push(cpu: &mut Cpu, data: cpu::ThumbInstrPUSH) -> cpu::InstrStatus {
    let arminst: u32 = 0b11101001001011010_0_000000_00000000
                                           | ((bf!(data.r_bit) as u32) << 14)
                                                    | ((bf!(data.register_list) as u32) << 0);
    cpu::instructions_arm::stm(cpu, cpu::ArmInstrLoadStoreMulti::new(arminst))
}

pub fn str_1(cpu: &mut Cpu, data: cpu::ThumbInstrLoadStore_1) -> cpu::InstrStatus {
    let base_val = cpu.regs[bf!(data.rn) as usize];
    let immed_5 = bf!(data.immed_5) as u32;

    let addr = base_val + immed_5 * 4;
    // TODO: determine behavior based on CP15 r1 bit_U (22)
    cpu.memory.write::<u32>(addr, cpu.regs[bf!(data.rd) as usize]);

    cpu::InstrStatus::InBlock
}

#[inline(always)]
pub fn str_3(cpu: &mut Cpu, data: cpu::ThumbInstrLoadStore_3) -> cpu::InstrStatus {
    let arminst: u32 = 0b1110010110001101_0000_00_00000000_00
                                          | ((bf!(data.rd) as u32) << 12)
                                                           | ((bf!(data.immed_8) as u32) << 0);
    cpu::instructions_arm::str(cpu, cpu::ArmInstrLoadStore::new(arminst))
}

pub fn strh_1(cpu: &mut Cpu, data: cpu::ThumbInstrLoadStore_1) -> cpu::InstrStatus {
    let base_val = cpu.regs[bf!(data.rn) as usize];
    let immed_5 = bf!(data.immed_5) as u32;

    let addr = base_val + immed_5 * 2;
    // TODO: determine behavior based on CP15 r1 bit_U (22)
    cpu.memory.write::<u16>(addr, cpu.regs[bf!(data.rd) as usize] as u16);

    cpu::InstrStatus::InBlock
}
<|endoftext|>


<commit_before>use std::iter;
use std::{fmt, ops};
use board::std_board::{Square};

#[derive(PartialEq, Eq, Clone, Copy, Hash)]
pub struct BitBoard {
    pub board: u64,
}

impl ops::BitOr for BitBoard {
    type Output = BitBoard;
    fn bitor(self, rhs: BitBoard) -> BitBoard {
        BitBoard::from_u64(self.board | rhs.board)
    }
}

impl ops::BitOrAssign for BitBoard {
    fn bitor_assign(&mut self, rhs: BitBoard) {
        self.board |= rhs.board
    }
}

impl ops::BitAnd for BitBoard {
    type Output = BitBoard;
    fn bitand(self, rhs: BitBoard) -> BitBoard {
        BitBoard::from_u64(self.board & rhs.board)
    }
}

impl ops::BitAndAssign for BitBoard {
    fn bitand_assign(&mut self, rhs: BitBoard) {
        self.board &= rhs.board
    }
}

impl ops::Not for BitBoard {
    type Output = BitBoard;
    fn not(self) -> BitBoard {
        BitBoard::from_u64(!self.board)
    }
}

impl BitBoard {
    pub const fn empty() -> Self {
        BitBoard { board: 0 }
    }
    pub const fn from_u64(n: u64) -> Self {
        BitBoard { board: n }
    }

    /// Returns a board with the diagonal neighbours squares (up to 4) set
    pub fn diagonal_neighbours(square: Square) -> BitBoard {
        DIAGONAL_NEIGHBOURS[square.0 as usize]
    }

    pub fn orthogonal_neighbours(square: Square) -> BitBoard {
        ORTHOGONAL_NEIGHBOURS[square.0 as usize]
    }

    pub const fn get(&self, square: Square) -> bool {
        self.board & (1<<square.0) != 0
    }
    // Sets the square to true
    pub const fn set(self, square: Square) -> Self {
        BitBoard::from_u64(self.board | 1<<square.0)
    }
    #[allow(dead_code)]
    // Sets the square to false
    pub const fn clear(self, square: Square) -> Self {
        BitBoard::from_u64(self.board & !(1<<square.0))
    }

    pub const fn is_empty(&self) -> bool {
        self.board == 0
    }

    pub const fn popcount(&self) -> u32 {
        self.board.count_ones()
    }

    /// Get a single rank
    /// Ranks are numbered from 0 (black's back rank) to 7 (white's back rank)
    pub const fn rank(self, rank: u8) -> u8 {
        (self.board >> (rank * 8)) as u8
    }
    #[allow(dead_code)]
    pub const fn file(self, file: u8) -> u8 {
        self.rotate().rank(file)
    }
    pub const fn rotate(&self) -> Self {
        self.flip_vertical().flip_diagonal()
    }
    pub const fn rotate_270(&self) -> Self {
        self.flip_diagonal().flip_vertical()
    }
    pub const fn rotate_45(&self) -> Self {
        let k1 = 0xAAAAAAAAAAAAAAAA;
        let k2 = 0xCCCCCCCCCCCCCCCC;
        let k4 = 0xF0F0F0F0F0F0F0F0;
        let mut x = self.board;
        x ^= k1 & (x ^ x.rotate_right(8));
        x ^= k2 & (x ^ x.rotate_right(16));
        x ^= k4 & (x ^ x.rotate_right(32));
        Self::from_u64(x)
    }
    pub const fn rotate_315(&self) -> Self {
        let k1 = 0x5555555555555555;
        let k2 = 0x3333333333333333;
        let k4 = 0x0f0f0f0f0f0f0f0f;
        let mut x = self.board;
        x ^= k1 & (x ^ x.rotate_right(8));
        x ^= k2 & (x ^ x.rotate_right(16));
        x ^= k4 & (x ^ x.rotate_right(32));
        Self::from_u64(x)
    }
    #[allow(dead_code)]
    pub const fn flip_horizontal(&self) -> Self {
        let k1 = 0x5555555555555555;
        let k2 = 0x3333333333333333;
        let k4 = 0x0f0f0f0f0f0f0f0f;
        let mut x = self.board;
        x = ((x >> 1) & k1) +  2*(x & k1);
        x = ((x >> 2) & k2) +  4*(x & k2);
        x = ((x >> 4) & k4) + 16*(x & k4);
        BitBoard::from_u64(x)
    }
    pub const fn flip_vertical(&self) -> Self {
        BitBoard::from_u64(self.board.swap_bytes())
    }

    pub const fn flip_diagonal(&self) -> Self {
        let k1 = 0x5500550055005500;
        let k2 = 0x3333000033330000;
        let k4 = 0x0f0f0f0f00000000;
        let mut x = self.board;
        let mut t = k4 & (x ^ (x << 28));
        x ^=       t ^ (t >> 28) ;
        t  = k2 & (x ^ (x << 14));
        x ^=       t ^ (t >> 14) ;
        t  = k1 & (x ^ (x <<  7));
        x ^=       t ^ (t >>  7) ;
        BitBoard::from_u64(x)
    }
    /// Diagonal_id is rank + file
    /// Assumes board is already rotated
    pub fn diagonal(&self, diagonal_id: u8) -> u8 {
        let len = if diagonal_id >= 8 { 15 - diagonal_id } else { diagonal_id + 1 };
        let n = diagonal_id as i8 - 7;
        //let offset = ((7 * n + 8)) % 64;
        let offset = if n <= 0 { n * (-8)} else { 8 * (8 - n) + n };
        ((self.board >> offset) & !(!0 << len)) as u8
    }

    /// Diagonal_id is rank - file
    /// Assumes board is already rotated
    pub fn antidiagonal(&self, diagonal_id: i8) -> u8 {
        let len = 8 - diagonal_id.abs(); // Between 1 and 8
        let n = diagonal_id as i16;
        let offset = if n <= 0 { n * (-8) - n} else { 8 * (8 - n) };
        ((self.board >> offset) & !(!0 << len as u64)) as u8
    }

    pub fn first_piece(&self) -> Option<Square> {
        let square = self.board.trailing_zeros();
        if square == 64 {
            None
        }
        else {
            Some(Square(square as u8))
        }
    }
}

impl fmt::Debug for BitBoard {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for n in 0..8 {
            writeln!(f, "{:08b}", (self.board >> (n * 8)) as u8).unwrap();
        }
        Ok(())
    }
}

impl IntoIterator for BitBoard {
    type Item = Square;
    type IntoIter = BitBoardIterator;

    fn into_iter(self) -> Self::IntoIter {
        BitBoardIterator::new(self)
    }
}

impl iter::FromIterator<Square> for BitBoard {
    fn from_iter<T: IntoIterator<Item=Square>>(iter: T) -> Self {
        let mut board = Self::empty();
        for square in iter {
            board = board.set(square);
        }
        board
    }
}

pub struct BitBoardIterator {
    board: BitBoard,
}

impl BitBoardIterator {
    const fn new(board: BitBoard) -> Self {
        Self { board }
    }
}

impl Iterator for BitBoardIterator {
    type Item = Square;
    fn next(&mut self) -> Option<Self::Item> {
        if let Some(next) = self.board.first_piece() {
            self.board = self.board.clear(next);
            Some(next)
        }
        else {
            None
        }
    }
}

lazy_static!(
    static ref DIAGONAL_NEIGHBOURS : [BitBoard; 64] = {
        let mut table : [BitBoard; 64] = [BitBoard::empty(); 64];

        for i in 0..64 {
            let mut board = BitBoard::empty();
            let (file, rank) = Square(i).file_rank();

            for &x in &[u8::overflowing_sub(file, 1).0, file + 1] {
                for &y in &[u8::overflowing_sub(rank, 1).0, rank + 1] {
                    if x < 8 && y < 8 {
                        board = board.set(Square::from_ints(x, y));
                    }
                }
            }
            table[i as usize] = board;
        }
        table
    };

    static ref RANK_NEIGHBOURS : [BitBoard; 64] = {
        let mut table : [BitBoard; 64] = [BitBoard::empty(); 64];
        for i in 0..64 {
            let (file, rank) = Square(i).file_rank();
            let mut board = BitBoard::empty();
            if file > 0 {
                board = board.set(Square::from_ints(file - 1, rank));
            }
            if file < 7 {
                board = board.set(Square::from_ints(file + 1, rank));
            }
            table[i as usize] = board;
        }
        table
    };

    static ref FILE_NEIGHBOURS : [BitBoard; 64] = {
        let mut table : [BitBoard; 64] = [BitBoard::empty(); 64];

        for i in 0..64 {
            let (file, rank) = Square(i).file_rank();
            let mut board = BitBoard::empty();
            if rank > 0 {
                board = board.set(Square::from_ints(file, rank - 1));
            }
            if rank < 7 {
                board = board.set(Square::from_ints(file, rank + 1));
            }
            table[i as usize] = board;
        }
        table
    };

    static ref ORTHOGONAL_NEIGHBOURS : [BitBoard; 64] = {
        let mut table : [BitBoard; 64] = [BitBoard::empty(); 64];

        for i in 0..64 {
            table[i] = RANK_NEIGHBOURS[i] | FILE_NEIGHBOURS[i];
        }
        table
    };
);<commit_msg>Implement FusedIterator for BitBoardIterator<commit_after>use std::iter;
use std::{fmt, ops};
use board::std_board::{Square};
use std::iter::FusedIterator;

#[derive(PartialEq, Eq, Clone, Copy, Hash)]
pub struct BitBoard {
    pub board: u64,
}

impl ops::BitOr for BitBoard {
    type Output = BitBoard;
    fn bitor(self, rhs: BitBoard) -> BitBoard {
        BitBoard::from_u64(self.board | rhs.board)
    }
}

impl ops::BitOrAssign for BitBoard {
    fn bitor_assign(&mut self, rhs: BitBoard) {
        self.board |= rhs.board
    }
}

impl ops::BitAnd for BitBoard {
    type Output = BitBoard;
    fn bitand(self, rhs: BitBoard) -> BitBoard {
        BitBoard::from_u64(self.board & rhs.board)
    }
}

impl ops::BitAndAssign for BitBoard {
    fn bitand_assign(&mut self, rhs: BitBoard) {
        self.board &= rhs.board
    }
}

impl ops::Not for BitBoard {
    type Output = BitBoard;
    fn not(self) -> BitBoard {
        BitBoard::from_u64(!self.board)
    }
}

impl BitBoard {
    pub const fn empty() -> Self {
        BitBoard { board: 0 }
    }
    pub const fn from_u64(n: u64) -> Self {
        BitBoard { board: n }
    }

    /// Returns a board with the diagonal neighbours squares (up to 4) set
    pub fn diagonal_neighbours(square: Square) -> BitBoard {
        DIAGONAL_NEIGHBOURS[square.0 as usize]
    }

    pub fn orthogonal_neighbours(square: Square) -> BitBoard {
        ORTHOGONAL_NEIGHBOURS[square.0 as usize]
    }

    pub const fn get(&self, square: Square) -> bool {
        self.board & (1<<square.0) != 0
    }
    // Sets the square to true
    pub const fn set(self, square: Square) -> Self {
        BitBoard::from_u64(self.board | 1<<square.0)
    }
    #[allow(dead_code)]
    // Sets the square to false
    pub const fn clear(self, square: Square) -> Self {
        BitBoard::from_u64(self.board & !(1<<square.0))
    }

    pub const fn is_empty(&self) -> bool {
        self.board == 0
    }

    pub const fn popcount(&self) -> u32 {
        self.board.count_ones()
    }

    /// Get a single rank
    /// Ranks are numbered from 0 (black's back rank) to 7 (white's back rank)
    pub const fn rank(self, rank: u8) -> u8 {
        (self.board >> (rank * 8)) as u8
    }
    #[allow(dead_code)]
    pub const fn file(self, file: u8) -> u8 {
        self.rotate().rank(file)
    }
    pub const fn rotate(&self) -> Self {
        self.flip_vertical().flip_diagonal()
    }
    pub const fn rotate_270(&self) -> Self {
        self.flip_diagonal().flip_vertical()
    }
    pub const fn rotate_45(&self) -> Self {
        let k1 = 0xAAAAAAAAAAAAAAAA;
        let k2 = 0xCCCCCCCCCCCCCCCC;
        let k4 = 0xF0F0F0F0F0F0F0F0;
        let mut x = self.board;
        x ^= k1 & (x ^ x.rotate_right(8));
        x ^= k2 & (x ^ x.rotate_right(16));
        x ^= k4 & (x ^ x.rotate_right(32));
        Self::from_u64(x)
    }
    pub const fn rotate_315(&self) -> Self {
        let k1 = 0x5555555555555555;
        let k2 = 0x3333333333333333;
        let k4 = 0x0f0f0f0f0f0f0f0f;
        let mut x = self.board;
        x ^= k1 & (x ^ x.rotate_right(8));
        x ^= k2 & (x ^ x.rotate_right(16));
        x ^= k4 & (x ^ x.rotate_right(32));
        Self::from_u64(x)
    }
    #[allow(dead_code)]
    pub const fn flip_horizontal(&self) -> Self {
        let k1 = 0x5555555555555555;
        let k2 = 0x3333333333333333;
        let k4 = 0x0f0f0f0f0f0f0f0f;
        let mut x = self.board;
        x = ((x >> 1) & k1) +  2*(x & k1);
        x = ((x >> 2) & k2) +  4*(x & k2);
        x = ((x >> 4) & k4) + 16*(x & k4);
        BitBoard::from_u64(x)
    }
    pub const fn flip_vertical(&self) -> Self {
        BitBoard::from_u64(self.board.swap_bytes())
    }

    pub const fn flip_diagonal(&self) -> Self {
        let k1 = 0x5500550055005500;
        let k2 = 0x3333000033330000;
        let k4 = 0x0f0f0f0f00000000;
        let mut x = self.board;
        let mut t = k4 & (x ^ (x << 28));
        x ^=       t ^ (t >> 28) ;
        t  = k2 & (x ^ (x << 14));
        x ^=       t ^ (t >> 14) ;
        t  = k1 & (x ^ (x <<  7));
        x ^=       t ^ (t >>  7) ;
        BitBoard::from_u64(x)
    }
    /// Diagonal_id is rank + file
    /// Assumes board is already rotated
    pub fn diagonal(&self, diagonal_id: u8) -> u8 {
        let len = if diagonal_id >= 8 { 15 - diagonal_id } else { diagonal_id + 1 };
        let n = diagonal_id as i8 - 7;
        //let offset = ((7 * n + 8)) % 64;
        let offset = if n <= 0 { n * (-8)} else { 8 * (8 - n) + n };
        ((self.board >> offset) & !(!0 << len)) as u8
    }

    /// Diagonal_id is rank - file
    /// Assumes board is already rotated
    pub fn antidiagonal(&self, diagonal_id: i8) -> u8 {
        let len = 8 - diagonal_id.abs(); // Between 1 and 8
        let n = diagonal_id as i16;
        let offset = if n <= 0 { n * (-8) - n} else { 8 * (8 - n) };
        ((self.board >> offset) & !(!0 << len as u64)) as u8
    }

    pub fn first_piece(&self) -> Option<Square> {
        let square = self.board.trailing_zeros();
        if square == 64 {
            None
        }
        else {
            Some(Square(square as u8))
        }
    }
}

impl fmt::Debug for BitBoard {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for n in 0..8 {
            writeln!(f, "{:08b}", (self.board >> (n * 8)) as u8).unwrap();
        }
        Ok(())
    }
}

impl IntoIterator for BitBoard {
    type Item = Square;
    type IntoIter = BitBoardIterator;

    fn into_iter(self) -> Self::IntoIter {
        BitBoardIterator::new(self)
    }
}

impl iter::FromIterator<Square> for BitBoard {
    fn from_iter<T: IntoIterator<Item=Square>>(iter: T) -> Self {
        let mut board = Self::empty();
        for square in iter {
            board = board.set(square);
        }
        board
    }
}

pub struct BitBoardIterator {
    board: BitBoard,
}

impl BitBoardIterator {
    const fn new(board: BitBoard) -> Self {
        Self { board }
    }
}

impl Iterator for BitBoardIterator {
    type Item = Square;
    fn next(&mut self) -> Option<Self::Item> {
        if let Some(next) = self.board.first_piece() {
            self.board = self.board.clear(next);
            Some(next)
        }
        else {
            None
        }
    }
}

impl FusedIterator for BitBoardIterator {}

lazy_static!(
    static ref DIAGONAL_NEIGHBOURS : [BitBoard; 64] = {
        let mut table : [BitBoard; 64] = [BitBoard::empty(); 64];

        for i in 0..64 {
            let mut board = BitBoard::empty();
            let (file, rank) = Square(i).file_rank();

            for &x in &[u8::overflowing_sub(file, 1).0, file + 1] {
                for &y in &[u8::overflowing_sub(rank, 1).0, rank + 1] {
                    if x < 8 && y < 8 {
                        board = board.set(Square::from_ints(x, y));
                    }
                }
            }
            table[i as usize] = board;
        }
        table
    };

    static ref RANK_NEIGHBOURS : [BitBoard; 64] = {
        let mut table : [BitBoard; 64] = [BitBoard::empty(); 64];
        for i in 0..64 {
            let (file, rank) = Square(i).file_rank();
            let mut board = BitBoard::empty();
            if file > 0 {
                board = board.set(Square::from_ints(file - 1, rank));
            }
            if file < 7 {
                board = board.set(Square::from_ints(file + 1, rank));
            }
            table[i as usize] = board;
        }
        table
    };

    static ref FILE_NEIGHBOURS : [BitBoard; 64] = {
        let mut table : [BitBoard; 64] = [BitBoard::empty(); 64];

        for i in 0..64 {
            let (file, rank) = Square(i).file_rank();
            let mut board = BitBoard::empty();
            if rank > 0 {
                board = board.set(Square::from_ints(file, rank - 1));
            }
            if rank < 7 {
                board = board.set(Square::from_ints(file, rank + 1));
            }
            table[i as usize] = board;
        }
        table
    };

    static ref ORTHOGONAL_NEIGHBOURS : [BitBoard; 64] = {
        let mut table : [BitBoard; 64] = [BitBoard::empty(); 64];

        for i in 0..64 {
            table[i] = RANK_NEIGHBOURS[i] | FILE_NEIGHBOURS[i];
        }
        table
    };
);<|endoftext|>


<commit_before>//! Collective communication
//!
//! Developing...
//!
//! # Unfinished features
//!
//! - **5.5**: Varying counts gather operation, `MPI_Gatherv()`
//! - **5.6**: Scatter, `MPI_Scatterv()`
//! - **5.7**: Gather-to-all, `MPI_Allgatherv()`
//! - **5.8**: All-to-all, `MPI_Alltoallv()`, `MPI_Alltoallw()`
//! - **5.9**: Global reduction operations, `MPI_Reduce()`, `MPI_Op_create()`, `MPI_Op_free()`,
//! `MPI_Allreduce()`, `MPI_Reduce_local()`, `MPI_Op_commutative()`
//! - **5.10**: Reduce-scatter, `MPI_Reduce_scatter_block()`, `MPI_Reduce_scatter()`
//! - **5.11**: Scan, `MPI_Scan()`, `MPI_Exscan()`
//! - **5.12**: Nonblocking collective operations, `MPI_Ibcast()`,
//! `MPI_Igather()`, `MPI_Igatherv()`, `MPI_Iscatter()`, `MPI_Iscatterv()`, `MPI_Iallgather()`,
//! `MPI_Iallgatherv()`, `MPI_Ialltoall()`, `MPI_Ialltoallv()`, `MPI_Ialltoallw()`,
//! `MPI_Ireduce()`, `MPI_Iallreduce()`, `MPI_Ireduce_scatter_block()`, `MPI_Ireduce_scatter()`,
//! `MPI_Iscan()`, `MPI_Iexscan()`

use std::{mem, ptr};

use ffi;
use ffi::{MPI_Request};
use topology::{Rank, Identifier};
use topology::traits::*;
use datatype::traits::*;
use point_to_point::{RawRequest};

pub mod traits;

/// Barrier synchronization among all processes in a `Communicator`
///
/// Calling processes (or threads within the calling processes) will enter the barrier and block
/// execution until all processes in the `Communicator` `&self` have entered the barrier.
///
/// # Standard section(s)
///
/// 5.3
pub trait Barrier {
    /// Partake in a barrier synchronization across all processes in the `Communicator` `&self`.
    ///
    /// # Examples
    ///
    /// See `examples/barrier.rs`
    fn barrier(&self);
}

impl<C: Communicator> Barrier for C {
    fn barrier(&self) {
        unsafe { ffi::MPI_Barrier(self.communicator().raw()); }
    }
}

/// Something that can take the role of 'root' in a collective operation.
///
/// Many collective operations define a 'root' process that takes a special role in the
/// communication. These collective operations are implemented as traits that have blanket
/// implementations for every type that implements the `Root` trait.
pub trait Root: Communicator {
    /// Rank of the root process
    fn root_rank(&self) -> Rank;
}

impl<'a, C: 'a + RawCommunicator> Root for Identifier<'a, C> {
    fn root_rank(&self) -> Rank {
        self.rank()
    }
}

/// Broadcast of the contents of a buffer
///
/// After the call completes, the `Buffer` on all processes in the `Communicator` of the `Root`
/// `&self` will contain what it contains on the `Root`.
///
/// # Standard section(s)
///
/// 5.4
pub trait BroadcastInto {
    /// Broadcast the contents of `buffer` from the `Root` to the `buffer`s on all other processes.
    ///
    /// # Examples
    ///
    /// See `examples/broadcast.rs`
    fn broadcast_into<Buf: BufferMut + ?Sized>(&self, buffer: &mut Buf);
}

impl<T: Root> BroadcastInto for T {
    fn broadcast_into<Buf: BufferMut + ?Sized>(&self, buffer: &mut Buf) {
        unsafe {
            ffi::MPI_Bcast(buffer.pointer_mut(), buffer.count(), buffer.datatype().raw(),
                self.root_rank(), self.communicator().raw());
        }
    }
}

// TODO: Introduce "partitioned buffer" for varying count gather/scatter/alltoall?

/// Gather contents of buffers on `Root`.
///
/// After the call completes, the contents of the `Buffer`s on all ranks will be
/// concatenated into the `Buffer` on `Root`.
///
/// # Standard section(s)
///
/// 5.5
pub trait GatherInto {
    /// Gather the contents of all `sendbuf`s into `recvbuf` on `Root` `&self`.
    ///
    /// # Examples
    ///
    /// See `examples/gather.rs`
    fn gather_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: &S, recvbuf: Option<&mut R>);
}

impl<T: Root> GatherInto for T {
    fn gather_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: &S, recvbuf: Option<&mut R>) {
        unsafe {
            let (recvptr, recvcount, recvtype) = recvbuf.map_or(
                (ptr::null_mut(), 0, u8::equivalent_datatype().raw()),
                |x| (x.pointer_mut(), x.count() / self.communicator().size(), x.datatype().raw()));

            ffi::MPI_Gather(sendbuf.pointer(), sendbuf.count(), sendbuf.datatype().raw(),
                recvptr, recvcount, recvtype, self.root_rank(), self.communicator().raw());
        }
    }
}

/// Gather contents of buffers on all participating processes.
///
/// After the call completes, the contents of the send `Buffer`s on all processes will be
/// concatenated into the receive `Buffer`s on all ranks.
///
/// # Standard section(s)
///
/// 5.7
pub trait AllGatherInto {
    /// Gather the contents of all `sendbuf`s into all `rcevbuf`s on all processes in the
    /// communicator.
    ///
    /// # Examples
    ///
    /// See `examples/all_gather.rs`
    fn all_gather_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: &S, recvbuf: &mut R);
}

impl<C: Communicator> AllGatherInto for C {
    fn all_gather_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: &S, recvbuf: &mut R) {
        unsafe {
            ffi::MPI_Allgather(sendbuf.pointer(), sendbuf.count(), sendbuf.datatype().raw(),
                recvbuf.pointer_mut(), recvbuf.count() / self.communicator().size(),
                recvbuf.datatype().raw(), self.communicator().raw());
        }
    }
}

/// Scatter contents of a buffer on the root process to all processes.
///
/// After the call completes each participating process will have received a part of the send
/// `Buffer` on the root process.
///
/// # Standard section(s)
///
/// 5.6
pub trait ScatterInto {
    /// Scatter the contents of `sendbuf` to the participating processes.
    ///
    /// # Examples
    ///
    /// See `examples/scatter.rs`
    fn scatter_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: Option<&S>, recvbuf: &mut R);
}

impl<T: Root> ScatterInto for T {
    fn scatter_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: Option<&S>, recvbuf: &mut R) {
        unsafe {
            let (sendptr, sendcount, sendtype) = sendbuf.map_or(
                (ptr::null(), 0, u8::equivalent_datatype().raw()),
                |x| (x.pointer(), x.count() / self.communicator().size(), x.datatype().raw()));

            ffi::MPI_Scatter(sendptr, sendcount, sendtype,
                recvbuf.pointer_mut(), recvbuf.count(), recvbuf.datatype().raw(),
                self.root_rank(), self.communicator().raw());
        }
    }
}

/// Distribute the send `Buffer`s from all processes to the receive `Buffer`s on all processes.
///
/// # Standard section(s)
///
/// 5.8
pub trait AllToAllInto {
    fn all_to_all_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: &S, recvbuf: &mut R);
}

impl<C: Communicator> AllToAllInto for C {
    /// Distribute the `sendbuf` from all ranks to the `recvbuf` on all ranks.
    ///
    /// # Examples
    ///
    /// See `examples/all_to_all.rs`
    fn all_to_all_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: &S, recvbuf: &mut R) {
        let c_size = self.communicator().size();
        unsafe {
            ffi::MPI_Alltoall(sendbuf.pointer(), sendbuf.count() / c_size, sendbuf.datatype().raw(),
                recvbuf.pointer_mut(), recvbuf.count() / c_size, recvbuf.datatype().raw(),
                self.communicator().raw());
        }
    }
}

/// A request object for an immediate (non-blocking) barrier operation
///
/// # Examples
///
/// See `examples/immediate_barrier.rs`
///
/// # Standard section(s)
///
/// 3.7.1
#[must_use]
pub struct BarrierRequest(MPI_Request);

impl RawRequest for BarrierRequest {
    unsafe fn raw(&self) -> MPI_Request { self.0 }
    unsafe fn ptr_mut(&mut self) -> *mut MPI_Request { &mut (self.0) }
}

/// Non-blocking barrier synchronization among all processes in a `Communicator`
///
/// Calling processes (or threads within the calling processes) enter the barrier. Completion
/// methods on the associated request object will block until all processes have entered.
///
/// # Standard section(s)
///
/// 5.12.1
pub trait ImmediateBarrier {
    /// Partake in a barrier synchronization across all processes in the `Communicator` `&self`.
    ///
    /// # Examples
    ///
    /// See `examples/immediate_barrier.rs`
    fn immediate_barrier(&self) -> BarrierRequest;
}

impl<C: Communicator> ImmediateBarrier for C {
    fn immediate_barrier(&self) -> BarrierRequest {
        let mut request = unsafe { mem::uninitialized() };
        unsafe { ffi::MPI_Ibarrier(self.communicator().raw(), &mut request as *mut MPI_Request); }
        BarrierRequest(request)
    }
}
<commit_msg>Add Drop to BarrierRequest.<commit_after>//! Collective communication
//!
//! Developing...
//!
//! # Unfinished features
//!
//! - **5.5**: Varying counts gather operation, `MPI_Gatherv()`
//! - **5.6**: Scatter, `MPI_Scatterv()`
//! - **5.7**: Gather-to-all, `MPI_Allgatherv()`
//! - **5.8**: All-to-all, `MPI_Alltoallv()`, `MPI_Alltoallw()`
//! - **5.9**: Global reduction operations, `MPI_Reduce()`, `MPI_Op_create()`, `MPI_Op_free()`,
//! `MPI_Allreduce()`, `MPI_Reduce_local()`, `MPI_Op_commutative()`
//! - **5.10**: Reduce-scatter, `MPI_Reduce_scatter_block()`, `MPI_Reduce_scatter()`
//! - **5.11**: Scan, `MPI_Scan()`, `MPI_Exscan()`
//! - **5.12**: Nonblocking collective operations, `MPI_Ibcast()`,
//! `MPI_Igather()`, `MPI_Igatherv()`, `MPI_Iscatter()`, `MPI_Iscatterv()`, `MPI_Iallgather()`,
//! `MPI_Iallgatherv()`, `MPI_Ialltoall()`, `MPI_Ialltoallv()`, `MPI_Ialltoallw()`,
//! `MPI_Ireduce()`, `MPI_Iallreduce()`, `MPI_Ireduce_scatter_block()`, `MPI_Ireduce_scatter()`,
//! `MPI_Iscan()`, `MPI_Iexscan()`

use std::{mem, ptr};

use ffi;
use ffi::{MPI_Request};
use topology::{Rank, Identifier};
use topology::traits::*;
use datatype::traits::*;
use point_to_point::{RawRequest};

pub mod traits;

/// Barrier synchronization among all processes in a `Communicator`
///
/// Calling processes (or threads within the calling processes) will enter the barrier and block
/// execution until all processes in the `Communicator` `&self` have entered the barrier.
///
/// # Standard section(s)
///
/// 5.3
pub trait Barrier {
    /// Partake in a barrier synchronization across all processes in the `Communicator` `&self`.
    ///
    /// # Examples
    ///
    /// See `examples/barrier.rs`
    fn barrier(&self);
}

impl<C: Communicator> Barrier for C {
    fn barrier(&self) {
        unsafe { ffi::MPI_Barrier(self.communicator().raw()); }
    }
}

/// Something that can take the role of 'root' in a collective operation.
///
/// Many collective operations define a 'root' process that takes a special role in the
/// communication. These collective operations are implemented as traits that have blanket
/// implementations for every type that implements the `Root` trait.
pub trait Root: Communicator {
    /// Rank of the root process
    fn root_rank(&self) -> Rank;
}

impl<'a, C: 'a + RawCommunicator> Root for Identifier<'a, C> {
    fn root_rank(&self) -> Rank {
        self.rank()
    }
}

/// Broadcast of the contents of a buffer
///
/// After the call completes, the `Buffer` on all processes in the `Communicator` of the `Root`
/// `&self` will contain what it contains on the `Root`.
///
/// # Standard section(s)
///
/// 5.4
pub trait BroadcastInto {
    /// Broadcast the contents of `buffer` from the `Root` to the `buffer`s on all other processes.
    ///
    /// # Examples
    ///
    /// See `examples/broadcast.rs`
    fn broadcast_into<Buf: BufferMut + ?Sized>(&self, buffer: &mut Buf);
}

impl<T: Root> BroadcastInto for T {
    fn broadcast_into<Buf: BufferMut + ?Sized>(&self, buffer: &mut Buf) {
        unsafe {
            ffi::MPI_Bcast(buffer.pointer_mut(), buffer.count(), buffer.datatype().raw(),
                self.root_rank(), self.communicator().raw());
        }
    }
}

// TODO: Introduce "partitioned buffer" for varying count gather/scatter/alltoall?

/// Gather contents of buffers on `Root`.
///
/// After the call completes, the contents of the `Buffer`s on all ranks will be
/// concatenated into the `Buffer` on `Root`.
///
/// # Standard section(s)
///
/// 5.5
pub trait GatherInto {
    /// Gather the contents of all `sendbuf`s into `recvbuf` on `Root` `&self`.
    ///
    /// # Examples
    ///
    /// See `examples/gather.rs`
    fn gather_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: &S, recvbuf: Option<&mut R>);
}

impl<T: Root> GatherInto for T {
    fn gather_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: &S, recvbuf: Option<&mut R>) {
        unsafe {
            let (recvptr, recvcount, recvtype) = recvbuf.map_or(
                (ptr::null_mut(), 0, u8::equivalent_datatype().raw()),
                |x| (x.pointer_mut(), x.count() / self.communicator().size(), x.datatype().raw()));

            ffi::MPI_Gather(sendbuf.pointer(), sendbuf.count(), sendbuf.datatype().raw(),
                recvptr, recvcount, recvtype, self.root_rank(), self.communicator().raw());
        }
    }
}

/// Gather contents of buffers on all participating processes.
///
/// After the call completes, the contents of the send `Buffer`s on all processes will be
/// concatenated into the receive `Buffer`s on all ranks.
///
/// # Standard section(s)
///
/// 5.7
pub trait AllGatherInto {
    /// Gather the contents of all `sendbuf`s into all `rcevbuf`s on all processes in the
    /// communicator.
    ///
    /// # Examples
    ///
    /// See `examples/all_gather.rs`
    fn all_gather_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: &S, recvbuf: &mut R);
}

impl<C: Communicator> AllGatherInto for C {
    fn all_gather_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: &S, recvbuf: &mut R) {
        unsafe {
            ffi::MPI_Allgather(sendbuf.pointer(), sendbuf.count(), sendbuf.datatype().raw(),
                recvbuf.pointer_mut(), recvbuf.count() / self.communicator().size(),
                recvbuf.datatype().raw(), self.communicator().raw());
        }
    }
}

/// Scatter contents of a buffer on the root process to all processes.
///
/// After the call completes each participating process will have received a part of the send
/// `Buffer` on the root process.
///
/// # Standard section(s)
///
/// 5.6
pub trait ScatterInto {
    /// Scatter the contents of `sendbuf` to the participating processes.
    ///
    /// # Examples
    ///
    /// See `examples/scatter.rs`
    fn scatter_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: Option<&S>, recvbuf: &mut R);
}

impl<T: Root> ScatterInto for T {
    fn scatter_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: Option<&S>, recvbuf: &mut R) {
        unsafe {
            let (sendptr, sendcount, sendtype) = sendbuf.map_or(
                (ptr::null(), 0, u8::equivalent_datatype().raw()),
                |x| (x.pointer(), x.count() / self.communicator().size(), x.datatype().raw()));

            ffi::MPI_Scatter(sendptr, sendcount, sendtype,
                recvbuf.pointer_mut(), recvbuf.count(), recvbuf.datatype().raw(),
                self.root_rank(), self.communicator().raw());
        }
    }
}

/// Distribute the send `Buffer`s from all processes to the receive `Buffer`s on all processes.
///
/// # Standard section(s)
///
/// 5.8
pub trait AllToAllInto {
    fn all_to_all_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: &S, recvbuf: &mut R);
}

impl<C: Communicator> AllToAllInto for C {
    /// Distribute the `sendbuf` from all ranks to the `recvbuf` on all ranks.
    ///
    /// # Examples
    ///
    /// See `examples/all_to_all.rs`
    fn all_to_all_into<S: Buffer + ?Sized, R: BufferMut + ?Sized>(&self, sendbuf: &S, recvbuf: &mut R) {
        let c_size = self.communicator().size();
        unsafe {
            ffi::MPI_Alltoall(sendbuf.pointer(), sendbuf.count() / c_size, sendbuf.datatype().raw(),
                recvbuf.pointer_mut(), recvbuf.count() / c_size, recvbuf.datatype().raw(),
                self.communicator().raw());
        }
    }
}

/// A request object for an immediate (non-blocking) barrier operation
///
/// # Examples
///
/// See `examples/immediate_barrier.rs`
///
/// # Standard section(s)
///
/// 3.7.1
#[must_use]
pub struct BarrierRequest(MPI_Request);

impl Drop for BarrierRequest {
    fn drop(&mut self) {
        unsafe {
            assert!(self.raw() == ffi::RSMPI_REQUEST_NULL,
                "asynchronous barrier request dropped without ascertaining completion.");
        }
    }
}

impl RawRequest for BarrierRequest {
    unsafe fn raw(&self) -> MPI_Request { self.0 }
    unsafe fn ptr_mut(&mut self) -> *mut MPI_Request { &mut (self.0) }
}

/// Non-blocking barrier synchronization among all processes in a `Communicator`
///
/// Calling processes (or threads within the calling processes) enter the barrier. Completion
/// methods on the associated request object will block until all processes have entered.
///
/// # Standard section(s)
///
/// 5.12.1
pub trait ImmediateBarrier {
    /// Partake in a barrier synchronization across all processes in the `Communicator` `&self`.
    ///
    /// # Examples
    ///
    /// See `examples/immediate_barrier.rs`
    fn immediate_barrier(&self) -> BarrierRequest;
}

impl<C: Communicator> ImmediateBarrier for C {
    fn immediate_barrier(&self) -> BarrierRequest {
        let mut request = unsafe { mem::uninitialized() };
        unsafe { ffi::MPI_Ibarrier(self.communicator().raw(), &mut request as *mut MPI_Request); }
        BarrierRequest(request)
    }
}
<|endoftext|>


<commit_before>
import std.map.hashmap;
import std.option;
import util.common.span;
import util.common.spanned;
import util.common.ty_mach;

type ident = str;

type name_ = rec(ident ident, vec[@ty] types);
type name = spanned[name_];
type path = vec[name];

type crate_num = int;
type def_num = int;
type def_id = tup(crate_num, def_num);

type ty_param = rec(ident ident, def_id id);

// Annotations added during successive passes.
tag ann {
    ann_none;
    ann_type(@middle.ty.t);
}

tag def {
    def_fn(def_id);
    def_obj(def_id);
    def_mod(def_id);
    def_const(def_id);
    def_arg(def_id);
    def_local(def_id);
    def_variant(def_id /* tag */, def_id /* variant */);
    def_ty(def_id);
    def_ty_arg(def_id);
    def_binding(def_id);
}

type crate = spanned[crate_];
type crate_ = rec(_mod module);

type use_node = spanned[use_node_];
type use_node_ = rec(ident name, vec[@meta_item] metadata);

type import_node = spanned[import_node_];
type import_node_ = rec(vec[ident] identifiers);

tag use_or_import {
    use_or_import_use(@use_node);
    use_or_import_import(@import_node);
}

type meta_item = spanned[meta_item_];
type meta_item_ = rec(ident name, str value);

type block = spanned[block_];
type block_ = rec(vec[@stmt] stmts,
                  option.t[@expr] expr,
                  hashmap[ident,uint] index);

type variant_def = tup(def_id /* tag */, def_id /* variant */);

type pat = spanned[pat_];
tag pat_ {
    pat_wild(ann);
    pat_bind(ident, def_id, ann);
    pat_tag(ident, vec[@pat], option.t[variant_def], ann);
}

tag mutability {
    mut;
    imm;
}

tag layer {
    layer_value;
    layer_state;
    layer_gc;
}

tag effect {
    eff_pure;
    eff_impure;
    eff_unsafe;
}

tag binop {
    add;
    sub;
    mul;
    div;
    rem;
    and;
    or;
    bitxor;
    bitand;
    bitor;
    lsl;
    lsr;
    asr;
    eq;
    lt;
    le;
    ne;
    ge;
    gt;
}

tag unop {
    box;
    deref;
    bitnot;
    not;
    neg;
}

tag mode {
    val;
    alias;
}

type stmt = spanned[stmt_];
tag stmt_ {
    stmt_decl(@decl);
    stmt_ret(option.t[@expr]);
    stmt_log(@expr);
    stmt_check_expr(@expr);
    stmt_expr(@expr);
}

type local = rec(option.t[@ty] ty,
                 bool infer,
                 ident ident,
                 option.t[@expr] init,
                 def_id id,
                 ann ann);

type decl = spanned[decl_];
tag decl_ {
    decl_local(@local);
    decl_item(@item);
}

type arm = rec(@pat pat, block block, hashmap[ident,def_id] index);

type elt = rec(mutability mut, @expr expr);
type field = rec(mutability mut, ident ident, @expr expr);

type expr = spanned[expr_];
tag expr_ {
    expr_vec(vec[@expr], ann);
    expr_tup(vec[elt], ann);
    expr_rec(vec[field], ann);
    expr_call(@expr, vec[@expr], ann);
    expr_bind(@expr, vec[option.t[@expr]], ann);
    expr_binary(binop, @expr, @expr, ann);
    expr_unary(unop, @expr, ann);
    expr_lit(@lit, ann);
    expr_cast(@expr, @ty, ann);
    expr_if(@expr, block, option.t[block], ann);
    expr_while(@expr, block, ann);
    expr_do_while(block, @expr, ann);
    expr_alt(@expr, vec[arm], ann);
    expr_block(block, ann);
    expr_assign(@expr /* TODO: @expr|is_lval */, @expr, ann);
    expr_assign_op(binop, @expr /* TODO: @expr|is_lval */, @expr, ann);
    expr_field(@expr, ident, ann);
    expr_index(@expr, @expr, ann);
    expr_name(name, option.t[def], ann);
}

type lit = spanned[lit_];
tag lit_ {
    lit_str(str);
    lit_char(char);
    lit_int(int);
    lit_uint(uint);
    lit_mach_int(ty_mach, int);
    lit_nil;
    lit_bool(bool);
}

// NB: If you change this, you'll probably want to change the corresponding
// type structure in middle/ty.rs as well.

type ty_field = rec(ident ident, @ty ty);
type ty_arg = rec(mode mode, @ty ty);
// TODO: effect
type ty_method = rec(ident ident, vec[ty_arg] inputs, @ty output);
type ty = spanned[ty_];
tag ty_ {
    ty_nil;
    ty_bool;
    ty_int;
    ty_uint;
    ty_machine(util.common.ty_mach);
    ty_char;
    ty_str;
    ty_box(@ty);
    ty_vec(@ty);
    ty_tup(vec[@ty]);
    ty_rec(vec[ty_field]);
    ty_fn(vec[ty_arg], @ty);        // TODO: effect
    ty_obj(vec[ty_method]);
    ty_path(path, option.t[def]);
    ty_mutable(@ty);
}

type arg = rec(mode mode, @ty ty, ident ident, def_id id);
type _fn = rec(effect effect,
               vec[arg] inputs,
               @ty output,
               block body);

type method_ = rec(ident ident, _fn meth, def_id id, ann ann);
type method = spanned[method_];

type obj_field = rec(@ty ty, ident ident, def_id id, ann ann);
type _obj = rec(vec[obj_field] fields,
                vec[@method] methods);

tag mod_index_entry {
    mie_item(uint);
    mie_tag_variant(uint /* tag item index */, uint /* variant index */);
}

type _mod = rec(vec[@item] items,
                hashmap[ident,mod_index_entry] index);

type variant_arg = rec(@ty ty, def_id id);
type variant = rec(str name, vec[variant_arg] args, def_id id, ann ann);

type item = spanned[item_];
tag item_ {
    item_const(ident, @ty, @expr, def_id, ann);
    item_fn(ident, _fn, vec[ty_param], def_id, ann);
    item_mod(ident, _mod, def_id);
    item_ty(ident, @ty, vec[ty_param], def_id, ann);
    item_tag(ident, vec[variant], vec[ty_param], def_id);
    item_obj(ident, _obj, vec[ty_param], def_id, ann);
}

//
// 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 ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<commit_msg>Add def id to ast for obj fields.<commit_after>
import std.map.hashmap;
import std.option;
import util.common.span;
import util.common.spanned;
import util.common.ty_mach;

type ident = str;

type name_ = rec(ident ident, vec[@ty] types);
type name = spanned[name_];
type path = vec[name];

type crate_num = int;
type def_num = int;
type def_id = tup(crate_num, def_num);

type ty_param = rec(ident ident, def_id id);

// Annotations added during successive passes.
tag ann {
    ann_none;
    ann_type(@middle.ty.t);
}

tag def {
    def_fn(def_id);
    def_obj(def_id);
    def_obj_field(def_id);
    def_mod(def_id);
    def_const(def_id);
    def_arg(def_id);
    def_local(def_id);
    def_variant(def_id /* tag */, def_id /* variant */);
    def_ty(def_id);
    def_ty_arg(def_id);
    def_binding(def_id);
}

type crate = spanned[crate_];
type crate_ = rec(_mod module);

type use_node = spanned[use_node_];
type use_node_ = rec(ident name, vec[@meta_item] metadata);

type import_node = spanned[import_node_];
type import_node_ = rec(vec[ident] identifiers);

tag use_or_import {
    use_or_import_use(@use_node);
    use_or_import_import(@import_node);
}

type meta_item = spanned[meta_item_];
type meta_item_ = rec(ident name, str value);

type block = spanned[block_];
type block_ = rec(vec[@stmt] stmts,
                  option.t[@expr] expr,
                  hashmap[ident,uint] index);

type variant_def = tup(def_id /* tag */, def_id /* variant */);

type pat = spanned[pat_];
tag pat_ {
    pat_wild(ann);
    pat_bind(ident, def_id, ann);
    pat_tag(ident, vec[@pat], option.t[variant_def], ann);
}

tag mutability {
    mut;
    imm;
}

tag layer {
    layer_value;
    layer_state;
    layer_gc;
}

tag effect {
    eff_pure;
    eff_impure;
    eff_unsafe;
}

tag binop {
    add;
    sub;
    mul;
    div;
    rem;
    and;
    or;
    bitxor;
    bitand;
    bitor;
    lsl;
    lsr;
    asr;
    eq;
    lt;
    le;
    ne;
    ge;
    gt;
}

tag unop {
    box;
    deref;
    bitnot;
    not;
    neg;
}

tag mode {
    val;
    alias;
}

type stmt = spanned[stmt_];
tag stmt_ {
    stmt_decl(@decl);
    stmt_ret(option.t[@expr]);
    stmt_log(@expr);
    stmt_check_expr(@expr);
    stmt_expr(@expr);
}

type local = rec(option.t[@ty] ty,
                 bool infer,
                 ident ident,
                 option.t[@expr] init,
                 def_id id,
                 ann ann);

type decl = spanned[decl_];
tag decl_ {
    decl_local(@local);
    decl_item(@item);
}

type arm = rec(@pat pat, block block, hashmap[ident,def_id] index);

type elt = rec(mutability mut, @expr expr);
type field = rec(mutability mut, ident ident, @expr expr);

type expr = spanned[expr_];
tag expr_ {
    expr_vec(vec[@expr], ann);
    expr_tup(vec[elt], ann);
    expr_rec(vec[field], ann);
    expr_call(@expr, vec[@expr], ann);
    expr_bind(@expr, vec[option.t[@expr]], ann);
    expr_binary(binop, @expr, @expr, ann);
    expr_unary(unop, @expr, ann);
    expr_lit(@lit, ann);
    expr_cast(@expr, @ty, ann);
    expr_if(@expr, block, option.t[block], ann);
    expr_while(@expr, block, ann);
    expr_do_while(block, @expr, ann);
    expr_alt(@expr, vec[arm], ann);
    expr_block(block, ann);
    expr_assign(@expr /* TODO: @expr|is_lval */, @expr, ann);
    expr_assign_op(binop, @expr /* TODO: @expr|is_lval */, @expr, ann);
    expr_field(@expr, ident, ann);
    expr_index(@expr, @expr, ann);
    expr_name(name, option.t[def], ann);
}

type lit = spanned[lit_];
tag lit_ {
    lit_str(str);
    lit_char(char);
    lit_int(int);
    lit_uint(uint);
    lit_mach_int(ty_mach, int);
    lit_nil;
    lit_bool(bool);
}

// NB: If you change this, you'll probably want to change the corresponding
// type structure in middle/ty.rs as well.

type ty_field = rec(ident ident, @ty ty);
type ty_arg = rec(mode mode, @ty ty);
// TODO: effect
type ty_method = rec(ident ident, vec[ty_arg] inputs, @ty output);
type ty = spanned[ty_];
tag ty_ {
    ty_nil;
    ty_bool;
    ty_int;
    ty_uint;
    ty_machine(util.common.ty_mach);
    ty_char;
    ty_str;
    ty_box(@ty);
    ty_vec(@ty);
    ty_tup(vec[@ty]);
    ty_rec(vec[ty_field]);
    ty_fn(vec[ty_arg], @ty);        // TODO: effect
    ty_obj(vec[ty_method]);
    ty_path(path, option.t[def]);
    ty_mutable(@ty);
}

type arg = rec(mode mode, @ty ty, ident ident, def_id id);
type _fn = rec(effect effect,
               vec[arg] inputs,
               @ty output,
               block body);

type method_ = rec(ident ident, _fn meth, def_id id, ann ann);
type method = spanned[method_];

type obj_field = rec(@ty ty, ident ident, def_id id, ann ann);
type _obj = rec(vec[obj_field] fields,
                vec[@method] methods);

tag mod_index_entry {
    mie_item(uint);
    mie_tag_variant(uint /* tag item index */, uint /* variant index */);
}

type _mod = rec(vec[@item] items,
                hashmap[ident,mod_index_entry] index);

type variant_arg = rec(@ty ty, def_id id);
type variant = rec(str name, vec[variant_arg] args, def_id id, ann ann);

type item = spanned[item_];
tag item_ {
    item_const(ident, @ty, @expr, def_id, ann);
    item_fn(ident, _fn, vec[ty_param], def_id, ann);
    item_mod(ident, _mod, def_id);
    item_ty(ident, @ty, vec[ty_param], def_id, ann);
    item_tag(ident, vec[variant], vec[ty_param], def_id);
    item_obj(ident, _obj, vec[ty_param], def_id, ann);
}

//
// 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 ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<|endoftext|>


<commit_before>#![feature(phase)]
#![crate_name = "cube"]

extern crate cgmath;
extern crate gfx;
#[phase(plugin)]
extern crate gfx_macros;
extern crate glfw;
extern crate native;
extern crate time;

use cgmath::angle;
use cgmath::array::FixedArray;
use cgmath::matrix::{Matrix, Matrix4};
use cgmath::point::Point3;
use cgmath::projection;
use cgmath::transform::{Transform, AffineMatrix3};
use cgmath::vector::Vector3;
use gfx::{Device, DeviceHelper};
use glfw::Context;

//----------------------------------------
// Cube associated data

#[vertex_format]
struct Vertex {
    #[as_float]
    a_Pos: [i8, ..3],
    #[as_float]
    a_TexCoord: [u8, ..2],
}

impl Vertex {
    fn new(pos: [i8, ..3], tc: [u8, ..2]) -> Vertex {
        Vertex {
            a_Pos: pos,
            a_TexCoord: tc,
        }
    }
}

#[shader_param(Program)]
struct Params {
    u_ModelViewProj: [[f32, ..4], ..4],
    t_Color: gfx::shade::TextureParam,
}

static VERTEX_SRC: gfx::ShaderSource = shaders! {
GLSL_120: b"
    #version 120
    attribute vec3 a_Pos;
    attribute vec2 a_TexCoord;
    varying vec2 v_TexCoord;
    uniform mat4 u_ModelViewProj;
    void main() {
        v_TexCoord = a_TexCoord;
        gl_Position = u_ModelViewProj * vec4(a_Pos, 1.0);
    }
"
GLSL_150: b"
    #version 150 core
    in vec3 a_Pos;
    in vec2 a_TexCoord;
    out vec2 v_TexCoord;
    uniform mat4 u_ModelViewProj;
    void main() {
        v_TexCoord = a_TexCoord;
        gl_Position = u_ModelViewProj * vec4(a_Pos, 1.0);
    }
"
};

static FRAGMENT_SRC: gfx::ShaderSource = shaders! {
GLSL_120: b"
    #version 120
    varying vec2 v_TexCoord;
    uniform sampler2D t_Color;
    void main() {
        vec4 tex = texture2D(t_Color, v_TexCoord);
        float blend = dot(v_TexCoord-vec2(0.5,0.5), v_TexCoord-vec2(0.5,0.5));
        gl_FragColor = mix(tex, vec4(0.0,0.0,0.0,0.0), blend*1.0);
    }
"
GLSL_150: b"
    #version 150 core
    in vec2 v_TexCoord;
    out vec4 o_Color;
    uniform sampler2D t_Color;
    void main() {
        vec4 tex = texture(t_Color, v_TexCoord);
        float blend = dot(v_TexCoord-vec2(0.5,0.5), v_TexCoord-vec2(0.5,0.5));
        o_Color = mix(tex, vec4(0.0,0.0,0.0,0.0), blend*1.0);
    }
"
};

//----------------------------------------

// We need to run on the main thread, so ensure we are using the `native` runtime. This is
// technically not needed, since this is the default, but it's not guaranteed.
#[start]
fn start(argc: int, argv: *const *const u8) -> int {
     native::start(argc, argv, main)
}

fn main() {
    let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    glfw.window_hint(glfw::ContextVersion(3, 2));
    glfw.window_hint(glfw::OpenglForwardCompat(true));
    glfw.window_hint(glfw::OpenglProfile(glfw::OpenGlCoreProfile));

    let (window, events) = glfw
        .create_window(640, 480, "Cube example", glfw::Windowed)
        .expect("Failed to create GLFW window.");

    window.make_current();
    glfw.set_error_callback(glfw::FAIL_ON_ERRORS);
    window.set_key_polling(true); // so we can quit when Esc is pressed
    let (w, h) = window.get_framebuffer_size();
    let frame = gfx::Frame::new(w as u16, h as u16);

    let mut device = gfx::GlDevice::new(|s| glfw.get_proc_address(s));
    let mut list = device.create_draw_list();

    let state = gfx::DrawState::new().depth(gfx::state::LessEqual, true);

    let vertex_data = vec![
        //top (0, 0, 1)
        Vertex::new([-1, -1,  1], [0, 0]),
        Vertex::new([ 1, -1,  1], [1, 0]),
        Vertex::new([ 1,  1,  1], [1, 1]),
        Vertex::new([-1,  1,  1], [0, 1]),
        //bottom (0, 0, -1)
        Vertex::new([ 1,  1, -1], [0, 0]),
        Vertex::new([-1,  1, -1], [1, 0]),
        Vertex::new([-1, -1, -1], [1, 1]),
        Vertex::new([ 1, -1, -1], [0, 1]),
        //right (1, 0, 0)
        Vertex::new([ 1, -1, -1], [0, 0]),
        Vertex::new([ 1,  1, -1], [1, 0]),
        Vertex::new([ 1,  1,  1], [1, 1]),
        Vertex::new([ 1, -1,  1], [0, 1]),
        //left (-1, 0, 0)
        Vertex::new([-1,  1,  1], [0, 0]),
        Vertex::new([-1, -1,  1], [1, 0]),
        Vertex::new([-1, -1, -1], [1, 1]),
        Vertex::new([-1,  1, -1], [0, 1]),
        //front (0, 1, 0)
        Vertex::new([-1,  1, -1], [0, 0]),
        Vertex::new([ 1,  1, -1], [1, 0]),
        Vertex::new([ 1,  1,  1], [1, 1]),
        Vertex::new([-1,  1,  1], [0, 1]),
        //back (0, -1, 0)
        Vertex::new([ 1, -1,  1], [0, 0]),
        Vertex::new([-1, -1,  1], [1, 0]),
        Vertex::new([-1, -1, -1], [1, 1]),
        Vertex::new([ 1, -1, -1], [0, 1]),
    ];

    let mesh = device.create_mesh(vertex_data);

    let slice = {
        let index_data = vec![
            0u8, 1, 2, 2, 3, 0,    //top
            4, 5, 6, 6, 7, 4,       //bottom
            8, 9, 10, 10, 11, 8,    //right
            12, 13, 14, 14, 16, 12, //left
            16, 17, 18, 18, 19, 16, //front
            20, 21, 22, 22, 23, 20, //back
        ];

        let buf = device.create_buffer_static(&index_data);
        gfx::IndexSlice8(buf, 0, 36)
    };

    let tinfo = gfx::tex::TextureInfo {
        width: 1,
        height: 1,
        depth: 1,
        mipmap_range: (0, 1),
        kind: gfx::tex::Texture2D,
        format: gfx::tex::RGBA8,
    };
    let img_info = tinfo.to_image_info();
    let texture = device.create_texture(tinfo).unwrap();
    device.update_texture(&texture, &img_info,
                          &vec![0x20u8, 0xA0u8, 0xC0u8, 0x00u8])
           .unwrap();

    let sampler = device.create_sampler(gfx::tex::SamplerInfo::new(
        gfx::tex::Bilinear, gfx::tex::Clamp));

    let mut prog = {
        let data = Params {
            u_ModelViewProj: Matrix4::identity().into_fixed(),
            t_Color: (texture, Some(sampler)),
        };
        device.link_program(data, VERTEX_SRC.clone(), FRAGMENT_SRC.clone())
               .unwrap()
    };

    let mut m_model = Matrix4::<f32>::identity();
    let m_viewproj = {
        let mv: AffineMatrix3<f32> = Transform::look_at(
            &Point3::new(1.5f32, -5.0, 3.0),
            &Point3::new(0f32, 0.0, 0.0),
            &Vector3::unit_z()
        );
        let aspect = w as f32 / h as f32;
        let mp = projection::perspective(angle::deg(45f32), aspect,
                                         1f32, 10f32);
        mp.mul_m(&mv.mat)
    };

    while !window.should_close() {
        glfw.poll_events();
        // quit when Esc is pressed.
        for (_, event) in glfw::flush_messages(&events) {
            match event {
                glfw::KeyEvent(glfw::KeyEscape, _, glfw::Press, _) =>
                    window.set_should_close(true),
                _ => {},
            }
        }
        // render
        list.reset();
        list.clear(
            gfx::ClearData {
                color: Some(gfx::Color([0.3, 0.3, 0.3, 1.0])),
                depth: Some(1.0),
                stencil: None,
            },
            &frame
        );
        m_model.x.x = 1.0;
        prog.data.u_ModelViewProj = m_viewproj.mul_m(&m_model).into_fixed();
        list.draw(&mesh, slice, &frame, &prog, &state).unwrap();
        device.submit(list.as_slice());
        window.swap_buffers();
    }
}
<commit_msg>Update cgmath imports<commit_after>#![feature(phase)]
#![crate_name = "cube"]

extern crate cgmath;
extern crate gfx;
#[phase(plugin)]
extern crate gfx_macros;
extern crate glfw;
extern crate native;
extern crate time;

use cgmath::FixedArray;
use cgmath::{Matrix, Matrix4, Point3, Vector3};
use cgmath::{Transform, AffineMatrix3};
use gfx::{Device, DeviceHelper};
use glfw::Context;

//----------------------------------------
// Cube associated data

#[vertex_format]
struct Vertex {
    #[as_float]
    a_Pos: [i8, ..3],
    #[as_float]
    a_TexCoord: [u8, ..2],
}

impl Vertex {
    fn new(pos: [i8, ..3], tc: [u8, ..2]) -> Vertex {
        Vertex {
            a_Pos: pos,
            a_TexCoord: tc,
        }
    }
}

#[shader_param(Program)]
struct Params {
    u_ModelViewProj: [[f32, ..4], ..4],
    t_Color: gfx::shade::TextureParam,
}

static VERTEX_SRC: gfx::ShaderSource = shaders! {
GLSL_120: b"
    #version 120
    attribute vec3 a_Pos;
    attribute vec2 a_TexCoord;
    varying vec2 v_TexCoord;
    uniform mat4 u_ModelViewProj;
    void main() {
        v_TexCoord = a_TexCoord;
        gl_Position = u_ModelViewProj * vec4(a_Pos, 1.0);
    }
"
GLSL_150: b"
    #version 150 core
    in vec3 a_Pos;
    in vec2 a_TexCoord;
    out vec2 v_TexCoord;
    uniform mat4 u_ModelViewProj;
    void main() {
        v_TexCoord = a_TexCoord;
        gl_Position = u_ModelViewProj * vec4(a_Pos, 1.0);
    }
"
};

static FRAGMENT_SRC: gfx::ShaderSource = shaders! {
GLSL_120: b"
    #version 120
    varying vec2 v_TexCoord;
    uniform sampler2D t_Color;
    void main() {
        vec4 tex = texture2D(t_Color, v_TexCoord);
        float blend = dot(v_TexCoord-vec2(0.5,0.5), v_TexCoord-vec2(0.5,0.5));
        gl_FragColor = mix(tex, vec4(0.0,0.0,0.0,0.0), blend*1.0);
    }
"
GLSL_150: b"
    #version 150 core
    in vec2 v_TexCoord;
    out vec4 o_Color;
    uniform sampler2D t_Color;
    void main() {
        vec4 tex = texture(t_Color, v_TexCoord);
        float blend = dot(v_TexCoord-vec2(0.5,0.5), v_TexCoord-vec2(0.5,0.5));
        o_Color = mix(tex, vec4(0.0,0.0,0.0,0.0), blend*1.0);
    }
"
};

//----------------------------------------

// We need to run on the main thread, so ensure we are using the `native` runtime. This is
// technically not needed, since this is the default, but it's not guaranteed.
#[start]
fn start(argc: int, argv: *const *const u8) -> int {
     native::start(argc, argv, main)
}

fn main() {
    let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    glfw.window_hint(glfw::ContextVersion(3, 2));
    glfw.window_hint(glfw::OpenglForwardCompat(true));
    glfw.window_hint(glfw::OpenglProfile(glfw::OpenGlCoreProfile));

    let (window, events) = glfw
        .create_window(640, 480, "Cube example", glfw::Windowed)
        .expect("Failed to create GLFW window.");

    window.make_current();
    glfw.set_error_callback(glfw::FAIL_ON_ERRORS);
    window.set_key_polling(true); // so we can quit when Esc is pressed
    let (w, h) = window.get_framebuffer_size();
    let frame = gfx::Frame::new(w as u16, h as u16);

    let mut device = gfx::GlDevice::new(|s| glfw.get_proc_address(s));
    let mut list = device.create_draw_list();

    let state = gfx::DrawState::new().depth(gfx::state::LessEqual, true);

    let vertex_data = vec![
        //top (0, 0, 1)
        Vertex::new([-1, -1,  1], [0, 0]),
        Vertex::new([ 1, -1,  1], [1, 0]),
        Vertex::new([ 1,  1,  1], [1, 1]),
        Vertex::new([-1,  1,  1], [0, 1]),
        //bottom (0, 0, -1)
        Vertex::new([ 1,  1, -1], [0, 0]),
        Vertex::new([-1,  1, -1], [1, 0]),
        Vertex::new([-1, -1, -1], [1, 1]),
        Vertex::new([ 1, -1, -1], [0, 1]),
        //right (1, 0, 0)
        Vertex::new([ 1, -1, -1], [0, 0]),
        Vertex::new([ 1,  1, -1], [1, 0]),
        Vertex::new([ 1,  1,  1], [1, 1]),
        Vertex::new([ 1, -1,  1], [0, 1]),
        //left (-1, 0, 0)
        Vertex::new([-1,  1,  1], [0, 0]),
        Vertex::new([-1, -1,  1], [1, 0]),
        Vertex::new([-1, -1, -1], [1, 1]),
        Vertex::new([-1,  1, -1], [0, 1]),
        //front (0, 1, 0)
        Vertex::new([-1,  1, -1], [0, 0]),
        Vertex::new([ 1,  1, -1], [1, 0]),
        Vertex::new([ 1,  1,  1], [1, 1]),
        Vertex::new([-1,  1,  1], [0, 1]),
        //back (0, -1, 0)
        Vertex::new([ 1, -1,  1], [0, 0]),
        Vertex::new([-1, -1,  1], [1, 0]),
        Vertex::new([-1, -1, -1], [1, 1]),
        Vertex::new([ 1, -1, -1], [0, 1]),
    ];

    let mesh = device.create_mesh(vertex_data);

    let slice = {
        let index_data = vec![
            0u8, 1, 2, 2, 3, 0,    //top
            4, 5, 6, 6, 7, 4,       //bottom
            8, 9, 10, 10, 11, 8,    //right
            12, 13, 14, 14, 16, 12, //left
            16, 17, 18, 18, 19, 16, //front
            20, 21, 22, 22, 23, 20, //back
        ];

        let buf = device.create_buffer_static(&index_data);
        gfx::IndexSlice8(buf, 0, 36)
    };

    let tinfo = gfx::tex::TextureInfo {
        width: 1,
        height: 1,
        depth: 1,
        mipmap_range: (0, 1),
        kind: gfx::tex::Texture2D,
        format: gfx::tex::RGBA8,
    };
    let img_info = tinfo.to_image_info();
    let texture = device.create_texture(tinfo).unwrap();
    device.update_texture(&texture, &img_info,
                          &vec![0x20u8, 0xA0u8, 0xC0u8, 0x00u8])
           .unwrap();

    let sampler = device.create_sampler(gfx::tex::SamplerInfo::new(
        gfx::tex::Bilinear, gfx::tex::Clamp));

    let mut prog = {
        let data = Params {
            u_ModelViewProj: Matrix4::identity().into_fixed(),
            t_Color: (texture, Some(sampler)),
        };
        device.link_program(data, VERTEX_SRC.clone(), FRAGMENT_SRC.clone())
               .unwrap()
    };

    let mut m_model = Matrix4::<f32>::identity();
    let m_viewproj = {
        let mv: AffineMatrix3<f32> = Transform::look_at(
            &Point3::new(1.5f32, -5.0, 3.0),
            &Point3::new(0f32, 0.0, 0.0),
            &Vector3::unit_z()
        );
        let aspect = w as f32 / h as f32;
        let mp = cgmath::perspective(cgmath::deg(45f32),
                                     aspect, 1f32, 10f32);
        mp.mul_m(&mv.mat)
    };

    while !window.should_close() {
        glfw.poll_events();
        // quit when Esc is pressed.
        for (_, event) in glfw::flush_messages(&events) {
            match event {
                glfw::KeyEvent(glfw::KeyEscape, _, glfw::Press, _) =>
                    window.set_should_close(true),
                _ => {},
            }
        }
        // render
        list.reset();
        list.clear(
            gfx::ClearData {
                color: Some(gfx::Color([0.3, 0.3, 0.3, 1.0])),
                depth: Some(1.0),
                stencil: None,
            },
            &frame
        );
        m_model.x.x = 1.0;
        prog.data.u_ModelViewProj = m_viewproj.mul_m(&m_model).into_fixed();
        list.draw(&mesh, slice, &frame, &prog, &state).unwrap();
        device.submit(list.as_slice());
        window.swap_buffers();
    }
}
<|endoftext|>


<commit_before>#[allow(ctypes)];
#[no_std];
#[feature(asm)];
//#[no_core];
#[feature(macro_rules)];

mod core;
pub mod stdio;
pub mod idt;

#[no_mangle]
pub unsafe fn main() {
    idt::idt_install();
    stdio::clear_screen(stdio::Green);
    stdio::write("Hello!aaa", 2, 3);
    let mut i: u32 = 0;
    let N: u32 = 80000000;
    while true {
        i += 1;
        if (i % N == 0) {
            stdio::putchar(2, 4, 65 + ((i / N) as u8));
        }
    }
}

<commit_msg>Make character-printing loop more readable<commit_after>#[allow(ctypes)];
#[no_std];
#[feature(asm)];
//#[no_core];
#[feature(macro_rules)];

mod core;
pub mod stdio;
pub mod idt;

#[no_mangle]
pub unsafe fn main() {
    idt::idt_install();
    stdio::clear_screen(stdio::Green);
    stdio::write("Hello!aaa", 2, 3);
    let mut i: u32 = 0;
    let mut c: u8 = 65; // 'A'
    let N: u32 = 80000000;
    while true {
        i += 1;
        if (i % N == 0) {
            c += 1;
            stdio::putchar(2, 4, c);
        }
    }
}

<|endoftext|>