<commit_before>//! Converting Cretonne IL to text.
//!
//! The `write` module provides the `write_function` function which converts an IL `Function` to an
//! equivalent textual representation. This textual representation can be read back by the
//! `cretonne-reader` crate.

use std::io::{self, Write};
use repr::Function;
use entities::{Inst, Ebb, Value};
use types::Type;

pub type Result = io::Result<()>;

/// Write `func` to `w` as equivalent text.
pub fn write_function(w: &mut Write, func: &Function) -> Result {
    try!(write_spec(w, func));
    try!(writeln!(w, " {{"));
    let mut any = try!(write_preamble(w, func));
    for ebb in func.ebbs_numerically() {
        if any {
            try!(writeln!(w, ""));
        }
        try!(write_ebb(w, func, ebb));
        any = true;
    }
    writeln!(w, "}}")
}

/// Convert `func` to a string.
pub fn function_to_string(func: &Function) -> String {
    let mut buffer: Vec<u8> = Vec::new();
    // Any errors here would be out-of-memory, which should not happen with normal functions.
    write_function(&mut buffer, func).unwrap();
    // A UTF-8 conversion error is a real bug.
    String::from_utf8(buffer).unwrap()
}

// ====--------------------------------------------------------------------------------------====//
//
// Function spec.
//
// ====--------------------------------------------------------------------------------------====//

// The function name may need quotes if it doesn't parse as an identifier.
fn needs_quotes(name: &str) -> bool {
    let mut iter = name.chars();
    if let Some(ch) = iter.next() {
        !ch.is_alphabetic() || !iter.all(char::is_alphanumeric)
    } else {
        // A blank function name needs quotes.
        true
    }
}

// Use Rust's escape_default which provides a few simple \t \r \n \' \" \\ escapes and uses
// \u{xxxx} for anything else outside the ASCII printable range.
fn escaped(name: &str) -> String {
    name.chars().flat_map(char::escape_default).collect()
}

fn write_spec(w: &mut Write, func: &Function) -> Result {
    let sig = func.own_signature();
    if !needs_quotes(&func.name) {
        write!(w, "function {}{}", func.name, sig)
    } else {
        write!(w, "function \"{}\" {}", escaped(&func.name), sig)
    }
}

fn write_preamble(w: &mut Write, func: &Function) -> io::Result<bool> {
    let mut any = false;

    for ss in func.stack_slot_iter() {
        any = true;
        try!(writeln!(w, "    {} = {}", ss, func[ss]));
    }

    Ok(any)
}

// ====--------------------------------------------------------------------------------------====//
//
// Basic blocks
//
// ====--------------------------------------------------------------------------------------====//

pub fn write_arg(w: &mut Write, func: &Function, arg: Value) -> Result {
    write!(w, "{}: {}", arg, func.value_type(arg))
}

pub fn write_ebb_header(w: &mut Write, func: &Function, ebb: Ebb) -> Result {
    // Write out the basic block header, outdented:
    //
    //    ebb1:
    //    ebb1(vx1: i32):
    //    ebb10(vx4: f64, vx5: b1):
    //

    let mut args = func.ebb_args(ebb);
    match args.next() {
        None => return writeln!(w, "{}:", ebb),
        Some(arg) => {
            try!(write!(w, "{}(", ebb));
            try!(write_arg(w, func, arg));
        }
    }
    // Remaining args.
    for arg in args {
        try!(write!(w, ", "));
        try!(write_arg(w, func, arg));
    }
    writeln!(w, "):")
}

pub fn write_ebb(w: &mut Write, func: &Function, ebb: Ebb) -> Result {
    try!(write_ebb_header(w, func, ebb));
    for inst in func.ebb_insts(ebb) {
        try!(write_instruction(w, func, inst));
    }
    Ok(())
}

// ====--------------------------------------------------------------------------------------====//
//
// Instructions
//
// ====--------------------------------------------------------------------------------------====//

// Should `inst` be printed with a type suffix?
//
// Polymorphic instructions may need a suffix indicating the value of the controlling type variable
// if it can't be trivially inferred.
//
fn type_suffix(func: &Function, inst: Inst) -> Option<Type> {
    let constraints = func[inst].opcode().constraints();

    if !constraints.is_polymorphic() {
        return None;
    }

    // If the controlling type variable can be inferred from the type of the designated value input
    // operand, we don't need the type suffix.
    // TODO: Should we include the suffix when the input value is defined in another block? The
    // parser needs to know the type of the value, so it must be defined in a block that lexically
    // comes before this one.
    if constraints.use_typevar_operand() {
        return None;
    }

    // This polymorphic instruction doesn't support basic type inference.
    // The controlling type variable is required to be the type of the first result.
    let rtype = func.value_type(func.first_result(inst));
    assert!(!rtype.is_void(),
            "Polymorphic instruction must produce a result");
    Some(rtype)
}

pub fn write_instruction(w: &mut Write, func: &Function, inst: Inst) -> Result {
    try!(write!(w, "    "));

    // First write out the result values, if any.
    let mut has_results = false;
    for r in func.inst_results(inst) {
        if !has_results {
            has_results = true;
            try!(write!(w, "{}", r));
        } else {
            try!(write!(w, ", {}", r));
        }
    }
    if has_results {
        try!(write!(w, " = "));
    }

    // Then the opcode, possibly with a '.type' suffix.
    let opcode = func[inst].opcode();

    match type_suffix(func, inst) {
        Some(suf) => try!(write!(w, "{}.{}", opcode, suf)),
        None => try!(write!(w, "{}", opcode)),
    }

    // Then the operands, depending on format.
    use instructions::InstructionData::*;
    match func[inst] {
        Nullary { .. } => writeln!(w, ""),
        Unary { arg, .. } => writeln!(w, " {}", arg),
        UnaryImm { imm, .. } => writeln!(w, " {}", imm),
        UnaryIeee32 { imm, .. } => writeln!(w, " {}", imm),
        UnaryIeee64 { imm, .. } => writeln!(w, " {}", imm),
        UnaryImmVector { .. } => writeln!(w, " [...]"),
        Binary { args, .. } => writeln!(w, " {}, {}", args[0], args[1]),
        BinaryImm { arg, imm, .. } => writeln!(w, " {}, {}", arg, imm),
        BinaryImmRev { imm, arg, .. } => writeln!(w, " {}, {}", imm, arg),
        BinaryOverflow { args, .. } => writeln!(w, " {}, {}", args[0], args[1]),
        Ternary { args, .. } => writeln!(w, " {}, {}, {}", args[0], args[1], args[2]),
        InsertLane { lane, args, .. } => writeln!(w, " {}, {}, {}", args[0], lane, args[1]),
        ExtractLane { lane, arg, .. } => writeln!(w, " {}, {}", arg, lane),
        IntCompare { cond, args, .. } => writeln!(w, " {}, {}, {}", cond, args[0], args[1]),
        FloatCompare { cond, args, .. } => writeln!(w, " {}, {}, {}", cond, args[0], args[1]),
        Jump { ref data, .. } => writeln!(w, " {}", data),
        Branch { ref data, .. } => writeln!(w, " {}", data),
        BranchTable { arg, table, .. } => writeln!(w, " {}, {}", arg, table),
        Call { ref data, .. } => writeln!(w, " {}", data),
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::{needs_quotes, escaped};
    use repr::{Function, StackSlotData};
    use types;

    #[test]
    fn quoting() {
        assert_eq!(needs_quotes(""), true);
        assert_eq!(needs_quotes("x"), false);
        assert_eq!(needs_quotes(" "), true);
        assert_eq!(needs_quotes("0"), true);
        assert_eq!(needs_quotes("x0"), false);
    }

    #[test]
    fn escaping() {
        assert_eq!(escaped(""), "");
        assert_eq!(escaped("x"), "x");
        assert_eq!(escaped(" "), " ");
        assert_eq!(escaped(" \n"), " \\n");
        assert_eq!(escaped("a\u{1000}v"), "a\\u{1000}v");
    }

    #[test]
    fn basic() {
        let mut f = Function::new();
        assert_eq!(function_to_string(&f), "function \"\" () {\n}\n");

        f.name.push_str("foo");
        assert_eq!(function_to_string(&f), "function foo() {\n}\n");

        f.make_stack_slot(StackSlotData::new(4));
        assert_eq!(function_to_string(&f),
                   "function foo() {\n    ss0 = stack_slot 4\n}\n");

        let ebb = f.make_ebb();
        assert_eq!(function_to_string(&f),
                   "function foo() {\n    ss0 = stack_slot 4\n\nebb0:\n}\n");

        f.append_ebb_arg(ebb, types::I8);
        assert_eq!(function_to_string(&f),
                   "function foo() {\n    ss0 = stack_slot 4\n\nebb0(vx0: i8):\n}\n");

        f.append_ebb_arg(ebb, types::F32.by(4).unwrap());
        assert_eq!(function_to_string(&f),
                   "function foo() {\n    ss0 = stack_slot 4\n\nebb0(vx0: i8, vx1: f32x4):\n}\n");
    }
}
<commit_msg>Don't print a space after quoted function names.<commit_after>//! Converting Cretonne IL to text.
//!
//! The `write` module provides the `write_function` function which converts an IL `Function` to an
//! equivalent textual representation. This textual representation can be read back by the
//! `cretonne-reader` crate.

use std::io::{self, Write};
use repr::Function;
use entities::{Inst, Ebb, Value};
use types::Type;

pub type Result = io::Result<()>;

/// Write `func` to `w` as equivalent text.
pub fn write_function(w: &mut Write, func: &Function) -> Result {
    try!(write_spec(w, func));
    try!(writeln!(w, " {{"));
    let mut any = try!(write_preamble(w, func));
    for ebb in func.ebbs_numerically() {
        if any {
            try!(writeln!(w, ""));
        }
        try!(write_ebb(w, func, ebb));
        any = true;
    }
    writeln!(w, "}}")
}

/// Convert `func` to a string.
pub fn function_to_string(func: &Function) -> String {
    let mut buffer: Vec<u8> = Vec::new();
    // Any errors here would be out-of-memory, which should not happen with normal functions.
    write_function(&mut buffer, func).unwrap();
    // A UTF-8 conversion error is a real bug.
    String::from_utf8(buffer).unwrap()
}

// ====--------------------------------------------------------------------------------------====//
//
// Function spec.
//
// ====--------------------------------------------------------------------------------------====//

// The function name may need quotes if it doesn't parse as an identifier.
fn needs_quotes(name: &str) -> bool {
    let mut iter = name.chars();
    if let Some(ch) = iter.next() {
        !ch.is_alphabetic() || !iter.all(char::is_alphanumeric)
    } else {
        // A blank function name needs quotes.
        true
    }
}

// Use Rust's escape_default which provides a few simple \t \r \n \' \" \\ escapes and uses
// \u{xxxx} for anything else outside the ASCII printable range.
fn escaped(name: &str) -> String {
    name.chars().flat_map(char::escape_default).collect()
}

fn write_spec(w: &mut Write, func: &Function) -> Result {
    let sig = func.own_signature();
    if !needs_quotes(&func.name) {
        write!(w, "function {}{}", func.name, sig)
    } else {
        write!(w, "function \"{}\"{}", escaped(&func.name), sig)
    }
}

fn write_preamble(w: &mut Write, func: &Function) -> io::Result<bool> {
    let mut any = false;

    for ss in func.stack_slot_iter() {
        any = true;
        try!(writeln!(w, "    {} = {}", ss, func[ss]));
    }

    Ok(any)
}

// ====--------------------------------------------------------------------------------------====//
//
// Basic blocks
//
// ====--------------------------------------------------------------------------------------====//

pub fn write_arg(w: &mut Write, func: &Function, arg: Value) -> Result {
    write!(w, "{}: {}", arg, func.value_type(arg))
}

pub fn write_ebb_header(w: &mut Write, func: &Function, ebb: Ebb) -> Result {
    // Write out the basic block header, outdented:
    //
    //    ebb1:
    //    ebb1(vx1: i32):
    //    ebb10(vx4: f64, vx5: b1):
    //

    let mut args = func.ebb_args(ebb);
    match args.next() {
        None => return writeln!(w, "{}:", ebb),
        Some(arg) => {
            try!(write!(w, "{}(", ebb));
            try!(write_arg(w, func, arg));
        }
    }
    // Remaining args.
    for arg in args {
        try!(write!(w, ", "));
        try!(write_arg(w, func, arg));
    }
    writeln!(w, "):")
}

pub fn write_ebb(w: &mut Write, func: &Function, ebb: Ebb) -> Result {
    try!(write_ebb_header(w, func, ebb));
    for inst in func.ebb_insts(ebb) {
        try!(write_instruction(w, func, inst));
    }
    Ok(())
}

// ====--------------------------------------------------------------------------------------====//
//
// Instructions
//
// ====--------------------------------------------------------------------------------------====//

// Should `inst` be printed with a type suffix?
//
// Polymorphic instructions may need a suffix indicating the value of the controlling type variable
// if it can't be trivially inferred.
//
fn type_suffix(func: &Function, inst: Inst) -> Option<Type> {
    let constraints = func[inst].opcode().constraints();

    if !constraints.is_polymorphic() {
        return None;
    }

    // If the controlling type variable can be inferred from the type of the designated value input
    // operand, we don't need the type suffix.
    // TODO: Should we include the suffix when the input value is defined in another block? The
    // parser needs to know the type of the value, so it must be defined in a block that lexically
    // comes before this one.
    if constraints.use_typevar_operand() {
        return None;
    }

    // This polymorphic instruction doesn't support basic type inference.
    // The controlling type variable is required to be the type of the first result.
    let rtype = func.value_type(func.first_result(inst));
    assert!(!rtype.is_void(),
            "Polymorphic instruction must produce a result");
    Some(rtype)
}

pub fn write_instruction(w: &mut Write, func: &Function, inst: Inst) -> Result {
    try!(write!(w, "    "));

    // First write out the result values, if any.
    let mut has_results = false;
    for r in func.inst_results(inst) {
        if !has_results {
            has_results = true;
            try!(write!(w, "{}", r));
        } else {
            try!(write!(w, ", {}", r));
        }
    }
    if has_results {
        try!(write!(w, " = "));
    }

    // Then the opcode, possibly with a '.type' suffix.
    let opcode = func[inst].opcode();

    match type_suffix(func, inst) {
        Some(suf) => try!(write!(w, "{}.{}", opcode, suf)),
        None => try!(write!(w, "{}", opcode)),
    }

    // Then the operands, depending on format.
    use instructions::InstructionData::*;
    match func[inst] {
        Nullary { .. } => writeln!(w, ""),
        Unary { arg, .. } => writeln!(w, " {}", arg),
        UnaryImm { imm, .. } => writeln!(w, " {}", imm),
        UnaryIeee32 { imm, .. } => writeln!(w, " {}", imm),
        UnaryIeee64 { imm, .. } => writeln!(w, " {}", imm),
        UnaryImmVector { .. } => writeln!(w, " [...]"),
        Binary { args, .. } => writeln!(w, " {}, {}", args[0], args[1]),
        BinaryImm { arg, imm, .. } => writeln!(w, " {}, {}", arg, imm),
        BinaryImmRev { imm, arg, .. } => writeln!(w, " {}, {}", imm, arg),
        BinaryOverflow { args, .. } => writeln!(w, " {}, {}", args[0], args[1]),
        Ternary { args, .. } => writeln!(w, " {}, {}, {}", args[0], args[1], args[2]),
        InsertLane { lane, args, .. } => writeln!(w, " {}, {}, {}", args[0], lane, args[1]),
        ExtractLane { lane, arg, .. } => writeln!(w, " {}, {}", arg, lane),
        IntCompare { cond, args, .. } => writeln!(w, " {}, {}, {}", cond, args[0], args[1]),
        FloatCompare { cond, args, .. } => writeln!(w, " {}, {}, {}", cond, args[0], args[1]),
        Jump { ref data, .. } => writeln!(w, " {}", data),
        Branch { ref data, .. } => writeln!(w, " {}", data),
        BranchTable { arg, table, .. } => writeln!(w, " {}, {}", arg, table),
        Call { ref data, .. } => writeln!(w, " {}", data),
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::{needs_quotes, escaped};
    use repr::{Function, StackSlotData};
    use types;

    #[test]
    fn quoting() {
        assert_eq!(needs_quotes(""), true);
        assert_eq!(needs_quotes("x"), false);
        assert_eq!(needs_quotes(" "), true);
        assert_eq!(needs_quotes("0"), true);
        assert_eq!(needs_quotes("x0"), false);
    }

    #[test]
    fn escaping() {
        assert_eq!(escaped(""), "");
        assert_eq!(escaped("x"), "x");
        assert_eq!(escaped(" "), " ");
        assert_eq!(escaped(" \n"), " \\n");
        assert_eq!(escaped("a\u{1000}v"), "a\\u{1000}v");
    }

    #[test]
    fn basic() {
        let mut f = Function::new();
        assert_eq!(function_to_string(&f), "function \"\"() {\n}\n");

        f.name.push_str("foo");
        assert_eq!(function_to_string(&f), "function foo() {\n}\n");

        f.make_stack_slot(StackSlotData::new(4));
        assert_eq!(function_to_string(&f),
                   "function foo() {\n    ss0 = stack_slot 4\n}\n");

        let ebb = f.make_ebb();
        assert_eq!(function_to_string(&f),
                   "function foo() {\n    ss0 = stack_slot 4\n\nebb0:\n}\n");

        f.append_ebb_arg(ebb, types::I8);
        assert_eq!(function_to_string(&f),
                   "function foo() {\n    ss0 = stack_slot 4\n\nebb0(vx0: i8):\n}\n");

        f.append_ebb_arg(ebb, types::F32.by(4).unwrap());
        assert_eq!(function_to_string(&f),
                   "function foo() {\n    ss0 = stack_slot 4\n\nebb0(vx0: i8, vx1: f32x4):\n}\n");
    }
}
<|endoftext|>


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

use mir::interpret::ConstValue;
use ty::subst::Substs;
use ty::{self, Ty, TypeFlags, TypeFoldable};

#[derive(Debug)]
pub struct FlagComputation {
    pub flags: TypeFlags,

    // see `TyS::outer_exclusive_binder` for details
    pub outer_exclusive_binder: ty::DebruijnIndex,
}

impl FlagComputation {
    fn new() -> FlagComputation {
        FlagComputation {
            flags: TypeFlags::empty(),
            outer_exclusive_binder: ty::INNERMOST,
        }
    }

    pub fn for_sty(st: &ty::TyKind<'_>) -> FlagComputation {
        let mut result = FlagComputation::new();
        result.add_sty(st);
        result
    }

    fn add_flags(&mut self, flags: TypeFlags) {
        self.flags = self.flags | (flags & TypeFlags::NOMINAL_FLAGS);
    }

    /// indicates that `self` refers to something at binding level `binder`
    fn add_binder(&mut self, binder: ty::DebruijnIndex) {
        let exclusive_binder = binder.shifted_in(1);
        self.add_exclusive_binder(exclusive_binder);
    }

    /// indicates that `self` refers to something *inside* binding
    /// level `binder` -- not bound by `binder`, but bound by the next
    /// binder internal to it
    fn add_exclusive_binder(&mut self, exclusive_binder: ty::DebruijnIndex) {
        self.outer_exclusive_binder = self.outer_exclusive_binder.max(exclusive_binder);
    }

    /// Adds the flags/depth from a set of types that appear within the current type, but within a
    /// region binder.
    fn add_bound_computation(&mut self, computation: &FlagComputation) {
        self.add_flags(computation.flags);

        // The types that contributed to `computation` occurred within
        // a region binder, so subtract one from the region depth
        // within when adding the depth to `self`.
        let outer_exclusive_binder = computation.outer_exclusive_binder;
        if outer_exclusive_binder > ty::INNERMOST {
            self.add_exclusive_binder(outer_exclusive_binder.shifted_out(1));
        } // otherwise, this binder captures nothing
    }

    fn add_sty(&mut self, st: &ty::TyKind<'_>) {
        match st {
            &ty::Bool |
            &ty::Char |
            &ty::Int(_) |
            &ty::Float(_) |
            &ty::Uint(_) |
            &ty::Never |
            &ty::Str |
            &ty::Foreign(..) => {
            }

            // You might think that we could just return Error for
            // any type containing Error as a component, and get
            // rid of the TypeFlags::HAS_TY_ERR flag -- likewise for ty_bot (with
            // the exception of function types that return bot).
            // But doing so caused sporadic memory corruption, and
            // neither I (tjc) nor nmatsakis could figure out why,
            // so we're doing it this way.
            &ty::Error => {
                self.add_flags(TypeFlags::HAS_TY_ERR)
            }

            &ty::Param(ref p) => {
                self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES);
                if p.is_self() {
                    self.add_flags(TypeFlags::HAS_SELF);
                } else {
                    self.add_flags(TypeFlags::HAS_PARAMS);
                }
            }

            &ty::Generator(_, ref substs, _) => {
                self.add_flags(TypeFlags::HAS_TY_CLOSURE);
                self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES);
                self.add_substs(&substs.substs);
            }

            &ty::GeneratorWitness(ref ts) => {
                let mut computation = FlagComputation::new();
                computation.add_tys(&ts.skip_binder()[..]);
                self.add_bound_computation(&computation);
            }

            &ty::Closure(_, ref substs) => {
                self.add_flags(TypeFlags::HAS_TY_CLOSURE);
                self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES);
                self.add_substs(&substs.substs);
            }

            &ty::Infer(infer) => {
                self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); // it might, right?
                self.add_flags(TypeFlags::HAS_TY_INFER);
                match infer {
                    ty::FreshTy(_) |
                    ty::FreshIntTy(_) |
                    ty::FreshFloatTy(_) |
                    ty::CanonicalTy(_) => {
                        self.add_flags(TypeFlags::HAS_CANONICAL_VARS);
                    }

                    ty::TyVar(_) |
                    ty::IntVar(_) |
                    ty::FloatVar(_) => {
                        self.add_flags(TypeFlags::KEEP_IN_LOCAL_TCX)
                    }
                }
            }

            &ty::Adt(_, substs) => {
                self.add_substs(substs);
            }

            &ty::Projection(ref data) => {
                // currently we can't normalize projections that
                // include bound regions, so track those separately.
                if !data.has_escaping_regions() {
                    self.add_flags(TypeFlags::HAS_NORMALIZABLE_PROJECTION);
                }
                self.add_flags(TypeFlags::HAS_PROJECTION);
                self.add_projection_ty(data);
            }

            &ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),

            &ty::Opaque(_, substs) => {
                self.add_flags(TypeFlags::HAS_PROJECTION);
                self.add_substs(substs);
            }

            &ty::Dynamic(ref obj, r) => {
                let mut computation = FlagComputation::new();
                for predicate in obj.skip_binder().iter() {
                    match *predicate {
                        ty::ExistentialPredicate::Trait(tr) => computation.add_substs(tr.substs),
                        ty::ExistentialPredicate::Projection(p) => {
                            let mut proj_computation = FlagComputation::new();
                            proj_computation.add_existential_projection(&p);
                            self.add_bound_computation(&proj_computation);
                        }
                        ty::ExistentialPredicate::AutoTrait(_) => {}
                    }
                }
                self.add_bound_computation(&computation);
                self.add_region(r);
            }

            &ty::Array(tt, len) => {
                self.add_ty(tt);
                self.add_const(len);
            }

            &ty::Slice(tt) => {
                self.add_ty(tt)
            }

            &ty::RawPtr(ref m) => {
                self.add_ty(m.ty);
            }

            &ty::Ref(r, ty, _) => {
                self.add_region(r);
                self.add_ty(ty);
            }

            &ty::Tuple(ref ts) => {
                self.add_tys(&ts[..]);
            }

            &ty::FnDef(_, substs) => {
                self.add_substs(substs);
            }

            &ty::FnPtr(f) => {
                self.add_fn_sig(f);
            }
        }
    }

    fn add_ty(&mut self, ty: Ty<'_>) {
        self.add_flags(ty.flags);
        self.add_exclusive_binder(ty.outer_exclusive_binder);
    }

    fn add_tys(&mut self, tys: &[Ty<'_>]) {
        for &ty in tys {
            self.add_ty(ty);
        }
    }

    fn add_fn_sig(&mut self, fn_sig: ty::PolyFnSig<'_>) {
        let mut computation = FlagComputation::new();

        computation.add_tys(fn_sig.skip_binder().inputs());
        computation.add_ty(fn_sig.skip_binder().output());

        self.add_bound_computation(&computation);
    }

    fn add_region(&mut self, r: ty::Region<'_>) {
        self.add_flags(r.type_flags());
        if let ty::ReLateBound(debruijn, _) = *r {
            self.add_binder(debruijn);
        }
    }

    fn add_const(&mut self, constant: &ty::Const<'_>) {
        self.add_ty(constant.ty);
        if let ConstValue::Unevaluated(_, substs) = constant.val {
            self.add_flags(TypeFlags::HAS_PROJECTION);
            self.add_substs(substs);
        }
    }

    fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) {
        self.add_substs(projection.substs);
        self.add_ty(projection.ty);
    }

    fn add_projection_ty(&mut self, projection_ty: &ty::ProjectionTy<'_>) {
        self.add_substs(projection_ty.substs);
    }

    fn add_substs(&mut self, substs: &Substs<'_>) {
        for ty in substs.types() {
            self.add_ty(ty);
        }

        for r in substs.regions() {
            self.add_region(r);
        }
    }
}
<commit_msg>Compute flags for `ty::UnnormalizedProjection`<commit_after>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use mir::interpret::ConstValue;
use ty::subst::Substs;
use ty::{self, Ty, TypeFlags, TypeFoldable};

#[derive(Debug)]
pub struct FlagComputation {
    pub flags: TypeFlags,

    // see `TyS::outer_exclusive_binder` for details
    pub outer_exclusive_binder: ty::DebruijnIndex,
}

impl FlagComputation {
    fn new() -> FlagComputation {
        FlagComputation {
            flags: TypeFlags::empty(),
            outer_exclusive_binder: ty::INNERMOST,
        }
    }

    pub fn for_sty(st: &ty::TyKind<'_>) -> FlagComputation {
        let mut result = FlagComputation::new();
        result.add_sty(st);
        result
    }

    fn add_flags(&mut self, flags: TypeFlags) {
        self.flags = self.flags | (flags & TypeFlags::NOMINAL_FLAGS);
    }

    /// indicates that `self` refers to something at binding level `binder`
    fn add_binder(&mut self, binder: ty::DebruijnIndex) {
        let exclusive_binder = binder.shifted_in(1);
        self.add_exclusive_binder(exclusive_binder);
    }

    /// indicates that `self` refers to something *inside* binding
    /// level `binder` -- not bound by `binder`, but bound by the next
    /// binder internal to it
    fn add_exclusive_binder(&mut self, exclusive_binder: ty::DebruijnIndex) {
        self.outer_exclusive_binder = self.outer_exclusive_binder.max(exclusive_binder);
    }

    /// Adds the flags/depth from a set of types that appear within the current type, but within a
    /// region binder.
    fn add_bound_computation(&mut self, computation: &FlagComputation) {
        self.add_flags(computation.flags);

        // The types that contributed to `computation` occurred within
        // a region binder, so subtract one from the region depth
        // within when adding the depth to `self`.
        let outer_exclusive_binder = computation.outer_exclusive_binder;
        if outer_exclusive_binder > ty::INNERMOST {
            self.add_exclusive_binder(outer_exclusive_binder.shifted_out(1));
        } // otherwise, this binder captures nothing
    }

    fn add_sty(&mut self, st: &ty::TyKind<'_>) {
        match st {
            &ty::Bool |
            &ty::Char |
            &ty::Int(_) |
            &ty::Float(_) |
            &ty::Uint(_) |
            &ty::Never |
            &ty::Str |
            &ty::Foreign(..) => {
            }

            // You might think that we could just return Error for
            // any type containing Error as a component, and get
            // rid of the TypeFlags::HAS_TY_ERR flag -- likewise for ty_bot (with
            // the exception of function types that return bot).
            // But doing so caused sporadic memory corruption, and
            // neither I (tjc) nor nmatsakis could figure out why,
            // so we're doing it this way.
            &ty::Error => {
                self.add_flags(TypeFlags::HAS_TY_ERR)
            }

            &ty::Param(ref p) => {
                self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES);
                if p.is_self() {
                    self.add_flags(TypeFlags::HAS_SELF);
                } else {
                    self.add_flags(TypeFlags::HAS_PARAMS);
                }
            }

            &ty::Generator(_, ref substs, _) => {
                self.add_flags(TypeFlags::HAS_TY_CLOSURE);
                self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES);
                self.add_substs(&substs.substs);
            }

            &ty::GeneratorWitness(ref ts) => {
                let mut computation = FlagComputation::new();
                computation.add_tys(&ts.skip_binder()[..]);
                self.add_bound_computation(&computation);
            }

            &ty::Closure(_, ref substs) => {
                self.add_flags(TypeFlags::HAS_TY_CLOSURE);
                self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES);
                self.add_substs(&substs.substs);
            }

            &ty::Infer(infer) => {
                self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); // it might, right?
                self.add_flags(TypeFlags::HAS_TY_INFER);
                match infer {
                    ty::FreshTy(_) |
                    ty::FreshIntTy(_) |
                    ty::FreshFloatTy(_) |
                    ty::CanonicalTy(_) => {
                        self.add_flags(TypeFlags::HAS_CANONICAL_VARS);
                    }

                    ty::TyVar(_) |
                    ty::IntVar(_) |
                    ty::FloatVar(_) => {
                        self.add_flags(TypeFlags::KEEP_IN_LOCAL_TCX)
                    }
                }
            }

            &ty::Adt(_, substs) => {
                self.add_substs(substs);
            }

            &ty::Projection(ref data) => {
                // currently we can't normalize projections that
                // include bound regions, so track those separately.
                if !data.has_escaping_regions() {
                    self.add_flags(TypeFlags::HAS_NORMALIZABLE_PROJECTION);
                }
                self.add_flags(TypeFlags::HAS_PROJECTION);
                self.add_projection_ty(data);
            }

            &ty::UnnormalizedProjection(ref data) => {
                self.add_flags(TypeFlags::HAS_PROJECTION);
                self.add_projection_ty(data);
            },

            &ty::Opaque(_, substs) => {
                self.add_flags(TypeFlags::HAS_PROJECTION);
                self.add_substs(substs);
            }

            &ty::Dynamic(ref obj, r) => {
                let mut computation = FlagComputation::new();
                for predicate in obj.skip_binder().iter() {
                    match *predicate {
                        ty::ExistentialPredicate::Trait(tr) => computation.add_substs(tr.substs),
                        ty::ExistentialPredicate::Projection(p) => {
                            let mut proj_computation = FlagComputation::new();
                            proj_computation.add_existential_projection(&p);
                            self.add_bound_computation(&proj_computation);
                        }
                        ty::ExistentialPredicate::AutoTrait(_) => {}
                    }
                }
                self.add_bound_computation(&computation);
                self.add_region(r);
            }

            &ty::Array(tt, len) => {
                self.add_ty(tt);
                self.add_const(len);
            }

            &ty::Slice(tt) => {
                self.add_ty(tt)
            }

            &ty::RawPtr(ref m) => {
                self.add_ty(m.ty);
            }

            &ty::Ref(r, ty, _) => {
                self.add_region(r);
                self.add_ty(ty);
            }

            &ty::Tuple(ref ts) => {
                self.add_tys(&ts[..]);
            }

            &ty::FnDef(_, substs) => {
                self.add_substs(substs);
            }

            &ty::FnPtr(f) => {
                self.add_fn_sig(f);
            }
        }
    }

    fn add_ty(&mut self, ty: Ty<'_>) {
        self.add_flags(ty.flags);
        self.add_exclusive_binder(ty.outer_exclusive_binder);
    }

    fn add_tys(&mut self, tys: &[Ty<'_>]) {
        for &ty in tys {
            self.add_ty(ty);
        }
    }

    fn add_fn_sig(&mut self, fn_sig: ty::PolyFnSig<'_>) {
        let mut computation = FlagComputation::new();

        computation.add_tys(fn_sig.skip_binder().inputs());
        computation.add_ty(fn_sig.skip_binder().output());

        self.add_bound_computation(&computation);
    }

    fn add_region(&mut self, r: ty::Region<'_>) {
        self.add_flags(r.type_flags());
        if let ty::ReLateBound(debruijn, _) = *r {
            self.add_binder(debruijn);
        }
    }

    fn add_const(&mut self, constant: &ty::Const<'_>) {
        self.add_ty(constant.ty);
        if let ConstValue::Unevaluated(_, substs) = constant.val {
            self.add_flags(TypeFlags::HAS_PROJECTION);
            self.add_substs(substs);
        }
    }

    fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) {
        self.add_substs(projection.substs);
        self.add_ty(projection.ty);
    }

    fn add_projection_ty(&mut self, projection_ty: &ty::ProjectionTy<'_>) {
        self.add_substs(projection_ty.substs);
    }

    fn add_substs(&mut self, substs: &Substs<'_>) {
        for ty in substs.types() {
            self.add_ty(ty);
        }

        for r in substs.regions() {
            self.add_region(r);
        }
    }
}
<|endoftext|>


<commit_before>//! Type representing a Liquid array, payload of the `BoxedValue::Array` variant

use std::fmt;

use kstring::KStringCow;

use crate::model::value::DisplayCow;
use crate::model::State;
use crate::model::Value;
use crate::model::ValueView;

/// Accessor for arrays.
pub trait ArrayView: ValueView {
    /// Cast to ValueView
    fn as_value(&self) -> &dyn ValueView;

    /// Returns the number of elements.
    fn size(&self) -> i32;

    /// Returns an iterator .
    fn values<'k>(&'k self) -> Box<dyn Iterator<Item = &'k dyn ValueView> + 'k>;

    /// Access a contained `BoxedValue`.
    fn contains_key(&self, index: i32) -> bool;
    /// Access a contained `Value`.
    fn get(&self, index: i32) -> Option<&dyn ValueView>;
    /// Returns the first element.
    fn first(&self) -> Option<&dyn ValueView> {
        self.get(0)
    }
    /// Returns the last element.
    fn last(&self) -> Option<&dyn ValueView> {
        self.get(-1)
    }
}

/// Type representing a Liquid array, payload of the `BoxedValue::Array` variant
pub type Array = Vec<Value>;

impl<T: ValueView> ValueView for Vec<T> {
    fn as_debug(&self) -> &dyn fmt::Debug {
        self
    }

    fn render(&self) -> DisplayCow<'_> {
        DisplayCow::Owned(Box::new(ArrayRender { s: self }))
    }
    fn source(&self) -> DisplayCow<'_> {
        DisplayCow::Owned(Box::new(ArraySource { s: self }))
    }
    fn type_name(&self) -> &'static str {
        "array"
    }
    fn query_state(&self, state: State) -> bool {
        match state {
            State::Truthy => true,
            State::DefaultValue | State::Empty | State::Blank => self.is_empty(),
        }
    }

    fn to_kstr(&self) -> KStringCow<'_> {
        let s = ArrayRender { s: self }.to_string();
        KStringCow::from_string(s)
    }
    fn to_value(&self) -> Value {
        let a = self.iter().map(|v| v.to_value()).collect();
        Value::Array(a)
    }

    fn as_array(&self) -> Option<&dyn ArrayView> {
        Some(self)
    }
}

impl<T: ValueView> ArrayView for Vec<T> {
    fn as_value(&self) -> &dyn ValueView {
        self
    }

    fn size(&self) -> i32 {
        self.len() as i32
    }

    fn values<'k>(&'k self) -> Box<dyn Iterator<Item = &'k dyn ValueView> + 'k> {
        let i = self.as_slice().iter().map(|v| convert_value(v));
        Box::new(i)
    }

    fn contains_key(&self, index: i32) -> bool {
        let index = convert_index(index, self.size());
        index < self.size()
    }

    fn get(&self, index: i32) -> Option<&dyn ValueView> {
        let index = convert_index(index, self.size());
        let value = self.as_slice().get(index as usize);
        value.map(|v| convert_value(v))
    }
}

fn convert_value(s: &dyn ValueView) -> &dyn ValueView {
    s
}

fn convert_index(index: i32, max_size: i32) -> i32 {
    if 0 <= index {
        index
    } else {
        max_size + index
    }
}

struct ArraySource<'s, T: ValueView> {
    s: &'s Vec<T>,
}

impl<'s, T: ValueView> fmt::Display for ArraySource<'s, T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "[")?;
        for item in self.s {
            write!(f, "{}, ", item.render())?;
        }
        write!(f, "]")?;
        Ok(())
    }
}

struct ArrayRender<'s, T: ValueView> {
    s: &'s Vec<T>,
}

impl<'s, T: ValueView> fmt::Display for ArrayRender<'s, T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        for item in self.s {
            write!(f, "{}", item.render())?;
        }
        Ok(())
    }
}

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

    #[test]
    fn test_array() {
        let arr = Array::new();
        println!("{}", arr.source());
        let array: &dyn ArrayView = &arr;
        println!("{}", array.source());
        let view: &dyn ValueView = array.as_value();
        println!("{}", view.source());
    }
}
<commit_msg>docs(core): Update outdated comments<commit_after>//! Type representing a Liquid array, payload of the `Value::Array` variant

use std::fmt;

use kstring::KStringCow;

use crate::model::value::DisplayCow;
use crate::model::State;
use crate::model::Value;
use crate::model::ValueView;

/// Accessor for arrays.
pub trait ArrayView: ValueView {
    /// Cast to ValueView
    fn as_value(&self) -> &dyn ValueView;

    /// Returns the number of elements.
    fn size(&self) -> i32;

    /// Returns an iterator .
    fn values<'k>(&'k self) -> Box<dyn Iterator<Item = &'k dyn ValueView> + 'k>;

    /// Access a contained `Value`.
    fn contains_key(&self, index: i32) -> bool;
    /// Access a contained `Value`.
    fn get(&self, index: i32) -> Option<&dyn ValueView>;
    /// Returns the first element.
    fn first(&self) -> Option<&dyn ValueView> {
        self.get(0)
    }
    /// Returns the last element.
    fn last(&self) -> Option<&dyn ValueView> {
        self.get(-1)
    }
}

/// Type representing a Liquid array, payload of the `Value::Array` variant
pub type Array = Vec<Value>;

impl<T: ValueView> ValueView for Vec<T> {
    fn as_debug(&self) -> &dyn fmt::Debug {
        self
    }

    fn render(&self) -> DisplayCow<'_> {
        DisplayCow::Owned(Box::new(ArrayRender { s: self }))
    }
    fn source(&self) -> DisplayCow<'_> {
        DisplayCow::Owned(Box::new(ArraySource { s: self }))
    }
    fn type_name(&self) -> &'static str {
        "array"
    }
    fn query_state(&self, state: State) -> bool {
        match state {
            State::Truthy => true,
            State::DefaultValue | State::Empty | State::Blank => self.is_empty(),
        }
    }

    fn to_kstr(&self) -> KStringCow<'_> {
        let s = ArrayRender { s: self }.to_string();
        KStringCow::from_string(s)
    }
    fn to_value(&self) -> Value {
        let a = self.iter().map(|v| v.to_value()).collect();
        Value::Array(a)
    }

    fn as_array(&self) -> Option<&dyn ArrayView> {
        Some(self)
    }
}

impl<T: ValueView> ArrayView for Vec<T> {
    fn as_value(&self) -> &dyn ValueView {
        self
    }

    fn size(&self) -> i32 {
        self.len() as i32
    }

    fn values<'k>(&'k self) -> Box<dyn Iterator<Item = &'k dyn ValueView> + 'k> {
        let i = self.as_slice().iter().map(|v| convert_value(v));
        Box::new(i)
    }

    fn contains_key(&self, index: i32) -> bool {
        let index = convert_index(index, self.size());
        index < self.size()
    }

    fn get(&self, index: i32) -> Option<&dyn ValueView> {
        let index = convert_index(index, self.size());
        let value = self.as_slice().get(index as usize);
        value.map(|v| convert_value(v))
    }
}

fn convert_value(s: &dyn ValueView) -> &dyn ValueView {
    s
}

fn convert_index(index: i32, max_size: i32) -> i32 {
    if 0 <= index {
        index
    } else {
        max_size + index
    }
}

struct ArraySource<'s, T: ValueView> {
    s: &'s Vec<T>,
}

impl<'s, T: ValueView> fmt::Display for ArraySource<'s, T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "[")?;
        for item in self.s {
            write!(f, "{}, ", item.render())?;
        }
        write!(f, "]")?;
        Ok(())
    }
}

struct ArrayRender<'s, T: ValueView> {
    s: &'s Vec<T>,
}

impl<'s, T: ValueView> fmt::Display for ArrayRender<'s, T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        for item in self.s {
            write!(f, "{}", item.render())?;
        }
        Ok(())
    }
}

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

    #[test]
    fn test_array() {
        let arr = Array::new();
        println!("{}", arr.source());
        let array: &dyn ArrayView = &arr;
        println!("{}", array.source());
        let view: &dyn ValueView = array.as_value();
        println!("{}", view.source());
    }
}
<|endoftext|>


<commit_before>mod mapper;

pub use self::mapper::PageMap;

use x86_64::registers::control::{Cr0, Cr0Flags};
use x86_64::registers::model_specific::{Efer, EferFlags};
use x86_64::structures::paging as pg;
use x86_64::structures::paging::PageTableFlags as Flags;
use x86_64::PhysAddr;

use crate::driver::vga_buffer::VGA_BUFFER_PHYSADDR;
use crate::interrupt::idt;
use crate::util::elf_parser::ELFData;

use super::prelude::*;
use super::{Page, PhysFrame};

pub unsafe fn enable_nxe() {
    Efer::update(|flags| flags.set(EferFlags::NO_EXECUTE_ENABLE, true))
}

pub unsafe fn enable_write_protection() {
    Cr0::update(|flags| {
        flags.set(Cr0Flags::WRITE_PROTECT, true);
    })
}

pub unsafe fn set_active_table(p4_addr: PhysAddr) {
    use x86_64::registers::control::{Cr3, Cr3Flags};
    Cr3::write(
        pg::PhysFrame::<pg::Size4KiB>::from_start_address(p4_addr).expect("Misaligned P4"),
        Cr3Flags::empty(),
    );
}

/// Remap kernel and other necessary memory areas
#[must_use]
pub unsafe fn init(elf_metadata: ELFData) -> PageMap {
    log::debug!("Remapping kernel...");

    // Create new page table
    let mut new_table = unsafe { PageMap::init(PT_VADDR, PT_PADDR, PT_VADDR) };

    // Kernel code and data segments
    new_table.identity_map_elf(PT_VADDR, elf_metadata);

    // Identity map IDT, GDT, DMA buffers, and the VGA text buffer
    let idt_frame = PhysFrame::containing_address(PhysAddr::new(idt::ADDRESS as u64));
    let vga_buffer_frame = PhysFrame::containing_address(VGA_BUFFER_PHYSADDR);

    assert_eq!(idt_frame, vga_buffer_frame);
    let lowmem_frame = idt_frame;

    unsafe {
        new_table
            .identity_map(
                PT_VADDR,
                lowmem_frame,
                Flags::PRESENT | Flags::WRITABLE | Flags::NO_EXECUTE,
            )
            .ignore();
    }

    log::debug!("Switching to new table...");
    unsafe {
        new_table.activate();
    }
    log::debug!("Remapping done.");
    new_table
}
<commit_msg>Check that DMA memory is on the correct page<commit_after>mod mapper;

pub use self::mapper::PageMap;

use x86_64::registers::control::{Cr0, Cr0Flags};
use x86_64::registers::model_specific::{Efer, EferFlags};
use x86_64::structures::paging as pg;
use x86_64::structures::paging::PageTableFlags as Flags;
use x86_64::PhysAddr;

use crate::driver::vga_buffer::VGA_BUFFER_PHYSADDR;
use crate::interrupt::idt;
use crate::util::elf_parser::ELFData;

use super::prelude::*;
use super::{Page, PhysFrame};

pub unsafe fn enable_nxe() {
    Efer::update(|flags| flags.set(EferFlags::NO_EXECUTE_ENABLE, true))
}

pub unsafe fn enable_write_protection() {
    Cr0::update(|flags| {
        flags.set(Cr0Flags::WRITE_PROTECT, true);
    })
}

pub unsafe fn set_active_table(p4_addr: PhysAddr) {
    use x86_64::registers::control::{Cr3, Cr3Flags};
    Cr3::write(
        pg::PhysFrame::<pg::Size4KiB>::from_start_address(p4_addr).expect("Misaligned P4"),
        Cr3Flags::empty(),
    );
}

/// Remap kernel and other necessary memory areas
#[must_use]
pub unsafe fn init(elf_metadata: ELFData) -> PageMap {
    log::debug!("Remapping kernel...");

    // Create new page table
    let mut new_table = unsafe { PageMap::init(PT_VADDR, PT_PADDR, PT_VADDR) };

    // Kernel code and data segments
    new_table.identity_map_elf(PT_VADDR, elf_metadata);

    // Identity map IDT, GDT, DMA buffers, and the VGA text buffer
    let idt_frame = PhysFrame::containing_address(PhysAddr::new(idt::ADDRESS as u64));
    let vga_buffer_frame = PhysFrame::containing_address(VGA_BUFFER_PHYSADDR);
    assert_eq!(idt_frame, vga_buffer_frame);

    let dma_start = PhysFrame::containing_address(DMA_MEMORY_START);
    let dma_end = PhysFrame::containing_address(DMA_MEMORY_START + DMA_MEMORY_SIZE);
    assert_eq!(dma_start, dma_end);

    assert_eq!(idt_frame, dma_start);
    let lowmem_frame = idt_frame;

    unsafe {
        new_table
            .identity_map(
                PT_VADDR,
                lowmem_frame,
                Flags::PRESENT | Flags::WRITABLE | Flags::NO_EXECUTE,
            )
            .ignore();
    }

    log::debug!("Switching to new table...");
    unsafe {
        new_table.activate();
    }
    log::debug!("Remapping done.");
    new_table
}
<|endoftext|>


<commit_before>use std::io::{Read,Write};
use std::sync::mpsc;
use std::thread;
use std::fs::{remove_file, File, OpenOptions};

use std::time::Duration;

use ::sync;

use std::collections::HashMap;

pub fn main() {
    let mut senders = HashMap::new();
    let mut id = 0;

    loop {
        let mut inf = OpenOptions::new().read(true).write(true).create(true).open("INPUT").unwrap();
        let mut outf = OpenOptions::new().append(true).create(true).open("OUTPUT").unwrap();

        let mut inputs = String::new();
        inf.read_to_string(&mut inputs).unwrap();
        let inputs = inputs.split("\n").collect::<Vec<_>>();

        for input in inputs {
            let input = input.trim();
            if input.starts_with("sync") {
                if let Some(func) = input.split_whitespace().collect::<Vec<_>>().get(1) {
                    let (sendr, recvr) = mpsc::channel::<()>();
                    senders.insert(id, sendr);
                    match *func {
                        "derpy" => { thread::spawn(move || sync::derpy::main(&recvr)); },
                        "e621"  => { thread::spawn(move || sync::e621::main(&recvr)); },
                        "dan"   => { thread::spawn(move || sync::danbooru::main(&recvr)); }
                        "kona"  => { thread::spawn(move || sync::konachan::main(&recvr)); }
                        _       => { writeln!(&mut outf, "Error: function not found").unwrap(); }
                    };
                    writeln!(&mut outf, "ID: {}", id).unwrap();
                    id += 1;
                } else { writeln!(&mut outf, "Use sync <name>").unwrap(); }
            } else if input.starts_with("kill") {
                if let Some(input) = input.split_whitespace().collect::<Vec<_>>().get(1) {
                    if let Ok(id) = input.parse::<u32>() {
                        match senders.clone().get(&id) {
                            Some(sender) => { let _ = sender.send(()); senders.remove(&id); writeln!(&mut outf, "Killed {}", id).unwrap(); },
                            None => { writeln!(&mut outf ,"Error: No such id").unwrap(); }
                        }
                    }
                }
            }
        }

        remove_file("INPUT").unwrap();
        File::create("INPUT").unwrap();
        thread::sleep(Duration::new(15,0));
    }
}
<commit_msg>Убирать содержимое файлов логичней, чем пересоздавать их<commit_after>use std::io::{Read,Write};
use std::sync::mpsc;
use std::thread;
use std::fs::{OpenOptions};

use std::time::Duration;

use ::sync;

use std::collections::HashMap;

pub fn main() {
    let mut senders = HashMap::new();
    let mut id = 0;

    loop {
        let mut inf = OpenOptions::new().read(true).write(true).create(true).open("INPUT").unwrap();
        let mut outf = OpenOptions::new().append(true).create(true).open("OUTPUT").unwrap();

        let mut inputs = String::new();
        inf.read_to_string(&mut inputs).unwrap();
        let inputs = inputs.split("\n").collect::<Vec<_>>();

        for input in inputs {
            let input = input.trim();
            if input.starts_with("sync") {
                if let Some(func) = input.split_whitespace().collect::<Vec<_>>().get(1) {
                    let (sendr, recvr) = mpsc::channel::<()>();
                    senders.insert(id, sendr);
                    match *func {
                        "derpy" => { thread::spawn(move || sync::derpy::main(&recvr)); },
                        "e621"  => { thread::spawn(move || sync::e621::main(&recvr)); },
                        "dan"   => { thread::spawn(move || sync::danbooru::main(&recvr)); }
                        "kona"  => { thread::spawn(move || sync::konachan::main(&recvr)); }
                        _       => { writeln!(&mut outf, "Error: function not found").unwrap(); }
                    };
                    writeln!(&mut outf, "ID: {}", id).unwrap();
                    id += 1;
                } else { writeln!(&mut outf, "Use sync <name>").unwrap(); }
            } else if input.starts_with("kill") {
                if let Some(input) = input.split_whitespace().collect::<Vec<_>>().get(1) {
                    if let Ok(id) = input.parse::<u32>() {
                        match senders.clone().get(&id) {
                            Some(sender) => { let _ = sender.send(()); senders.remove(&id); writeln!(&mut outf, "Killed {}", id).unwrap(); },
                            None => { writeln!(&mut outf ,"Error: No such id").unwrap(); }
                        }
                    }
                }
            }
        }

        inf.set_len(0).unwrap();
        thread::sleep(Duration::new(15,0));
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate libimagrt;
extern crate libimagentrytag;
extern crate libimagutil;
#[macro_use] extern crate version;

use clap::Shell;
use libimagrt::runtime::Runtime;

/// This macro generates mods with the given '$modulename',
/// whose content is the file given with `$path`.
/// In this case, It is used specifically to include the
/// `ui.rs` files of the imag binaries.
/// The imag project (accidentally?) followed the convention
/// to write a `ui.rs` containing the function
/// `fn build_ui(app : App) -> App`.
/// This macro allows us to use the same named functions by
/// putting them each into their own module.
macro_rules! gen_mods_buildui {
    ($(($path:expr, $modulename:ident)$(,)*)*) => (
        $(
            mod $modulename {
                include!($path);
            }
         )*
        )
}

/// This macro reduces boilerplate code.
///
/// For example: `build_subcommand!("counter", imagcounter)`
/// will result in the following code:
/// ```ignore
/// imagcounter::build_ui(Runtime::get_default_cli_builder(
///     "counter",
///     &version!()[..],
///     "counter"))
/// ```
/// As for the `&version!()[..]` part, it does not matter
/// which version the subcommand is getting here, as the
/// output of this script is a completion script, which
/// does not contain information about the version at all.
macro_rules! build_subcommand {
    ($name:expr, $module:ident) => (
        $module::build_ui(Runtime::get_default_cli_builder(
                $name,
                &version!()[..],
                $name))
    )
}

// Actually generates the module.
gen_mods_buildui!(
    ("../imag-bookmark/src/ui.rs",  imagbookmark),
    ("../imag-counter/src/ui.rs",   imagcounter),
    ("../imag-diary/src/ui.rs",     imagdiary),
    ("../imag-link/src/ui.rs",      imaglink),
    ("../imag-notes/src/ui.rs",     imagnotes),
    ("../imag-ref/src/ui.rs",       imagref),
    ("../imag-store/src/ui.rs",     imagstore),
    ("../imag-tag/src/ui.rs",       imagtag),
    ("../imag-todo/src/ui.rs",      imagtodo),
    ("../imag-view/src/ui.rs",      imagview)
);

fn main() {
    // Make the `imag`-App...
    let mut app = Runtime::get_default_cli_builder(
        "imag",
        &version!()[..],
        "imag")
        // and add all the subapps as subcommands.
        .subcommand(build_subcommand!("bookmark",   imagbookmark))
        .subcommand(build_subcommand!("counter",    imagcounter))
        .subcommand(build_subcommand!("diary",      imagdiary))
        .subcommand(build_subcommand!("link",       imaglink))
        .subcommand(build_subcommand!("notes",      imagnotes))
        .subcommand(build_subcommand!("ref",        imagref))
        .subcommand(build_subcommand!("store",      imagstore))
        .subcommand(build_subcommand!("tag",        imagtag))
        .subcommand(build_subcommand!("todo",       imagtodo))
        .subcommand(build_subcommand!("view",       imagview));

    // Actually generates the completion files
    app.gen_completions("imag", Shell::Bash, env!("OUT_DIR"));
    app.gen_completions("imag", Shell::Fish, env!("OUT_DIR"));
    app.gen_completions("imag", Shell::Zsh, env!("OUT_DIR"));

}

<commit_msg>Remove removed crates from compl-gen build script<commit_after>extern crate clap;
extern crate libimagrt;
extern crate libimagentrytag;
extern crate libimagutil;
#[macro_use] extern crate version;

use clap::Shell;
use libimagrt::runtime::Runtime;

/// This macro generates mods with the given '$modulename',
/// whose content is the file given with `$path`.
/// In this case, It is used specifically to include the
/// `ui.rs` files of the imag binaries.
/// The imag project (accidentally?) followed the convention
/// to write a `ui.rs` containing the function
/// `fn build_ui(app : App) -> App`.
/// This macro allows us to use the same named functions by
/// putting them each into their own module.
macro_rules! gen_mods_buildui {
    ($(($path:expr, $modulename:ident)$(,)*)*) => (
        $(
            mod $modulename {
                include!($path);
            }
         )*
        )
}

/// This macro reduces boilerplate code.
///
/// For example: `build_subcommand!("counter", imagcounter)`
/// will result in the following code:
/// ```ignore
/// imagcounter::build_ui(Runtime::get_default_cli_builder(
///     "counter",
///     &version!()[..],
///     "counter"))
/// ```
/// As for the `&version!()[..]` part, it does not matter
/// which version the subcommand is getting here, as the
/// output of this script is a completion script, which
/// does not contain information about the version at all.
macro_rules! build_subcommand {
    ($name:expr, $module:ident) => (
        $module::build_ui(Runtime::get_default_cli_builder(
                $name,
                &version!()[..],
                $name))
    )
}

// Actually generates the module.
gen_mods_buildui!(
    ("../imag-link/src/ui.rs",      imaglink),
    ("../imag-notes/src/ui.rs",     imagnotes),
    ("../imag-ref/src/ui.rs",       imagref),
    ("../imag-store/src/ui.rs",     imagstore),
    ("../imag-tag/src/ui.rs",       imagtag),
    ("../imag-view/src/ui.rs",      imagview)
);

fn main() {
    // Make the `imag`-App...
    let mut app = Runtime::get_default_cli_builder(
        "imag",
        &version!()[..],
        "imag")
        // and add all the subapps as subcommands.
        .subcommand(build_subcommand!("link",       imaglink))
        .subcommand(build_subcommand!("notes",      imagnotes))
        .subcommand(build_subcommand!("ref",        imagref))
        .subcommand(build_subcommand!("store",      imagstore))
        .subcommand(build_subcommand!("tag",        imagtag))
        .subcommand(build_subcommand!("view",       imagview));

    // Actually generates the completion files
    app.gen_completions("imag", Shell::Bash, env!("OUT_DIR"));
    app.gen_completions("imag", Shell::Fish, env!("OUT_DIR"));
    app.gen_completions("imag", Shell::Zsh, env!("OUT_DIR"));

}

<|endoftext|>


<commit_before>//! Instruction shrinking.
//!
//! Sometimes there are multiple valid encodings for a given instruction. Cranelift often initially
//! chooses the largest one, because this typically provides the register allocator the most
//! flexibility. However, once register allocation is done, this is no longer important, and we
//! can switch to smaller encodings when possible.

use crate::ir::instructions::InstructionData;
use crate::ir::Function;
use crate::isa::TargetIsa;
use crate::regalloc::RegDiversions;
use crate::timing;
use log::debug;

/// Pick the smallest valid encodings for instructions.
pub fn shrink_instructions(func: &mut Function, isa: &dyn TargetIsa) {
    let _tt = timing::shrink_instructions();

    let encinfo = isa.encoding_info();
    let mut divert = RegDiversions::new();

    for ebb in func.layout.ebbs() {
        divert.clear();
        for inst in func.layout.ebb_insts(ebb) {
            let enc = func.encodings[inst];
            if enc.is_legal() {
                // regmove/regfill/regspill are special instructions with register immediates
                // that represented as normal operands, so the normal predicates below don't
                // handle them correctly.
                //
                // Also, they need to be presented to the `RegDiversions` to update the
                // location tracking.
                //
                // TODO: Eventually, we want the register allocator to avoid leaving these special
                // instructions behind, but for now, just temporarily avoid trying to shrink them.
                match func.dfg[inst] {
                    InstructionData::RegMove { .. }
                    | InstructionData::RegFill { .. }
                    | InstructionData::RegSpill { .. } => {
                        divert.apply(&func.dfg[inst]);
                        continue;
                    }
                    _ => (),
                }

                let ctrl_type = func.dfg.ctrl_typevar(inst);

                // Pick the last encoding with constraints that are satisfied.
                let best_enc = isa
                    .legal_encodings(func, &func.dfg[inst], ctrl_type)
                    .filter(|e| encinfo.constraints[e.recipe()].satisfied(inst, &divert, &func))
                    .min_by_key(|e| encinfo.byte_size(*e, inst, &divert, &func))
                    .unwrap();

                if best_enc != enc {
                    func.encodings[inst] = best_enc;

                    debug!(
                        "Shrunk [{}] to [{}] in {}, reducing the size from {} to {}",
                        encinfo.display(enc),
                        encinfo.display(best_enc),
                        func.dfg.display_inst(inst, isa),
                        encinfo.byte_size(enc, inst, &divert, &func),
                        encinfo.byte_size(best_enc, inst, &divert, &func)
                    );
                }
            }
        }
    }
}
<commit_msg>Shrink: Factor accesses of instruction data<commit_after>//! Instruction shrinking.
//!
//! Sometimes there are multiple valid encodings for a given instruction. Cranelift often initially
//! chooses the largest one, because this typically provides the register allocator the most
//! flexibility. However, once register allocation is done, this is no longer important, and we
//! can switch to smaller encodings when possible.

use crate::ir::instructions::InstructionData;
use crate::ir::Function;
use crate::isa::TargetIsa;
use crate::regalloc::RegDiversions;
use crate::timing;
use log::debug;

/// Pick the smallest valid encodings for instructions.
pub fn shrink_instructions(func: &mut Function, isa: &dyn TargetIsa) {
    let _tt = timing::shrink_instructions();

    let encinfo = isa.encoding_info();
    let mut divert = RegDiversions::new();

    for ebb in func.layout.ebbs() {
        divert.clear();
        for inst in func.layout.ebb_insts(ebb) {
            let enc = func.encodings[inst];
            if enc.is_legal() {
                // regmove/regfill/regspill are special instructions with register immediates
                // that represented as normal operands, so the normal predicates below don't
                // handle them correctly.
                //
                // Also, they need to be presented to the `RegDiversions` to update the
                // location tracking.
                //
                // TODO: Eventually, we want the register allocator to avoid leaving these special
                // instructions behind, but for now, just temporarily avoid trying to shrink them.
                let inst_data = &func.dfg[inst];
                match inst_data {
                    InstructionData::RegMove { .. }
                    | InstructionData::RegFill { .. }
                    | InstructionData::RegSpill { .. } => {
                        divert.apply(inst_data);
                        continue;
                    }
                    _ => (),
                }

                let ctrl_type = func.dfg.ctrl_typevar(inst);

                // Pick the last encoding with constraints that are satisfied.
                let best_enc = isa
                    .legal_encodings(func, &func.dfg[inst], ctrl_type)
                    .filter(|e| encinfo.constraints[e.recipe()].satisfied(inst, &divert, &func))
                    .min_by_key(|e| encinfo.byte_size(*e, inst, &divert, &func))
                    .unwrap();

                if best_enc != enc {
                    func.encodings[inst] = best_enc;

                    debug!(
                        "Shrunk [{}] to [{}] in {}, reducing the size from {} to {}",
                        encinfo.display(enc),
                        encinfo.display(best_enc),
                        func.dfg.display_inst(inst, isa),
                        encinfo.byte_size(enc, inst, &divert, &func),
                        encinfo.byte_size(best_enc, inst, &divert, &func)
                    );
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::ptr::null_mut;

use gdk_pixbuf_sys::{
    GdkPixbufFormat, GdkPixbufModule, GdkPixbufModulePattern, GdkPixbufModulePreparedFunc,
    GdkPixbufModuleSizeFunc, GdkPixbufModuleUpdatedFunc, GDK_PIXBUF_FORMAT_SCALABLE,
    GDK_PIXBUF_FORMAT_THREADSAFE,
};

use glib_sys::GError;
use gobject_sys::GObject;
use libc::{c_char, c_int, c_uint, c_void};

use gio::prelude::MemoryInputStreamExt;
use gio::MemoryInputStream;
use glib::Bytes;
use librsvg::Loader;

#[allow(non_camel_case_types)]
type c_bool = c_int;

use cstr::cstr;

struct SvgContext {
    size_func: GdkPixbufModuleSizeFunc,
    prep_func: GdkPixbufModulePreparedFunc,
    update_func: GdkPixbufModuleUpdatedFunc,
    user_data: *mut c_void,
    stream: MemoryInputStream,
}

#[no_mangle]
unsafe extern "C" fn begin_load(
    size_func: GdkPixbufModuleSizeFunc,
    prep_func: GdkPixbufModulePreparedFunc,
    update_func: GdkPixbufModuleUpdatedFunc,
    user_data: *mut c_void,
    error: *mut *mut GError,
) -> *mut c_void {
    if error != null_mut() {
        *error = null_mut();
    }

    let stream = MemoryInputStream::new();
    let ctx = Box::new(SvgContext {
        size_func,
        prep_func,
        update_func,
        user_data,
        stream,
    });

    Box::into_raw(ctx) as *mut c_void
}

#[no_mangle]
unsafe extern "C" fn load_increment(
    user_data: *mut c_void,
    buffer: *const u8,
    size: c_uint,
    error: *mut *mut GError,
) -> c_bool {
    if error != null_mut() {
        *error = null_mut();
    }

    let ctx = user_data as *mut SvgContext;

    let data = std::slice::from_raw_parts(buffer, size as usize);
    let data = data.to_vec();
    (&*ctx).stream.add_bytes(&Bytes::from_owned(data));
    1
}

fn argb_to_rgba(data: &mut Vec<u8>, width: usize, height: usize, stride: usize) {
    assert!((width * 4) >= stride);
    assert!((stride * height) <= data.len());
    for i in 0..height {
        let row_index = i * stride;
        for j in 0..width {
            let pixel_index = row_index + (j * 4);
            let tmp = data[pixel_index + 2];
            data[pixel_index + 2] = data[pixel_index];
            data[pixel_index] = tmp;
        }
    }
}

#[no_mangle]
unsafe extern "C" fn stop_load(user_data: *mut c_void, error: *mut *mut GError) -> c_int {
    let ctx = Box::from_raw(user_data as *mut SvgContext);
    if error != null_mut() {
        *error = null_mut();
    }

    fn _inner_stop_load(ctx: &Box<SvgContext>) -> Result<(Vec<u8>, i32, i32, i32), String> {
        let handle = Loader::new()
            .read_stream::<_, gio::File, gio::Cancellable>(&ctx.stream, None, None)
            .map_err(|e| e.to_string())?;

        let renderer = librsvg::CairoRenderer::new(&handle);
        let (w, h) = match renderer.intrinsic_size_in_pixels() {
            Some((w, h)) => (w, h),
            None => {
                return Err(String::from(
                    "Could not get intrinsic size in pixel of Cairo memory surface",
                ));
            }
        };

        let surface =
            cairo::ImageSurface::create(cairo::Format::ARgb32, w.ceil() as i32, h.ceil() as i32)
                .map_err(|e| e.to_string())?;

        let cr = cairo::Context::new(&surface).map_err(|e| e.to_string())?;

        renderer
            .render_document(
                &cr,
                &cairo::Rectangle {
                    x: 0.0,
                    y: 0.0,
                    width: w,
                    height: h,
                },
            )
            .map_err(|e| e.to_string())?;

        let w = w.ceil() as i32;
        let h = h.ceil() as i32;

        let stride = surface.stride();
        // The cairo::Context holds a reference to the surface which needs to be dropped to access the data
        std::mem::drop(cr);
        let sfc_data = surface.take_data().map_err(|e| e.to_string())?;
        let sfc_data = unsafe { std::slice::from_raw_parts(sfc_data.as_ptr(), sfc_data.len()) }; // This is just a slice to the canonical data
                                                                                // We need it as a mutable vector to move the alpha channel around
        let pb_data = sfc_data.to_vec();

        Ok((pb_data, w, h, stride))
    }

    let (mut pb_data, mut w, mut h, stride) = match _inner_stop_load(&ctx) {
        Ok(r) => r,
        Err(e) => {
            let gerr = glib::Error::new(gdk_pixbuf::PixbufError::Failed, &e.to_string());
            *error = gerr.into_raw();
            return 0;
        }
    };

    // GDK Pixbuf only support RGBA and Cairo only ARGB32, we swap channels around
    argb_to_rgba(&mut pb_data, w as usize, h as usize, stride as usize);

    // Vector length and capacity to rebuild and destroy the vector in destroy_fn
    let cb_data = Box::new((pb_data.len(), pb_data.capacity()));

    // Function to free the pixel data by rebuilding the Vec object
    #[no_mangle]
    unsafe extern "C" fn destroy_cb_foo(pixels: *mut u8, user_data: *mut c_void) {
        let data = Box::<(usize, usize)>::from_raw(user_data as *mut (usize, usize));
        Vec::from_raw_parts(pixels, data.0, data.1);
    }

    let pb_data = pb_data.leak::<'static>(); // Allocator stops tracking vector data
    let pixbuf = gdk_pixbuf_sys::gdk_pixbuf_new_from_data(
        pb_data.as_mut_ptr(),
        gdk_pixbuf_sys::GDK_COLORSPACE_RGB,
        1,
        8,
        w,
        h,
        stride,
        Some(destroy_cb_foo),
        Box::into_raw(cb_data) as *mut c_void,
    );
    if let Some(size_func) = ctx.size_func {
        size_func(&mut w as *mut i32, &mut h as *mut i32, ctx.user_data);
    }
    if let Some(update_func) = ctx.update_func {
        update_func(pixbuf, 0, 0, w, h, ctx.user_data);
    }
    if let Some(prep_func) = ctx.prep_func {
        prep_func(pixbuf, null_mut(), ctx.user_data);
    }

    // The module loader increases a ref so we drop the pixbuf here
    gobject_sys::g_object_unref(pixbuf as *mut GObject);

    1
}

#[no_mangle]
extern "C" fn fill_vtable(module: &mut GdkPixbufModule) {
    module.begin_load = Some(begin_load);
    module.stop_load = Some(stop_load);
    module.load_increment = Some(load_increment);
}

const SIGNATURE: [GdkPixbufModulePattern; 3] = [
    GdkPixbufModulePattern {
        prefix: cstr!(" <svg").as_ptr() as *mut c_char,
        mask: cstr!("*    ").as_ptr() as *mut c_char,
        relevance: 100,
    },
    GdkPixbufModulePattern {
        prefix: " <!DOCTYPE svg\0".as_ptr() as *mut c_char,
        mask: "*             \0".as_ptr() as *mut c_char,
        relevance: 100,
    },
    GdkPixbufModulePattern {
        prefix: std::ptr::null_mut(),
        mask: std::ptr::null_mut(),
        relevance: 0,
    },
];

const MIME_TYPES: [*const i8; 7] = [
    cstr!("image/svg+xml").as_ptr(),
    cstr!("image/svg").as_ptr(),
    cstr!("image/svg-xml").as_ptr(),
    cstr!("image/vnd.adobe.svg+xml").as_ptr(),
    cstr!("text/xml-svg").as_ptr(),
    cstr!("image/svg+xml-compressed").as_ptr(),
    std::ptr::null(),
];

const EXTENSIONS: [*const i8; 4] = [
    cstr!("svg").as_ptr(),
    cstr!("svgz").as_ptr(),
    cstr!("svg.gz").as_ptr(),
    std::ptr::null(),
];

#[no_mangle]
extern "C" fn fill_info(info: &mut GdkPixbufFormat) {
    info.name = cstr!("svg").as_ptr() as *mut c_char;
    info.signature = SIGNATURE.as_ptr() as *mut GdkPixbufModulePattern;
    info.description = cstr!("Scalable Vector Graphics").as_ptr() as *mut c_char; //TODO: Gettext this
    info.mime_types = MIME_TYPES.as_ptr() as *mut *mut c_char;
    info.extensions = EXTENSIONS.as_ptr() as *mut *mut c_char;
    info.flags = GDK_PIXBUF_FORMAT_SCALABLE | GDK_PIXBUF_FORMAT_THREADSAFE;
    info.license = cstr!("LGPL").as_ptr() as *mut c_char;
}

#[cfg(test)]
mod tests {
    use gdk_pixbuf_sys::{
        GdkPixbufFormat, GDK_PIXBUF_FORMAT_SCALABLE, GDK_PIXBUF_FORMAT_THREADSAFE,
    };

    use crate::{EXTENSIONS, MIME_TYPES};
    use std::ptr::{null, null_mut};

    fn pb_format_new() -> GdkPixbufFormat {
        let mut info = super::GdkPixbufFormat {
            name: null_mut(),
            signature: null_mut(),
            description: null_mut(),
            mime_types: null_mut(),
            extensions: null_mut(),
            flags: 0,
            license: null_mut(),
            disabled: 0,
            domain: null_mut(),
        };

        super::fill_info(&mut info);
        info
    }

    #[test]
    fn fill_info() {
        let info = pb_format_new();

        assert_ne!(info.name, null_mut());
        assert_ne!(info.signature, null_mut());
        assert_ne!(info.description, null_mut());
        assert_ne!(info.mime_types, null_mut());
        assert_ne!(info.extensions, null_mut());
        assert_eq!(
            info.flags,
            GDK_PIXBUF_FORMAT_SCALABLE | GDK_PIXBUF_FORMAT_THREADSAFE
        );
        assert_ne!(info.license, null_mut());
    }

    fn check_null_terminated_arr_cstrings(arr: &[*const i8]) {
        let n_strings = arr
            .iter()
            .filter(|e| e != &&null())
            .map(|e| {
                if e != &null() {
                    // We use strlen in all of them to ensure some safety
                    // We could use CStr instead but it'd be a bit more cumbersome
                    assert!(unsafe { libc::strlen(*e as *const i8) } > 0)
                }
            })
            .count(); // Count all non_null items

        // Ensure last item is null and is the only null item
        assert_eq!(n_strings, arr.len() - 1);
        assert!(arr.last().unwrap() == &null());
    }

    #[test]
    fn extensions_bounds() {
        check_null_terminated_arr_cstrings(&EXTENSIONS);
    }

    #[test]
    fn mime_bounds() {
        check_null_terminated_arr_cstrings(&MIME_TYPES)
    }

    #[test]
    fn signature() {
        let info = pb_format_new();

        for i in 0..2 {
            let ptr = unsafe { info.signature.offset(i) };
            if i == 2 {
                assert_eq!(unsafe { (*ptr).prefix }, null_mut());
                continue;
            } else {
                assert_ne!(unsafe { (*ptr).prefix }, null_mut());
                if unsafe { (*ptr).mask } != null_mut() {
                    // Mask can be null
                    assert_eq!(unsafe { libc::strlen((*ptr).prefix as *mut i8) }, unsafe {
                        libc::strlen((*ptr).mask as *mut i8)
                    });
                }
                // Relevance must be 0 to 100
                assert!(unsafe { (*ptr).relevance } >= 0);
                assert!(unsafe { (*ptr).relevance } <= 100);
            }
        }
    }

    const SVG_DATA: &'static str = r#"<svg
            width="100" height="100" viewBox="0 0 26.458333 26.458333" version="1.1" id="svg5" xmlns="http://www.w3.org/2000/svg"
            xmlns:svg="http://www.w3.org/2000/svg">
            <defs id="defs2" />
            <g id="layer1">
                <rect style="fill:#000000;stroke-width:0.130147" id="rect31"
                    width="26.458334" height="26.458334"
                    x="-3.1789145e-07" y="-3.1789145e-07" />
            </g>
        </svg>"#;

    #[test]
    fn minimal_svg() {
        unsafe extern "C" fn prep_cb(
            pb: *mut gdk_pixbuf_sys::GdkPixbuf,
            pba: *mut gdk_pixbuf_sys::GdkPixbufAnimation,
            user_data: *mut libc::c_void,
        ) {
            assert_eq!(user_data, null_mut());
            assert_eq!(pba, null_mut());

            let w = gdk_pixbuf_sys::gdk_pixbuf_get_width(pb);
            let h = gdk_pixbuf_sys::gdk_pixbuf_get_height(pb);
            let stride = gdk_pixbuf_sys::gdk_pixbuf_get_rowstride(pb);
            assert_eq!(w, 100);
            assert_eq!(h, 100);

            let pixels = gdk_pixbuf_sys::gdk_pixbuf_get_pixels(pb);

            // Upper left pixel, black with full opacity #000000ff
            assert_eq!(*pixels, 0x00);
            assert_eq!(*pixels.offset(1), 0x00);
            assert_eq!(*pixels.offset(2), 0x00);
            assert_eq!(*pixels.offset(3), 0xff);

            // Bottom left pixel
            assert_eq!(*pixels.offset((stride * 99) as isize), 0x00);
            assert_eq!(*pixels.offset((stride * 99) as isize + 1), 0x00);
            assert_eq!(*pixels.offset((stride * 99) as isize + 2), 0x00);
            assert_eq!(*pixels.offset((stride * 99) as isize + 3), 0xff);
        }

        let ctx = unsafe { crate::begin_load(None, Some(prep_cb), None, null_mut(), null_mut()) };
        assert_ne!(ctx, null_mut());

        let inc = unsafe {
            crate::load_increment(ctx, SVG_DATA.as_ptr(), SVG_DATA.len() as u32, null_mut())
        };
        assert_ne!(inc, 0);

        unsafe { crate::stop_load(ctx, null_mut()) };
    }
}
<commit_msg>use different values for different channels to ensure pixel order<commit_after>use std::ptr::null_mut;

use gdk_pixbuf_sys::{
    GdkPixbufFormat, GdkPixbufModule, GdkPixbufModulePattern, GdkPixbufModulePreparedFunc,
    GdkPixbufModuleSizeFunc, GdkPixbufModuleUpdatedFunc, GDK_PIXBUF_FORMAT_SCALABLE,
    GDK_PIXBUF_FORMAT_THREADSAFE,
};

use glib_sys::GError;
use gobject_sys::GObject;
use libc::{c_char, c_int, c_uint, c_void};

use gio::prelude::MemoryInputStreamExt;
use gio::MemoryInputStream;
use glib::Bytes;
use librsvg::Loader;

#[allow(non_camel_case_types)]
type c_bool = c_int;

use cstr::cstr;

struct SvgContext {
    size_func: GdkPixbufModuleSizeFunc,
    prep_func: GdkPixbufModulePreparedFunc,
    update_func: GdkPixbufModuleUpdatedFunc,
    user_data: *mut c_void,
    stream: MemoryInputStream,
}

#[no_mangle]
unsafe extern "C" fn begin_load(
    size_func: GdkPixbufModuleSizeFunc,
    prep_func: GdkPixbufModulePreparedFunc,
    update_func: GdkPixbufModuleUpdatedFunc,
    user_data: *mut c_void,
    error: *mut *mut GError,
) -> *mut c_void {
    if error != null_mut() {
        *error = null_mut();
    }

    let stream = MemoryInputStream::new();
    let ctx = Box::new(SvgContext {
        size_func,
        prep_func,
        update_func,
        user_data,
        stream,
    });

    Box::into_raw(ctx) as *mut c_void
}

#[no_mangle]
unsafe extern "C" fn load_increment(
    user_data: *mut c_void,
    buffer: *const u8,
    size: c_uint,
    error: *mut *mut GError,
) -> c_bool {
    if error != null_mut() {
        *error = null_mut();
    }

    let ctx = user_data as *mut SvgContext;

    let data = std::slice::from_raw_parts(buffer, size as usize);
    let data = data.to_vec();
    (&*ctx).stream.add_bytes(&Bytes::from_owned(data));
    1
}

fn argb_to_rgba(data: &mut Vec<u8>, width: usize, height: usize, stride: usize) {
    assert!((width * 4) >= stride);
    assert!((stride * height) <= data.len());
    for i in 0..height {
        let row_index = i * stride;
        for j in 0..width {
            let pixel_index = row_index + (j * 4);
            let tmp = data[pixel_index + 2];
            data[pixel_index + 2] = data[pixel_index];
            data[pixel_index] = tmp;
        }
    }
}

#[no_mangle]
unsafe extern "C" fn stop_load(user_data: *mut c_void, error: *mut *mut GError) -> c_int {
    let ctx = Box::from_raw(user_data as *mut SvgContext);
    if error != null_mut() {
        *error = null_mut();
    }

    fn _inner_stop_load(ctx: &Box<SvgContext>) -> Result<(Vec<u8>, i32, i32, i32), String> {
        let handle = Loader::new()
            .read_stream::<_, gio::File, gio::Cancellable>(&ctx.stream, None, None)
            .map_err(|e| e.to_string())?;

        let renderer = librsvg::CairoRenderer::new(&handle);
        let (w, h) = match renderer.intrinsic_size_in_pixels() {
            Some((w, h)) => (w, h),
            None => {
                return Err(String::from(
                    "Could not get intrinsic size in pixel of Cairo memory surface",
                ));
            }
        };

        let surface =
            cairo::ImageSurface::create(cairo::Format::ARgb32, w.ceil() as i32, h.ceil() as i32)
                .map_err(|e| e.to_string())?;

        let cr = cairo::Context::new(&surface).map_err(|e| e.to_string())?;

        renderer
            .render_document(
                &cr,
                &cairo::Rectangle {
                    x: 0.0,
                    y: 0.0,
                    width: w,
                    height: h,
                },
            )
            .map_err(|e| e.to_string())?;

        let w = w.ceil() as i32;
        let h = h.ceil() as i32;

        let stride = surface.stride();
        // The cairo::Context holds a reference to the surface which needs to be dropped to access the data
        std::mem::drop(cr);
        let sfc_data = surface.take_data().map_err(|e| e.to_string())?;
        let sfc_data = unsafe { std::slice::from_raw_parts(sfc_data.as_ptr(), sfc_data.len()) }; // This is just a slice to the canonical data
                                                                                // We need it as a mutable vector to move the alpha channel around
        let pb_data = sfc_data.to_vec();

        Ok((pb_data, w, h, stride))
    }

    let (mut pb_data, mut w, mut h, stride) = match _inner_stop_load(&ctx) {
        Ok(r) => r,
        Err(e) => {
            let gerr = glib::Error::new(gdk_pixbuf::PixbufError::Failed, &e.to_string());
            *error = gerr.into_raw();
            return 0;
        }
    };

    // GDK Pixbuf only support RGBA and Cairo only ARGB32, we swap channels around
    argb_to_rgba(&mut pb_data, w as usize, h as usize, stride as usize);

    // Vector length and capacity to rebuild and destroy the vector in destroy_fn
    let cb_data = Box::new((pb_data.len(), pb_data.capacity()));

    // Function to free the pixel data by rebuilding the Vec object
    #[no_mangle]
    unsafe extern "C" fn destroy_cb_foo(pixels: *mut u8, user_data: *mut c_void) {
        let data = Box::<(usize, usize)>::from_raw(user_data as *mut (usize, usize));
        Vec::from_raw_parts(pixels, data.0, data.1);
    }

    let pb_data = pb_data.leak::<'static>(); // Allocator stops tracking vector data
    let pixbuf = gdk_pixbuf_sys::gdk_pixbuf_new_from_data(
        pb_data.as_mut_ptr(),
        gdk_pixbuf_sys::GDK_COLORSPACE_RGB,
        1,
        8,
        w,
        h,
        stride,
        Some(destroy_cb_foo),
        Box::into_raw(cb_data) as *mut c_void,
    );
    if let Some(size_func) = ctx.size_func {
        size_func(&mut w as *mut i32, &mut h as *mut i32, ctx.user_data);
    }
    if let Some(update_func) = ctx.update_func {
        update_func(pixbuf, 0, 0, w, h, ctx.user_data);
    }
    if let Some(prep_func) = ctx.prep_func {
        prep_func(pixbuf, null_mut(), ctx.user_data);
    }

    // The module loader increases a ref so we drop the pixbuf here
    gobject_sys::g_object_unref(pixbuf as *mut GObject);

    1
}

#[no_mangle]
extern "C" fn fill_vtable(module: &mut GdkPixbufModule) {
    module.begin_load = Some(begin_load);
    module.stop_load = Some(stop_load);
    module.load_increment = Some(load_increment);
}

const SIGNATURE: [GdkPixbufModulePattern; 3] = [
    GdkPixbufModulePattern {
        prefix: cstr!(" <svg").as_ptr() as *mut c_char,
        mask: cstr!("*    ").as_ptr() as *mut c_char,
        relevance: 100,
    },
    GdkPixbufModulePattern {
        prefix: " <!DOCTYPE svg\0".as_ptr() as *mut c_char,
        mask: "*             \0".as_ptr() as *mut c_char,
        relevance: 100,
    },
    GdkPixbufModulePattern {
        prefix: std::ptr::null_mut(),
        mask: std::ptr::null_mut(),
        relevance: 0,
    },
];

const MIME_TYPES: [*const i8; 7] = [
    cstr!("image/svg+xml").as_ptr(),
    cstr!("image/svg").as_ptr(),
    cstr!("image/svg-xml").as_ptr(),
    cstr!("image/vnd.adobe.svg+xml").as_ptr(),
    cstr!("text/xml-svg").as_ptr(),
    cstr!("image/svg+xml-compressed").as_ptr(),
    std::ptr::null(),
];

const EXTENSIONS: [*const i8; 4] = [
    cstr!("svg").as_ptr(),
    cstr!("svgz").as_ptr(),
    cstr!("svg.gz").as_ptr(),
    std::ptr::null(),
];

#[no_mangle]
extern "C" fn fill_info(info: &mut GdkPixbufFormat) {
    info.name = cstr!("svg").as_ptr() as *mut c_char;
    info.signature = SIGNATURE.as_ptr() as *mut GdkPixbufModulePattern;
    info.description = cstr!("Scalable Vector Graphics").as_ptr() as *mut c_char; //TODO: Gettext this
    info.mime_types = MIME_TYPES.as_ptr() as *mut *mut c_char;
    info.extensions = EXTENSIONS.as_ptr() as *mut *mut c_char;
    info.flags = GDK_PIXBUF_FORMAT_SCALABLE | GDK_PIXBUF_FORMAT_THREADSAFE;
    info.license = cstr!("LGPL").as_ptr() as *mut c_char;
}

#[cfg(test)]
mod tests {
    use gdk_pixbuf_sys::{
        GdkPixbufFormat, GDK_PIXBUF_FORMAT_SCALABLE, GDK_PIXBUF_FORMAT_THREADSAFE,
    };

    use crate::{EXTENSIONS, MIME_TYPES};
    use std::ptr::{null, null_mut};

    fn pb_format_new() -> GdkPixbufFormat {
        let mut info = super::GdkPixbufFormat {
            name: null_mut(),
            signature: null_mut(),
            description: null_mut(),
            mime_types: null_mut(),
            extensions: null_mut(),
            flags: 0,
            license: null_mut(),
            disabled: 0,
            domain: null_mut(),
        };

        super::fill_info(&mut info);
        info
    }

    #[test]
    fn fill_info() {
        let info = pb_format_new();

        assert_ne!(info.name, null_mut());
        assert_ne!(info.signature, null_mut());
        assert_ne!(info.description, null_mut());
        assert_ne!(info.mime_types, null_mut());
        assert_ne!(info.extensions, null_mut());
        assert_eq!(
            info.flags,
            GDK_PIXBUF_FORMAT_SCALABLE | GDK_PIXBUF_FORMAT_THREADSAFE
        );
        assert_ne!(info.license, null_mut());
    }

    fn check_null_terminated_arr_cstrings(arr: &[*const i8]) {
        let n_strings = arr
            .iter()
            .filter(|e| e != &&null())
            .map(|e| {
                if e != &null() {
                    // We use strlen in all of them to ensure some safety
                    // We could use CStr instead but it'd be a bit more cumbersome
                    assert!(unsafe { libc::strlen(*e as *const i8) } > 0)
                }
            })
            .count(); // Count all non_null items

        // Ensure last item is null and is the only null item
        assert_eq!(n_strings, arr.len() - 1);
        assert!(arr.last().unwrap() == &null());
    }

    #[test]
    fn extensions_bounds() {
        check_null_terminated_arr_cstrings(&EXTENSIONS);
    }

    #[test]
    fn mime_bounds() {
        check_null_terminated_arr_cstrings(&MIME_TYPES)
    }

    #[test]
    fn signature() {
        let info = pb_format_new();

        for i in 0..2 {
            let ptr = unsafe { info.signature.offset(i) };
            if i == 2 {
                assert_eq!(unsafe { (*ptr).prefix }, null_mut());
                continue;
            } else {
                assert_ne!(unsafe { (*ptr).prefix }, null_mut());
                if unsafe { (*ptr).mask } != null_mut() {
                    // Mask can be null
                    assert_eq!(unsafe { libc::strlen((*ptr).prefix as *mut i8) }, unsafe {
                        libc::strlen((*ptr).mask as *mut i8)
                    });
                }
                // Relevance must be 0 to 100
                assert!(unsafe { (*ptr).relevance } >= 0);
                assert!(unsafe { (*ptr).relevance } <= 100);
            }
        }
    }

    const SVG_DATA: &'static str = r#"<svg
            width="100" height="100" viewBox="0 0 26.458333 26.458333" version="1.1" id="svg5" xmlns="http://www.w3.org/2000/svg"
            xmlns:svg="http://www.w3.org/2000/svg">
            <defs id="defs2" />
            <g id="layer1">
                <rect style="fill:#aa1144;stroke-width:0.130147" id="rect31"
                    width="26.458334" height="26.458334"
                    x="-3.1789145e-07" y="-3.1789145e-07" />
            </g>
        </svg>"#;

    #[test]
    fn minimal_svg() {
        unsafe extern "C" fn prep_cb(
            pb: *mut gdk_pixbuf_sys::GdkPixbuf,
            pba: *mut gdk_pixbuf_sys::GdkPixbufAnimation,
            user_data: *mut libc::c_void,
        ) {
            assert_eq!(user_data, null_mut());
            assert_eq!(pba, null_mut());

            let w = gdk_pixbuf_sys::gdk_pixbuf_get_width(pb);
            let h = gdk_pixbuf_sys::gdk_pixbuf_get_height(pb);
            let stride = gdk_pixbuf_sys::gdk_pixbuf_get_rowstride(pb);
            assert_eq!(w, 100);
            assert_eq!(h, 100);

            let pixels = gdk_pixbuf_sys::gdk_pixbuf_get_pixels(pb);

            // Upper left pixel, black with full opacity #000000ff
            assert_eq!(*pixels, 0xaa);
            assert_eq!(*pixels.offset(1), 0x11);
            assert_eq!(*pixels.offset(2), 0x44);
            assert_eq!(*pixels.offset(3), 0xff);

            // Bottom left pixel
            assert_eq!(*pixels.offset((stride * 99) as isize), 0xaa);
            assert_eq!(*pixels.offset((stride * 99) as isize + 1), 0x11);
            assert_eq!(*pixels.offset((stride * 99) as isize + 2), 0x44);
            assert_eq!(*pixels.offset((stride * 99) as isize + 3), 0xff);
        }

        let ctx = unsafe { crate::begin_load(None, Some(prep_cb), None, null_mut(), null_mut()) };
        assert_ne!(ctx, null_mut());

        let inc = unsafe {
            crate::load_increment(ctx, SVG_DATA.as_ptr(), SVG_DATA.len() as u32, null_mut())
        };
        assert_ne!(inc, 0);

        unsafe { crate::stop_load(ctx, null_mut()) };
    }
}
<|endoftext|>


<commit_before>/*
type characteristic =
    | IMAGE_FILE_RELOCS_STRIPPED
    | IMAGE_FILE_EXECUTABLE_IMAGE
    | IMAGE_FILE_LINE_NUMS_STRIPPED
    | IMAGE_FILE_LOCAL_SYMS_STRIPPED
    | IMAGE_FILE_AGGRESSIVE_WS_TRIM
    | IMAGE_FILE_LARGE_ADDRESS_AWARE
    | RESERVED
    | IMAGE_FILE_BYTES_REVERSED_LO
    | IMAGE_FILE_32BIT_MACHINE
    | IMAGE_FILE_DEBUG_STRIPPED
    | IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP
    | IMAGE_FILE_NET_RUN_FROM_SWAP
    | IMAGE_FILE_SYSTEM
    | IMAGE_FILE_DLL
    | IMAGE_FILE_UP_SYSTEM_ONLY
    | IMAGE_FILE_BYTES_REVERSED_HI
    | UNKNOWN of int

let get_characteristic =
  function
  | 0x0001 -> IMAGE_FILE_RELOCS_STRIPPED
  | 0x0002 -> IMAGE_FILE_EXECUTABLE_IMAGE
  | 0x0004 -> IMAGE_FILE_LINE_NUMS_STRIPPED
  | 0x0008 -> IMAGE_FILE_LOCAL_SYMS_STRIPPED
  | 0x0010 -> IMAGE_FILE_AGGRESSIVE_WS_TRIM
  | 0x0020 -> IMAGE_FILE_LARGE_ADDRESS_AWARE
  | 0x0040 -> RESERVED
  | 0x0080 -> IMAGE_FILE_BYTES_REVERSED_LO
  | 0x0100 -> IMAGE_FILE_32BIT_MACHINE
  | 0x0200 -> IMAGE_FILE_DEBUG_STRIPPED
  | 0x0400 -> IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP
  | 0x0800 -> IMAGE_FILE_NET_RUN_FROM_SWAP
  | 0x1000 -> IMAGE_FILE_SYSTEM
  | 0x2000 -> IMAGE_FILE_DLL
  | 0x4000 -> IMAGE_FILE_UP_SYSTEM_ONLY
  | 0x8000 -> IMAGE_FILE_BYTES_REVERSED_HI
  | x -> UNKNOWN x

let characteristic_to_int =
  function
  | IMAGE_FILE_RELOCS_STRIPPED -> 0x0001
  | IMAGE_FILE_EXECUTABLE_IMAGE -> 0x0002
  | IMAGE_FILE_LINE_NUMS_STRIPPED -> 0x0004
  | IMAGE_FILE_LOCAL_SYMS_STRIPPED -> 0x0008
  | IMAGE_FILE_AGGRESSIVE_WS_TRIM -> 0x0010
  | IMAGE_FILE_LARGE_ADDRESS_AWARE -> 0x0020
  | RESERVED -> 0x0040
  | IMAGE_FILE_BYTES_REVERSED_LO -> 0x0080
  | IMAGE_FILE_32BIT_MACHINE -> 0x0100
  | IMAGE_FILE_DEBUG_STRIPPED -> 0x0200
  | IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP -> 0x0400
  | IMAGE_FILE_NET_RUN_FROM_SWAP -> 0x0800
  | IMAGE_FILE_SYSTEM -> 0x1000
  | IMAGE_FILE_DLL -> 0x2000
  | IMAGE_FILE_UP_SYSTEM_ONLY -> 0x4000
  | IMAGE_FILE_BYTES_REVERSED_HI -> 0x8000
  | UNKNOWN x -> x

let characteristic_to_string =
  function
  | IMAGE_FILE_RELOCS_STRIPPED -> "IMAGE_FILE_RELOCS_STRIPPED"
  | IMAGE_FILE_EXECUTABLE_IMAGE -> "IMAGE_FILE_EXECUTABLE_IMAGE"
  | IMAGE_FILE_LINE_NUMS_STRIPPED -> "IMAGE_FILE_LINE_NUMS_STRIPPED"
  | IMAGE_FILE_LOCAL_SYMS_STRIPPED -> "IMAGE_FILE_LOCAL_SYMS_STRIPPED"
  | IMAGE_FILE_AGGRESSIVE_WS_TRIM -> "IMAGE_FILE_AGGRESSIVE_WS_TRIM"
  | IMAGE_FILE_LARGE_ADDRESS_AWARE -> "IMAGE_FILE_LARGE_ADDRESS_AWARE"
  | RESERVED -> "RESERVED"
  | IMAGE_FILE_BYTES_REVERSED_LO -> "IMAGE_FILE_BYTES_REVERSED_LO"
  | IMAGE_FILE_32BIT_MACHINE -> "IMAGE_FILE_32BIT_MACHINE"
  | IMAGE_FILE_DEBUG_STRIPPED -> "IMAGE_FILE_DEBUG_STRIPPED"
  | IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP -> "IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP"
  | IMAGE_FILE_NET_RUN_FROM_SWAP -> "IMAGE_FILE_NET_RUN_FROM_SWAP"
  | IMAGE_FILE_SYSTEM -> "IMAGE_FILE_SYSTEM"
  | IMAGE_FILE_DLL -> "IMAGE_FILE_DLL"
  | IMAGE_FILE_UP_SYSTEM_ONLY -> "IMAGE_FILE_UP_SYSTEM_ONLY"
  | IMAGE_FILE_BYTES_REVERSED_HI -> "IMAGE_FILE_BYTES_REVERSED_HI"
  | UNKNOWN x -> Printf.sprintf "UNKNOWN_CHARACTERISTIC 0x%x" x

let is_dll characteristics =
  let characteristic = characteristic_to_int IMAGE_FILE_DLL in
  characteristics land characteristic = characteristic

let has characteristic characteristics =
  let characteristic = characteristic_to_int characteristic in
  characteristics land characteristic = characteristic

(* TODO: this is a mad hack *)
let show_type characteristics =
  if (has IMAGE_FILE_DLL characteristics) then "DLL"
  else if (has IMAGE_FILE_EXECUTABLE_IMAGE characteristics) then "EXE"
  else "MANY"                   (* print all *)
 */

pub const IMAGE_FILE_DLL: u16 = 0x2000;
pub const IMAGE_FILE_EXECUTABLE_IMAGE: u16 = 0x2;

pub fn is_dll(characteristics: u16) -> bool {
  characteristics & IMAGE_FILE_DLL == IMAGE_FILE_DLL
}

pub fn is_exe(characteristics: u16) -> bool {
  characteristics & IMAGE_FILE_EXECUTABLE_IMAGE == IMAGE_FILE_EXECUTABLE_IMAGE
}
<commit_msg>pe: add more characteristic constants<commit_after>/*
type characteristic =
    | IMAGE_FILE_RELOCS_STRIPPED
    | IMAGE_FILE_EXECUTABLE_IMAGE
    | IMAGE_FILE_LINE_NUMS_STRIPPED
    | IMAGE_FILE_LOCAL_SYMS_STRIPPED
    | IMAGE_FILE_AGGRESSIVE_WS_TRIM
    | IMAGE_FILE_LARGE_ADDRESS_AWARE
    | RESERVED
    | IMAGE_FILE_BYTES_REVERSED_LO
    | IMAGE_FILE_32BIT_MACHINE
    | IMAGE_FILE_DEBUG_STRIPPED
    | IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP
    | IMAGE_FILE_NET_RUN_FROM_SWAP
    | IMAGE_FILE_SYSTEM
    | IMAGE_FILE_DLL
    | IMAGE_FILE_UP_SYSTEM_ONLY
    | IMAGE_FILE_BYTES_REVERSED_HI
    | UNKNOWN of int

let get_characteristic =
  function
  | 0x0001 -> IMAGE_FILE_RELOCS_STRIPPED
  | 0x0002 -> IMAGE_FILE_EXECUTABLE_IMAGE
  | 0x0004 -> IMAGE_FILE_LINE_NUMS_STRIPPED
  | 0x0008 -> IMAGE_FILE_LOCAL_SYMS_STRIPPED
  | 0x0010 -> IMAGE_FILE_AGGRESSIVE_WS_TRIM
  | 0x0020 -> IMAGE_FILE_LARGE_ADDRESS_AWARE
  | 0x0040 -> RESERVED
  | 0x0080 -> IMAGE_FILE_BYTES_REVERSED_LO
  | 0x0100 -> IMAGE_FILE_32BIT_MACHINE
  | 0x0200 -> IMAGE_FILE_DEBUG_STRIPPED
  | 0x0400 -> IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP
  | 0x0800 -> IMAGE_FILE_NET_RUN_FROM_SWAP
  | 0x1000 -> IMAGE_FILE_SYSTEM
  | 0x2000 -> IMAGE_FILE_DLL
  | 0x4000 -> IMAGE_FILE_UP_SYSTEM_ONLY
  | 0x8000 -> IMAGE_FILE_BYTES_REVERSED_HI
  | x -> UNKNOWN x

let characteristic_to_string =
  function
  | IMAGE_FILE_RELOCS_STRIPPED -> "IMAGE_FILE_RELOCS_STRIPPED"
  | IMAGE_FILE_EXECUTABLE_IMAGE -> "IMAGE_FILE_EXECUTABLE_IMAGE"
  | IMAGE_FILE_LINE_NUMS_STRIPPED -> "IMAGE_FILE_LINE_NUMS_STRIPPED"
  | IMAGE_FILE_LOCAL_SYMS_STRIPPED -> "IMAGE_FILE_LOCAL_SYMS_STRIPPED"
  | IMAGE_FILE_AGGRESSIVE_WS_TRIM -> "IMAGE_FILE_AGGRESSIVE_WS_TRIM"
  | IMAGE_FILE_LARGE_ADDRESS_AWARE -> "IMAGE_FILE_LARGE_ADDRESS_AWARE"
  | RESERVED -> "RESERVED"
  | IMAGE_FILE_BYTES_REVERSED_LO -> "IMAGE_FILE_BYTES_REVERSED_LO"
  | IMAGE_FILE_32BIT_MACHINE -> "IMAGE_FILE_32BIT_MACHINE"
  | IMAGE_FILE_DEBUG_STRIPPED -> "IMAGE_FILE_DEBUG_STRIPPED"
  | IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP -> "IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP"
  | IMAGE_FILE_NET_RUN_FROM_SWAP -> "IMAGE_FILE_NET_RUN_FROM_SWAP"
  | IMAGE_FILE_SYSTEM -> "IMAGE_FILE_SYSTEM"
  | IMAGE_FILE_DLL -> "IMAGE_FILE_DLL"
  | IMAGE_FILE_UP_SYSTEM_ONLY -> "IMAGE_FILE_UP_SYSTEM_ONLY"
  | IMAGE_FILE_BYTES_REVERSED_HI -> "IMAGE_FILE_BYTES_REVERSED_HI"
  | UNKNOWN x -> Printf.sprintf "UNKNOWN_CHARACTERISTIC 0x%x" x

let is_dll characteristics =
  let characteristic = characteristic_to_int IMAGE_FILE_DLL in
  characteristics land characteristic = characteristic

let has characteristic characteristics =
  let characteristic = characteristic_to_int characteristic in
  characteristics land characteristic = characteristic

(* TODO: this is a mad hack *)
let show_type characteristics =
  if (has IMAGE_FILE_DLL characteristics) then "DLL"
  else if (has IMAGE_FILE_EXECUTABLE_IMAGE characteristics) then "EXE"
  else "MANY"                   (* print all *)
 */

pub const IMAGE_FILE_RELOCS_STRIPPED: u16 = 0x0001;
pub const IMAGE_FILE_EXECUTABLE_IMAGE: u16 = 0x0002;
pub const IMAGE_FILE_LINE_NUMS_STRIPPED: u16 = 0x0004;
pub const IMAGE_FILE_LOCAL_SYMS_STRIPPED: u16 = 0x0008;
pub const IMAGE_FILE_AGGRESSIVE_WS_TRIM: u16 = 0x0010;
pub const IMAGE_FILE_LARGE_ADDRESS_AWARE: u16 = 0x0020;
pub const RESERVED: u16 = 0x0040;
pub const IMAGE_FILE_BYTES_REVERSED_LO: u16 = 0x0080;
pub const IMAGE_FILE_32BIT_MACHINE: u16 = 0x0100;
pub const IMAGE_FILE_DEBUG_STRIPPED: u16 = 0x0200;
pub const IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP: u16 = 0x0400;
pub const IMAGE_FILE_NET_RUN_FROM_SWAP: u16 = 0x0800;
pub const IMAGE_FILE_SYSTEM: u16 = 0x1000;
pub const IMAGE_FILE_DLL: u16 = 0x2000;
pub const IMAGE_FILE_UP_SYSTEM_ONLY: u16 = 0x4000;
pub const IMAGE_FILE_BYTES_REVERSED_HI: u16 = 0x8000;

pub fn is_dll(characteristics: u16) -> bool {
  characteristics & IMAGE_FILE_DLL == IMAGE_FILE_DLL
}

pub fn is_exe(characteristics: u16) -> bool {
  characteristics & IMAGE_FILE_EXECUTABLE_IMAGE == IMAGE_FILE_EXECUTABLE_IMAGE
}
<|endoftext|>