<commit_before>use ast;
use lexer;
use parser;

use interp::env;
use interp::types;

use core::hashmap::linear;
use core::to_bytes;

/*
 * aster - AST EvaulatoR
 *
 * aster evaluates a Prismo program via reduction of the AST.
 *
 * "It's pretty terrible."
 * -- Tony, 2013
 */

impl to_bytes::IterBytes for ast::RecordName {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
        match self {
            &ast::RecordName(n, s) => (n, s).iter_bytes(lsb0, f)
        }
    }
}

impl to_bytes::IterBytes for ast::DottedName {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
        match self {
            &ast::DottedName(s) => s.iter_bytes(lsb0, f)
        }
    }
}

pub struct Interp {
    record_types: @mut linear::LinearMap<@ast::RecordName, @ast::RecordDeclaration>,
    import_paths: @[Path],
    root: @mut env::Env<Interp>,
    argv: @[@str],
    filename: @str,
    current_frame: @mut option::Option<@mut Frame>
}

pub impl Interp {
    pub fn new(import_paths: @[Path], argv: @[@str], filename: @str) -> Interp {
        Interp {
            record_types: @mut linear::LinearMap::new(),
            import_paths: import_paths,
            root: @mut env::Env::new(),
            argv: argv,
            filename: filename,
            current_frame: @mut option::None
        }
    }
}

fn wind(interp: @mut Interp, env: @mut env::Env<Interp>, lineno: uint) -> @mut Frame {
    // allocate a new frame
    let frame = @mut Frame::new(interp, env, interp.filename, lineno);
    interp.current_frame = @mut option::Some(frame);
    frame
}

fn unwind(interp: @mut Interp) -> () {
    interp.current_frame = match *interp.current_frame {
        option::None => @mut option::None,
        option::Some(frame) => frame.parent
    };
}

pub struct Frame {
    parent: @mut option::Option<@mut Frame>,
    env: @mut env::Env<Interp>,
    file: @str,
    lineno: uint,
    exception: @mut option::Option<@mut types::Val<Interp>>
}

pub impl Frame {
    pub fn new(interp: @mut Interp, env: @mut env::Env<Interp>, file: @str, lineno: uint) -> Frame {
        Frame {
            parent: interp.current_frame,
            env: env,
            file: file,
            lineno: lineno,
            exception: @mut option::None
        }
    }
}

pub fn import_module(interp: @mut Interp, name: &ast::DottedName, qualified: bool) -> () {
    let module_parts = (**name).to_owned().map(|x| (*x).to_owned());
    let mut parts = copy module_parts;

    vec::reverse(parts);
    let module_name = copy parts[0];
    let filename = fmt!("%s.pr", module_name);
    parts = vec::tail(parts).to_owned();
    vec::reverse(parts);

    let mut found = false;
    let mut paths = interp.import_paths.to_owned();

    for paths.each_mut |import_path| {
        // make a path inside the import path and check if that exists
        let base_path = (copy *import_path).push_many(parts);
        let path = base_path.push(filename);

        if os::path_exists(&path) {
            // make a copy of the import paths then give them to a new sub-interpreter
            let mut import_paths1 = interp.import_paths.to_owned();
            import_paths1.unshift(base_path);

            let interp1 = @mut Interp::new(at_vec::from_owned(import_paths1), interp.argv, path.to_str().to_managed());

            // run the file in the sub-interpreter
            run_file(interp1, &path);

            if qualified {
                let module_name = ast::Sym(module_name.to_managed());

                // qualified imports symbols from child interpreter into a module
                env::declare(interp.root, &module_name,
                             @mut types::Module(interp1.root.vars));

                for interp1.record_types.each_key |k| {
                    interp.record_types.insert(match *k {
                        @ast::RecordName(modu, name) => @ast::RecordName(@ast::DottedName(**modu + [module_name]), name)
                    }, *interp1.record_types.find(k).unwrap());
                }
            } else {
                // otherwise we just plop all the symbols in
                for interp1.root.vars.each_key |k| {
                    env::declare(interp.root, k, *interp1.root.vars.find(k).unwrap());
                }

                // import record types
                for interp1.record_types.each_key |k| {
                    interp.record_types.insert(*k, *interp1.record_types.find(k).unwrap());
                }
            }

            found = true;
            break;
        }
    };

    if !found {
        fail!(fmt!("couldn't import module %s", str::connect(module_parts, ".")))
    };
}

fn unify_pattern_basic(interp: @mut Interp, env: @mut env::Env<Interp>, pat: &ast::Pat, val: @mut types::Val<Interp>) -> bool {
    // perform pattern matching of basic patterns -- if a match fails, we leave all the symbols in
    // scope and not care. this is pretty bad.
    match *pat {
        ast::AnyPattern => true,
        ast::ManyPattern => false,
        ast::UnitPattern => match *val {
            types::Unit => true,
            _ => false
        },
        ast::LiteralPattern(lit) => *val == types:: gen_lit(lit),
        ast::SymbolPattern(sym) => {
            env::declare(env, &sym, val);
            true
        },
        ast::BoundPattern(sym, pat) => {
            let r = unify_pattern_basic(interp, env, pat, val);
            env::declare(env, &sym, val);
            r
        },
        ast::DisjunctivePattern(pat1, pat2) => {
            unify_pattern_basic(interp, env, pat1, val) || unify_pattern_basic(interp, env, pat2, val)
        },
        ast::ConjunctivePattern(pat1, pat2) => {
            unify_pattern_basic(interp, env, pat1, val) && unify_pattern_basic(interp, env, pat2, val)
        },
        ast::RecordPattern(name, pats) => match *val {
            types::Record(_, vals) => {
                // look up the decl in the interpreter and check if it's our decl
                match interp.record_types.find(&@name) {
                    option::None => false,
                    option::Some(decl) => {
                        // check we're matching out the correct number of slots
                        // TODO: ManyPattern
                        if pats.len() != vals.len() {
                            false
                        } else {
                            let mut ok = true;
                            let mut i = 0;
                            while i < pats.len() - 1 {
                                ok = unify_pattern_basic(interp, env, &pats[i], vals[i]);
                                if !ok { break; };
                                i += 1;
                            }
                            ok
                        }
                    }
                }
            },
            _ => false
        },
        ast::ListPattern(pats) => match *val {
            types::List(vals) => {
                if vals.len() < pats.len() {
                    false
                } else {
                    match pats[pats.len() - 1] {
                        ast::ManyPattern => {
                            // pattern match with a spread argument
                            let mut ok = true;
                            let mut i = 0;
                            while i < pats.len() - 1 {
                                ok = unify_pattern_basic(interp, env, &pats[i], vals[i]);
                                if !ok { break; };
                                i += 1;
                            }
                            ok
                        },
                        _ => {
                            if vals.len() > pats.len() {
                                // no spread argument, :(
                                false
                            } else {
                                // pattern match with a full pattern list
                                let mut ok = true;
                                let mut i = 0;
                                while i < pats.len() {
                                    ok = unify_pattern_basic(interp, env, &pats[i], vals[i]);
                                    if !ok { break; };
                                    i += 1;
                                }
                                ok
                            }
                        }
                    }
                }
            },
            _ => false
        }
    }
}

fn unify_pattern_let(interp: @mut Interp, env: @mut env::Env<Interp>, pat: &ast::LetPat, val: @mut types::Val<Interp>) -> bool {
    match *pat {
        ast::BasicPattern(pat) => unify_pattern_basic(interp, env, &pat, val),
        _ => fail!(~":V")
    }
}

fn eval_exp(interp: @mut Interp, env: @mut env::Env<Interp>, exp: &ast::Exp) -> types::Val<Interp> {
    let frame = interp.current_frame.unwrap();

    let r = match exp.exp {
        ast::UnitExpression => types::Unit,
        ast::LiteralExpression(l) => types::gen_lit(l),
        ast::LambdaExpression(pat, exp) => types::Function(@[types::Fun {
            pattern: pat,
            body: exp,
            env: env
        }]),
        ast::ListExpression(exps) => {
            let mut vals = @[];

            for exps.each |exp| {
                vals += [@mut eval_exp(interp, env, exp)];
                if !frame.exception.is_none() {
                    return types::Unit;
                }
            }

            types::List(vals)
        },
        ast::SymbolExpression(sym) => {
            match env::find(env, &sym) {
                option::Some(x) => types::Unit, // TODO,
                option::None => {
                    frame.exception = @mut option::Some(@mut types::String(fmt!("symbol `%s` not found in scope", *sym).to_managed()));
                    types::Unit
                }
            }
        },
        _ => fail!(~":V")
    };

    r
}

fn exec_stmt(interp: @mut Interp, env: @mut env::Env<Interp>, stmt: &ast::Stmt) -> () {
    let frame = interp.current_frame.unwrap();

    match stmt.stmt {
        ast::LetBindingStatement(pat, exp) => {
            if !unify_pattern_let(interp, env, &pat, @mut eval_exp(interp, env, &exp)) {
                // uh oh, we need to throw an exception and unwind
                frame.exception = @mut option::Some(@mut types::String(@"pattern match refuted"));
            }
        },
        ast::ExpressionStatement(exp) => { eval_exp(interp, env, &exp); }
    };
}

pub fn run_file(interp: @mut Interp, path: &Path) -> () {
    match io::file_reader(path) {
        result::Ok(r) => {
            let tokens = lexer::lex(r);
            let program = parser::parse(tokens);
            run(interp, program);
        },
        result::Err(f) => fail!(f)
    }
}

pub fn run(interp: @mut Interp, prog: ast::Program) -> () {
    for prog.imports.each |imp| {
        import_module(interp, &imp.module, imp.qualified);
    }

    for prog.records.each |rec| {
        interp.record_types.insert(@rec.name, @*rec);
        let ast::RecordName(_, r) = rec.name;

        env::declare(interp.root, &ast::Sym(r), @mut if rec.slots.len() == 0 {
            types::Record(@*rec, @[])
        } else {
            types::RecordConstructor(@*rec)
        });
    }

    for prog.body.each |stmt| {
        let mut frame = wind(interp, interp.root, stmt.lineno);

        exec_stmt(interp, interp.root, stmt);

        match *frame.exception {
            option::None => unwind(interp),
            option::Some(f) => {
                let mut current_frame = frame;
                let mut buf = ~[fmt!("%?", f)];
                loop {
                    buf += [fmt!("        from %s:%u", frame.file, frame.lineno)];
                    if current_frame.parent.is_none() { break; }
                    current_frame = current_frame.parent.unwrap();
                }
                io::println(str::connect(buf, "\n"));
                fail!(~"uncaught aster exception");
            }
        }
    }
}
<commit_msg>bind values correctly<commit_after>use ast;
use lexer;
use parser;

use interp::env;
use interp::types;

use core::hashmap::linear;
use core::to_bytes;

/*
 * aster - AST EvaulatoR
 *
 * aster evaluates a Prismo program via reduction of the AST.
 *
 * "It's pretty terrible."
 * -- Tony, 2013
 */

impl to_bytes::IterBytes for ast::RecordName {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
        match self {
            &ast::RecordName(n, s) => (n, s).iter_bytes(lsb0, f)
        }
    }
}

impl to_bytes::IterBytes for ast::DottedName {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
        match self {
            &ast::DottedName(s) => s.iter_bytes(lsb0, f)
        }
    }
}

pub struct Interp {
    record_types: @mut linear::LinearMap<@ast::RecordName, @ast::RecordDeclaration>,
    import_paths: @[Path],
    root: @mut env::Env<Interp>,
    argv: @[@str],
    filename: @str,
    current_frame: @mut option::Option<@mut Frame>
}

pub impl Interp {
    pub fn new(import_paths: @[Path], argv: @[@str], filename: @str) -> Interp {
        Interp {
            record_types: @mut linear::LinearMap::new(),
            import_paths: import_paths,
            root: @mut env::Env::new(),
            argv: argv,
            filename: filename,
            current_frame: @mut option::None
        }
    }
}

fn wind(interp: @mut Interp, env: @mut env::Env<Interp>, lineno: uint) -> @mut Frame {
    // allocate a new frame
    let frame = @mut Frame::new(interp, env, interp.filename, lineno);
    interp.current_frame = @mut option::Some(frame);
    frame
}

fn unwind(interp: @mut Interp) -> () {
    interp.current_frame = match *interp.current_frame {
        option::None => @mut option::None,
        option::Some(frame) => frame.parent
    };
}

pub struct Frame {
    parent: @mut option::Option<@mut Frame>,
    env: @mut env::Env<Interp>,
    file: @str,
    lineno: uint,
    exception: @mut option::Option<@mut types::Val<Interp>>
}

pub impl Frame {
    pub fn new(interp: @mut Interp, env: @mut env::Env<Interp>, file: @str, lineno: uint) -> Frame {
        Frame {
            parent: interp.current_frame,
            env: env,
            file: file,
            lineno: lineno,
            exception: @mut option::None
        }
    }
}

pub fn import_module(interp: @mut Interp, name: &ast::DottedName, qualified: bool) -> () {
    let module_parts = (**name).to_owned().map(|x| (*x).to_owned());
    let mut parts = copy module_parts;

    vec::reverse(parts);
    let module_name = copy parts[0];
    let filename = fmt!("%s.pr", module_name);
    parts = vec::tail(parts).to_owned();
    vec::reverse(parts);

    let mut found = false;
    let mut paths = interp.import_paths.to_owned();

    for paths.each_mut |import_path| {
        // make a path inside the import path and check if that exists
        let base_path = (copy *import_path).push_many(parts);
        let path = base_path.push(filename);

        if os::path_exists(&path) {
            // make a copy of the import paths then give them to a new sub-interpreter
            let mut import_paths1 = interp.import_paths.to_owned();
            import_paths1.unshift(base_path);

            let interp1 = @mut Interp::new(at_vec::from_owned(import_paths1), interp.argv, path.to_str().to_managed());

            // run the file in the sub-interpreter
            run_file(interp1, &path);

            if qualified {
                let module_name = ast::Sym(module_name.to_managed());

                // qualified imports symbols from child interpreter into a module
                env::declare(interp.root, &module_name,
                             @mut types::Module(interp1.root.vars));

                for interp1.record_types.each_key |k| {
                    interp.record_types.insert(match *k {
                        @ast::RecordName(modu, name) => @ast::RecordName(@ast::DottedName(**modu + [module_name]), name)
                    }, *interp1.record_types.find(k).unwrap());
                }
            } else {
                // otherwise we just plop all the symbols in
                for interp1.root.vars.each_key |k| {
                    env::declare(interp.root, k, *interp1.root.vars.find(k).unwrap());
                }

                // import record types
                for interp1.record_types.each_key |k| {
                    interp.record_types.insert(*k, *interp1.record_types.find(k).unwrap());
                }
            }

            found = true;
            break;
        }
    };

    if !found {
        fail!(fmt!("couldn't import module %s", str::connect(module_parts, ".")))
    };
}

fn unify_pattern_basic(interp: @mut Interp, env: @mut env::Env<Interp>, pat: &ast::Pat, val: @mut types::Val<Interp>) -> bool {
    // perform pattern matching of basic patterns -- if a match fails, we leave all the symbols in
    // scope and not care. this is pretty bad.
    match *pat {
        ast::AnyPattern => true,
        ast::ManyPattern => false,
        ast::UnitPattern => match *val {
            types::Unit => true,
            _ => false
        },
        ast::LiteralPattern(lit) => *val == types:: gen_lit(lit),
        ast::SymbolPattern(sym) => {
            env::declare(env, &sym, val);
            true
        },
        ast::BoundPattern(sym, pat) => {
            let r = unify_pattern_basic(interp, env, pat, val);
            env::declare(env, &sym, val);
            r
        },
        ast::DisjunctivePattern(pat1, pat2) => {
            unify_pattern_basic(interp, env, pat1, val) || unify_pattern_basic(interp, env, pat2, val)
        },
        ast::ConjunctivePattern(pat1, pat2) => {
            unify_pattern_basic(interp, env, pat1, val) && unify_pattern_basic(interp, env, pat2, val)
        },
        ast::RecordPattern(name, pats) => match *val {
            types::Record(_, vals) => {
                // look up the decl in the interpreter and check if it's our decl
                match interp.record_types.find(&@name) {
                    option::None => false,
                    option::Some(_) => {
                        // check we're matching out the correct number of slots
                        // TODO: ManyPattern
                        if pats.len() != vals.len() {
                            false
                        } else if pats.len() == 0 {
                            true
                        } else {
                            let mut ok = true;
                            let mut i = 0;
                            while i < pats.len() {
                                ok = unify_pattern_basic(interp, env, &pats[i], vals[i]);
                                if !ok { break; };
                                i += 1;
                            }
                            ok
                        }
                    }
                }
            },
            _ => false
        },
        ast::ListPattern(pats) => match *val {
            types::List(vals) => {
                if vals.len() < pats.len() {
                    false
                } else {
                    match pats[pats.len() - 1] {
                        ast::ManyPattern => {
                            // pattern match with a spread argument
                            let mut ok = true;
                            let mut i = 0;
                            while i < pats.len() - 1 {
                                ok = unify_pattern_basic(interp, env, &pats[i], vals[i]);
                                if !ok { break; };
                                i += 1;
                            }
                            ok
                        },
                        _ => {
                            if vals.len() > pats.len() {
                                // no spread argument, :(
                                false
                            } else {
                                // pattern match with a full pattern list
                                let mut ok = true;
                                let mut i = 0;
                                while i < pats.len() {
                                    ok = unify_pattern_basic(interp, env, &pats[i], vals[i]);
                                    if !ok { break; };
                                    i += 1;
                                }
                                ok
                            }
                        }
                    }
                }
            },
            _ => false
        }
    }
}

fn unify_pattern_let(interp: @mut Interp, env: @mut env::Env<Interp>, pat: &ast::LetPat, val: @mut types::Val<Interp>) -> bool {
    match *pat {
        ast::BasicPattern(pat) => unify_pattern_basic(interp, env, &pat, val),
        _ => fail!(~":V")
    }
}

fn eval_exp(interp: @mut Interp, env: @mut env::Env<Interp>, exp: &ast::Exp) -> @mut types::Val<Interp> {
    let frame = interp.current_frame.unwrap();

    let r = match exp.exp {
        ast::UnitExpression => @mut types::Unit,
        ast::LiteralExpression(l) => @mut types::gen_lit(l),
        ast::LambdaExpression(pat, exp) => @mut types::Function(@[types::Fun {
            pattern: pat,
            body: exp,
            env: env
        }]),
        ast::ListExpression(exps) => {
            let mut vals = @[];

            for exps.each |exp| {
                vals += [eval_exp(interp, env, exp)];
                if !frame.exception.is_none() {
                    return @mut types::Unit;
                }
            }

            @mut types::List(vals)
        },
        ast::SymbolExpression(sym) => {
            match env::find(env, &sym) {
                option::Some(x) => x,
                option::None => {
                    frame.exception = @mut option::Some(@mut types::String(fmt!("symbol `%s` not found in scope", *sym).to_managed()));
                    @mut types::Unit
                }
            }
        },
        _ => fail!(~":V")
    };

    r
}

fn exec_stmt(interp: @mut Interp, env: @mut env::Env<Interp>, stmt: &ast::Stmt) -> () {
    let frame = interp.current_frame.unwrap();

    match stmt.stmt {
        ast::LetBindingStatement(pat, exp) => {
            if !unify_pattern_let(interp, env, &pat, eval_exp(interp, env, &exp)) {
                // uh oh, we need to throw an exception and unwind
                frame.exception = @mut option::Some(@mut types::String(@"pattern match refuted"));
            }
        },
        ast::ExpressionStatement(exp) => { eval_exp(interp, env, &exp); }
    };
}

pub fn run_file(interp: @mut Interp, path: &Path) -> () {
    match io::file_reader(path) {
        result::Ok(r) => {
            let tokens = lexer::lex(r);
            let program = parser::parse(tokens);
            run(interp, program);
        },
        result::Err(f) => fail!(f)
    }
}

pub fn run(interp: @mut Interp, prog: ast::Program) -> () {
    for prog.imports.each |imp| {
        import_module(interp, &imp.module, imp.qualified);
    }

    for prog.records.each |rec| {
        interp.record_types.insert(@rec.name, @*rec);
        let ast::RecordName(_, r) = rec.name;

        env::declare(interp.root, &ast::Sym(r), @mut if rec.slots.len() == 0 {
            types::Record(@*rec, @[])
        } else {
            types::RecordConstructor(@*rec)
        });
    }

    for prog.body.each |stmt| {
        let mut frame = wind(interp, interp.root, stmt.lineno);

        exec_stmt(interp, interp.root, stmt);

        match *frame.exception {
            option::None => unwind(interp),
            option::Some(f) => {
                let mut current_frame = frame;
                let mut buf = ~[fmt!("%?", f)];
                loop {
                    buf += [fmt!("        from %s:%u", frame.file, frame.lineno)];
                    if current_frame.parent.is_none() { break; }
                    current_frame = current_frame.parent.unwrap();
                }
                io::println(str::connect(buf, "\n"));
                fail!(~"uncaught aster exception");
            }
        }
    }
}
<|endoftext|>


<commit_before>use byteorder::{BigEndian, ByteOrder, ReadBytesExt};
use std::error::Error;
use std::fs::File;
use std::io::prelude::*;
use std::io::Cursor;
use std::io::SeekFrom;

use lz77;

#[derive(Debug)]
pub struct Colour {
    r: usize,
    g: usize,
    b: usize,
}

#[derive(Debug)]
pub struct PivImage {
    palette: Vec<Colour>,
    pixels: Vec<u8>,
}

impl PivImage {
    pub fn from_file(filename: &String) -> Result<(PivImage), Box<Error>> {
        let mut f = File::open(filename)?;
        let mut data: Vec<u8> = Vec::new();
        f.read_to_end(&mut data)?;
        let header = PivImage::read_header(&data[..6])?;

        let palette: Vec<Colour> =
            read_palette(header.bit_depth, &data[6..6 + (header.bit_depth * 2)])?;

        Ok(PivImage {
            palette: palette,
            pixels: lz77::decompress(header.file_length, &data[6 + (header.bit_depth * 2)..])?,
        })
    }

    fn read_header(data: &[u8]) -> Result<Header, Box<Error>> {
        let mut rdr = Cursor::new(data);
        let file_type = rdr.read_u16::<BigEndian>()?;
        rdr.seek(SeekFrom::Current(2))?;
        Ok(Header {
            file_length: rdr.read_u16::<BigEndian>()?,
            bit_depth: 1usize.wrapping_shl(file_type as u32),
        })
    }
}

#[derive(Debug)]
struct Header {
    file_length: u16,
    bit_depth: usize,
}

pub fn read_palette(bit_depth: usize, data: &[u8]) -> Result<Vec<Colour>, Box<Error>> {
    let mut rdr = Cursor::new(data);
    let mut palette = vec![0; bit_depth];
    rdr.read_u16_into::<BigEndian>(&mut palette)?;
    let palette: Vec<u16> = palette.iter().map(|pel| pel & 0x7fff).collect();

    Ok(palette
        .iter()
        .map(|pel| {
            let mut pel_bytes = [0u8; 2];
            BigEndian::write_u16(&mut pel_bytes, *pel);
            Colour {
                r: (pel_bytes[0] as usize) << 4,
                g: (((pel_bytes[1] as usize) & 0xf0) >> 2) << 2,
                b: ((pel_bytes[1] as usize) & 0x0f) << 4,
            }
        })
        .collect())
}
<commit_msg>Rust: Add PivImage::combine_bit_planes<commit_after>use std::error::Error;
use std::fs::File;
use std::io::prelude::*;
use std::io::Cursor;
use std::io::SeekFrom;

use bv::BitSlice;
use byteorder::{BigEndian, ByteOrder, ReadBytesExt};

use lz77;

#[derive(Debug)]
pub struct Colour {
    r: usize,
    g: usize,
    b: usize,
}

#[derive(Debug)]
pub struct PivImage {
    palette: Vec<Colour>,
    pixels: Vec<usize>,
}

impl PivImage {
    pub fn from_file(filename: &String) -> Result<(PivImage), Box<Error>> {
        let mut f = File::open(filename)?;
        let mut data: Vec<u8> = Vec::new();
        f.read_to_end(&mut data)?;
        let header = PivImage::read_header(&data[..6])?;

        let palette: Vec<Colour> =
            read_palette(header.bit_depth, &data[6..6 + (header.bit_depth * 2)])?;

        let extracted = lz77::decompress(header.file_length, &data[6 + (header.bit_depth * 2)..])?;
        let pixels = PivImage::combine_bit_planes(&extracted);
        Ok(PivImage {
            palette: palette,
            pixels: pixels,
        })
    }

    fn read_header(data: &[u8]) -> Result<Header, Box<Error>> {
        let mut rdr = Cursor::new(data);
        let file_type = rdr.read_u16::<BigEndian>()?;
        rdr.seek(SeekFrom::Current(2))?;
        Ok(Header {
            file_length: rdr.read_u16::<BigEndian>()?,
            bit_depth: 1usize.wrapping_shl(file_type as u32),
        })
    }

    fn combine_bit_planes(data: &[u8]) -> Vec<usize> {
        let plane0 = BitSlice::from_slice(&data[..8000]);
        let plane1 = BitSlice::from_slice(&data[8000..16000]);
        let plane2 = BitSlice::from_slice(&data[16000..24000]);
        let plane3 = BitSlice::from_slice(&data[24000..32000]);
        let plane4 = BitSlice::from_slice(&data[32000..]);

        let mut pixels: Vec<usize> = Vec::with_capacity(64000);
        for i in (0..plane0.len()).map(|x| 7 - (x % 8) + x / 8 * 8) {
            let mut sum = 0;
            sum += plane0[i] as usize;
            sum += (plane1[i] as usize) << 1;
            sum += (plane2[i] as usize) << 2;
            sum += (plane3[i] as usize) << 3;
            sum += (plane4[i] as usize) << 4;

            pixels.push(sum);
        }
        pixels
    }
}

#[derive(Debug)]
struct Header {
    file_length: u16,
    bit_depth: usize,
}

pub fn read_palette(bit_depth: usize, data: &[u8]) -> Result<Vec<Colour>, Box<Error>> {
    let mut rdr = Cursor::new(data);
    let mut palette = vec![0; bit_depth];
    rdr.read_u16_into::<BigEndian>(&mut palette)?;
    let palette: Vec<u16> = palette.iter().map(|pel| pel & 0x7fff).collect();

    Ok(palette
        .iter()
        .map(|pel| {
            let mut pel_bytes = [0u8; 2];
            BigEndian::write_u16(&mut pel_bytes, *pel);
            Colour {
                r: (pel_bytes[0] as usize) << 4,
                g: (((pel_bytes[1] as usize) & 0xf0) >> 2) << 2,
                b: ((pel_bytes[1] as usize) & 0x0f) << 4,
            }
        })
        .collect())
}
<|endoftext|>


<commit_before>// use crate::utils::uuids;
use async_trait::async_trait;
use eyre::Result;
use once_cell::sync::Lazy;
use regex::Regex;
use serde::{Deserialize, Serialize};
use std::fmt;
use stencila_schema::{CodeError, Node};
use strum::Display;

// Re-export for the convenience of crates that implement `KernelTrait`
pub use ::async_trait;
pub use eyre;
pub use serde;
pub use stencila_schema;

/// The type of kernel
///
/// At present this is mainly for informational purposes.
#[derive(Debug, Clone, Serialize, Deserialize, Display)]
pub enum KernelType {
    Builtin,
    Micro,
    Jupyter,
}

/// A specification for kernels
///
/// All kernels, including those implemented in plugins, should provide this
/// specification. Rust implementations return a `Kernel` instance from the
/// `spec` function of `KernelTrait`. Plugins provide a JSON or YAML serialization
/// as part of their manifest.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Kernel {
    /// The name of the kernel
    ///
    /// This is used for informational purposes and to allow the user to specify
    /// which kernel they want to use (e.g. in instances that they have more than one kernel that
    /// is capable of executing a language).
    pub name: String,

    /// The type of kernel
    pub r#type: KernelType,

    /// The languages supported by the kernel
    ///
    /// These should be the `name` of one of the `Format`s defined in
    /// the `formats` crate. Many kernels only support one language.
    pub languages: Vec<String>,
}

impl Kernel {
    // Create a new kernel specification
    pub fn new(name: &str, r#type: KernelType, languages: &[&str]) -> Self {
        let languages = languages
            .iter()
            .map(|language| language.to_string())
            .collect();
        Self {
            name: name.to_string(),
            r#type,
            languages,
        }
    }

    // Does the kernel specification match against a kernel selector string?
    pub fn matches(&self, selector: &str) -> bool {
        KernelSelector::parse(selector).matches(self)
    }
}

/// The status of a running kernel
#[derive(Debug, PartialEq, Clone, Serialize, Display)]
#[allow(dead_code)]
pub enum KernelStatus {
    Pending,
    Starting,
    Idle,
    Busy,
    Unresponsive,
    Stopping,
    Finished,
    Failed,
    Unknown,
}

/// A selector used to choose amongst alternative kernels
pub struct KernelSelector {
    /// A string that will match against the kernel `name` or any of its `languages`
    pub any: Option<String>,

    /// A string that will match against the kernel `name`
    pub name: Option<String>,

    /// A string that will match against any of a kernel's `languages`
    pub lang: Option<String>,

    /// A string that will match against the kernel `type`
    pub r#type: Option<String>,
}

impl fmt::Display for KernelSelector {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        let mut str = self.any.clone().unwrap_or_default();
        if let Some(name) = &self.name {
            str.push_str(" name:");
            str.push_str(name);
        }
        if let Some(lang) = &self.lang {
            str.push_str(" lang:");
            str.push_str(lang);
        }
        if let Some(r#type) = &self.r#type {
            str.push_str(" type:");
            str.push_str(r#type);
        }
        write!(formatter, "{}", str.trim())
    }
}

impl KernelSelector {
    /// Create a new `KernelSelector`
    pub fn new(name: Option<String>, lang: Option<String>, r#type: Option<String>) -> Self {
        Self {
            any: None,
            name,
            lang,
            r#type,
        }
    }

    /// Parse a kernel selector string into a `KernelSelector`
    pub fn parse(selector: &str) -> Self {
        static REGEX: Lazy<Regex> = Lazy::new(|| {
            Regex::new(r"(\b(name|lang|type)\s*:\s*(\w+)\b)|(\w+)").expect("Unable to create regex")
        });

        let mut any = None;
        let mut name = None;
        let mut lang = None;
        let mut r#type = None;
        for captures in REGEX.captures_iter(selector) {
            if let Some(tag) = captures.get(2) {
                let value = Some(captures[3].to_string());
                match tag.as_str() {
                    "name" => {
                        if name.is_none() {
                            name = value
                        } else {
                            tracing::warn!("Ignoring additional kernel `name` selector");
                        }
                    }
                    "lang" => {
                        if lang.is_none() {
                            lang = value
                        } else {
                            tracing::warn!("Ignoring additional kernel `lang` selector");
                        }
                    }
                    "type" => {
                        if r#type.is_none() {
                            r#type = value
                        } else {
                            tracing::warn!("Ignoring additional kernel `type` selector");
                        }
                    }
                    _ => (),
                }
            } else if any.is_none() {
                any = Some(captures[4].to_string())
            } else {
                tracing::warn!(
                    "Ignoring extraneous kernel selector: {}",
                    captures[0].to_string()
                );
            }
        }

        Self {
            any,
            name,
            lang,
            r#type,
        }
    }

    pub fn is_empty(&self) -> bool {
        self.any.is_none() && self.name.is_none() && self.lang.is_none() && self.r#type.is_none()
    }

    /// Does a `Kernel` match this selector
    pub fn matches(&self, kernel: &Kernel) -> bool {
        let mut matched = true;

        if let (true, Some(name)) = (matched, &self.name) {
            matched = name.to_lowercase() == kernel.name.to_lowercase();
        } else if let Some(name) = &self.any {
            matched = name.to_lowercase() == kernel.name.to_lowercase();
        }

        if let (true, Some(lang)) = (matched, &self.lang) {
            let mut lang_matched = false;
            for kernel_lang in &kernel.languages {
                if lang.to_lowercase() == kernel_lang.to_lowercase() {
                    lang_matched = true;
                    break;
                }
            }
            matched &= lang_matched;
        } else if let (false, Some(lang)) = (matched, &self.any) {
            for kernel_lang in &kernel.languages {
                if lang.to_lowercase() == kernel_lang.to_lowercase() {
                    matched = true;
                    break;
                }
            }
        }

        if let (true, Some(r#type)) = (matched, &self.r#type) {
            matched = r#type.to_lowercase() == kernel.r#type.to_string().to_lowercase();
        }

        matched
    }
}

/// A trait for kernels
///
/// This trait can be used by Rust implementations of kernels, allowing them to
/// be compiled into the Stencila binaries.
#[async_trait]
pub trait KernelTrait {
    /// Get the [`Kernel`] specification for this implementation
    fn spec(&self) -> Kernel;

    /// Is the kernel available on the current machine?
    async fn available(&self) -> bool {
        true
    }

    /// Is the kernel forkable on the current machine?
    async fn forkable(&self) -> bool {
        false
    }

    /// Start the kernel
    async fn start(&mut self) -> Result<()> {
        Ok(())
    }

    /// Stop the kernel
    async fn stop(&mut self) -> Result<()> {
        Ok(())
    }

    /// Get the status of the kernel
    async fn status(&self) -> Result<KernelStatus>;

    /// Get a symbol from the kernel
    async fn get(&mut self, name: &str) -> Result<Node>;

    /// Set a symbol in the kernel
    async fn set(&mut self, name: &str, value: Node) -> Result<()>;

    /// Execute some code in the kernel
    async fn exec(&mut self, code: &str) -> Result<(Vec<Node>, Vec<CodeError>)>;

    /// Fork the kernel and execute code in the fork
    ///
    /// This default implementation does not fork - it simply executes the code in the
    /// kernel. If a kernel is `forkable: true` it should override this function.
    ///
    /// For more on the "Fork-exec" technique in general see https://en.wikipedia.org/wiki/Fork%E2%80%93exec.
    async fn fork_exec(&mut self, code: &str) -> Result<(Vec<Node>, Vec<CodeError>)> {
        self.exec(code).await
    }
}

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

    #[test]
    fn kernel_selector_new() {
        let ks = KernelSelector::parse("name_lang");
        assert_eq!(ks.any, Some("name_lang".to_string()));
        assert_eq!(ks.name, None);
        assert_eq!(ks.lang, None);
        assert_eq!(ks.r#type, None);
        assert_eq!(ks.to_string(), "name_lang");

        let ks = KernelSelector::parse("name_lang foo bar");
        assert_eq!(ks.any, Some("name_lang".to_string()));
        assert_eq!(ks.name, None);
        assert_eq!(ks.lang, None);
        assert_eq!(ks.r#type, None);

        let ks = KernelSelector::parse("type:micro name_lang");
        assert_eq!(ks.any, Some("name_lang".to_string()));
        assert_eq!(ks.name, None);
        assert_eq!(ks.lang, None);
        assert_eq!(ks.r#type, Some("micro".to_string()));

        let ks = KernelSelector::parse("name_lang type:jupyter lang:py");
        assert_eq!(ks.any, Some("name_lang".to_string()));
        assert_eq!(ks.name, None);
        assert_eq!(ks.lang, Some("py".to_string()));
        assert_eq!(ks.r#type, Some("jupyter".to_string()));

        let ks = KernelSelector::parse("name:ir");
        assert_eq!(ks.any, None);
        assert_eq!(ks.name, Some("ir".to_string()));
        assert_eq!(ks.lang, None);
        assert_eq!(ks.r#type, None);

        let ks = KernelSelector::parse("type:jupyter lang:r name:ir");
        assert_eq!(ks.any, None);
        assert_eq!(ks.name, Some("ir".to_string()));
        assert_eq!(ks.lang, Some("r".to_string()));
        assert_eq!(ks.r#type, Some("jupyter".to_string()));
        assert_eq!(ks.to_string(), "name:ir lang:r type:jupyter");
    }

    #[test]
    fn kernel_selector_matches() {
        let k = Kernel::new("foo", KernelType::Builtin, &["bar", "baz"]);

        assert!(KernelSelector::parse("foo").matches(&k));
        assert!(KernelSelector::parse("bar").matches(&k));
        assert!(KernelSelector::parse("baz").matches(&k));
        assert!(KernelSelector::parse("name:foo").matches(&k));
        assert!(KernelSelector::parse("lang:bar").matches(&k));
        assert!(KernelSelector::parse("lang:baz").matches(&k));
        assert!(KernelSelector::parse("name:foo lang:bar type:builtin").matches(&k));
        assert!(KernelSelector::parse("foo type:builtin").matches(&k));

        assert!(!KernelSelector::parse("quax").matches(&k));
        assert!(!KernelSelector::parse("name:quax").matches(&k));
        assert!(!KernelSelector::parse("lang:quax").matches(&k));
        assert!(!KernelSelector::parse("name:foo lang:quax").matches(&k));
        assert!(!KernelSelector::parse("name:foo lang:bar type:quax").matches(&k));
        assert!(!KernelSelector::parse("foo type:quax").matches(&k));
    }
}
<commit_msg>fix(Kernels): Allow selector tags to have hyphens<commit_after>// use crate::utils::uuids;
use async_trait::async_trait;
use eyre::Result;
use once_cell::sync::Lazy;
use regex::Regex;
use serde::{Deserialize, Serialize};
use std::fmt;
use stencila_schema::{CodeError, Node};
use strum::Display;

// Re-export for the convenience of crates that implement `KernelTrait`
pub use ::async_trait;
pub use eyre;
pub use serde;
pub use stencila_schema;

/// The type of kernel
///
/// At present this is mainly for informational purposes.
#[derive(Debug, Clone, Serialize, Deserialize, Display)]
pub enum KernelType {
    Builtin,
    Micro,
    Jupyter,
}

/// A specification for kernels
///
/// All kernels, including those implemented in plugins, should provide this
/// specification. Rust implementations return a `Kernel` instance from the
/// `spec` function of `KernelTrait`. Plugins provide a JSON or YAML serialization
/// as part of their manifest.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Kernel {
    /// The name of the kernel
    ///
    /// This is used for informational purposes and to allow the user to specify
    /// which kernel they want to use (e.g. in instances that they have more than one kernel that
    /// is capable of executing a language).
    pub name: String,

    /// The type of kernel
    pub r#type: KernelType,

    /// The languages supported by the kernel
    ///
    /// These should be the `name` of one of the `Format`s defined in
    /// the `formats` crate. Many kernels only support one language.
    pub languages: Vec<String>,
}

impl Kernel {
    // Create a new kernel specification
    pub fn new(name: &str, r#type: KernelType, languages: &[&str]) -> Self {
        let languages = languages
            .iter()
            .map(|language| language.to_string())
            .collect();
        Self {
            name: name.to_string(),
            r#type,
            languages,
        }
    }

    // Does the kernel specification match against a kernel selector string?
    pub fn matches(&self, selector: &str) -> bool {
        KernelSelector::parse(selector).matches(self)
    }
}

/// The status of a running kernel
#[derive(Debug, PartialEq, Clone, Serialize, Display)]
#[allow(dead_code)]
pub enum KernelStatus {
    Pending,
    Starting,
    Idle,
    Busy,
    Unresponsive,
    Stopping,
    Finished,
    Failed,
    Unknown,
}

/// A selector used to choose amongst alternative kernels
pub struct KernelSelector {
    /// A string that will match against the kernel `name` or any of its `languages`
    pub any: Option<String>,

    /// A string that will match against the kernel `name`
    pub name: Option<String>,

    /// A string that will match against any of a kernel's `languages`
    pub lang: Option<String>,

    /// A string that will match against the kernel `type`
    pub r#type: Option<String>,
}

impl fmt::Display for KernelSelector {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        let mut str = self.any.clone().unwrap_or_default();
        if let Some(name) = &self.name {
            str.push_str(" name:");
            str.push_str(name);
        }
        if let Some(lang) = &self.lang {
            str.push_str(" lang:");
            str.push_str(lang);
        }
        if let Some(r#type) = &self.r#type {
            str.push_str(" type:");
            str.push_str(r#type);
        }
        write!(formatter, "{}", str.trim())
    }
}

impl KernelSelector {
    /// Create a new `KernelSelector`
    pub fn new(name: Option<String>, lang: Option<String>, r#type: Option<String>) -> Self {
        Self {
            any: None,
            name,
            lang,
            r#type,
        }
    }

    /// Parse a kernel selector string into a `KernelSelector`
    pub fn parse(selector: &str) -> Self {
        static REGEX: Lazy<Regex> = Lazy::new(|| {
            Regex::new(r"(\b(name|lang|type)\s*:\s*([\w-]+)\b)|([\w-]+)")
                .expect("Unable to create regex")
        });

        let mut any = None;
        let mut name = None;
        let mut lang = None;
        let mut r#type = None;
        for captures in REGEX.captures_iter(selector) {
            if let Some(tag) = captures.get(2) {
                let value = Some(captures[3].to_string());
                match tag.as_str() {
                    "name" => {
                        if name.is_none() {
                            name = value
                        } else {
                            tracing::warn!("Ignoring additional kernel `name` selector");
                        }
                    }
                    "lang" => {
                        if lang.is_none() {
                            lang = value
                        } else {
                            tracing::warn!("Ignoring additional kernel `lang` selector");
                        }
                    }
                    "type" => {
                        if r#type.is_none() {
                            r#type = value
                        } else {
                            tracing::warn!("Ignoring additional kernel `type` selector");
                        }
                    }
                    _ => (),
                }
            } else if any.is_none() {
                any = Some(captures[4].to_string())
            } else {
                tracing::warn!(
                    "Ignoring extraneous kernel selector: {}",
                    captures[0].to_string()
                );
            }
        }

        Self {
            any,
            name,
            lang,
            r#type,
        }
    }

    pub fn is_empty(&self) -> bool {
        self.any.is_none() && self.name.is_none() && self.lang.is_none() && self.r#type.is_none()
    }

    /// Does a `Kernel` match this selector
    pub fn matches(&self, kernel: &Kernel) -> bool {
        let mut matched = true;

        if let (true, Some(name)) = (matched, &self.name) {
            matched = name.to_lowercase() == kernel.name.to_lowercase();
        } else if let Some(name) = &self.any {
            matched = name.to_lowercase() == kernel.name.to_lowercase();
        }

        if let (true, Some(lang)) = (matched, &self.lang) {
            let mut lang_matched = false;
            for kernel_lang in &kernel.languages {
                if lang.to_lowercase() == kernel_lang.to_lowercase() {
                    lang_matched = true;
                    break;
                }
            }
            matched &= lang_matched;
        } else if let (false, Some(lang)) = (matched, &self.any) {
            for kernel_lang in &kernel.languages {
                if lang.to_lowercase() == kernel_lang.to_lowercase() {
                    matched = true;
                    break;
                }
            }
        }

        if let (true, Some(r#type)) = (matched, &self.r#type) {
            matched = r#type.to_lowercase() == kernel.r#type.to_string().to_lowercase();
        }

        matched
    }
}

/// A trait for kernels
///
/// This trait can be used by Rust implementations of kernels, allowing them to
/// be compiled into the Stencila binaries.
#[async_trait]
pub trait KernelTrait {
    /// Get the [`Kernel`] specification for this implementation
    fn spec(&self) -> Kernel;

    /// Is the kernel available on the current machine?
    async fn available(&self) -> bool {
        true
    }

    /// Is the kernel forkable on the current machine?
    async fn forkable(&self) -> bool {
        false
    }

    /// Start the kernel
    async fn start(&mut self) -> Result<()> {
        Ok(())
    }

    /// Stop the kernel
    async fn stop(&mut self) -> Result<()> {
        Ok(())
    }

    /// Get the status of the kernel
    async fn status(&self) -> Result<KernelStatus>;

    /// Get a symbol from the kernel
    async fn get(&mut self, name: &str) -> Result<Node>;

    /// Set a symbol in the kernel
    async fn set(&mut self, name: &str, value: Node) -> Result<()>;

    /// Execute some code in the kernel
    async fn exec(&mut self, code: &str) -> Result<(Vec<Node>, Vec<CodeError>)>;

    /// Fork the kernel and execute code in the fork
    ///
    /// This default implementation does not fork - it simply executes the code in the
    /// kernel. If a kernel is `forkable: true` it should override this function.
    ///
    /// For more on the "Fork-exec" technique in general see https://en.wikipedia.org/wiki/Fork%E2%80%93exec.
    async fn fork_exec(&mut self, code: &str) -> Result<(Vec<Node>, Vec<CodeError>)> {
        self.exec(code).await
    }
}

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

    #[test]
    fn kernel_selector_new() {
        let ks = KernelSelector::parse("name_lang");
        assert_eq!(ks.any, Some("name_lang".to_string()));
        assert_eq!(ks.name, None);
        assert_eq!(ks.lang, None);
        assert_eq!(ks.r#type, None);
        assert_eq!(ks.to_string(), "name_lang");

        let ks = KernelSelector::parse("name_lang foo bar");
        assert_eq!(ks.any, Some("name_lang".to_string()));
        assert_eq!(ks.name, None);
        assert_eq!(ks.lang, None);
        assert_eq!(ks.r#type, None);

        let ks = KernelSelector::parse("type:micro name_lang");
        assert_eq!(ks.any, Some("name_lang".to_string()));
        assert_eq!(ks.name, None);
        assert_eq!(ks.lang, None);
        assert_eq!(ks.r#type, Some("micro".to_string()));

        let ks = KernelSelector::parse("name_lang type:jupyter lang:py");
        assert_eq!(ks.any, Some("name_lang".to_string()));
        assert_eq!(ks.name, None);
        assert_eq!(ks.lang, Some("py".to_string()));
        assert_eq!(ks.r#type, Some("jupyter".to_string()));

        let ks = KernelSelector::parse("name:node-micro");
        assert_eq!(ks.any, None);
        assert_eq!(ks.name, Some("node-micro".to_string()));
        assert_eq!(ks.lang, None);
        assert_eq!(ks.r#type, None);

        let ks = KernelSelector::parse("type:jupyter lang:r name:ir");
        assert_eq!(ks.any, None);
        assert_eq!(ks.name, Some("ir".to_string()));
        assert_eq!(ks.lang, Some("r".to_string()));
        assert_eq!(ks.r#type, Some("jupyter".to_string()));
        assert_eq!(ks.to_string(), "name:ir lang:r type:jupyter");
    }

    #[test]
    fn kernel_selector_matches() {
        let k = Kernel::new("foo", KernelType::Builtin, &["bar", "baz"]);

        assert!(KernelSelector::parse("foo").matches(&k));
        assert!(KernelSelector::parse("bar").matches(&k));
        assert!(KernelSelector::parse("baz").matches(&k));
        assert!(KernelSelector::parse("name:foo").matches(&k));
        assert!(KernelSelector::parse("lang:bar").matches(&k));
        assert!(KernelSelector::parse("lang:baz").matches(&k));
        assert!(KernelSelector::parse("name:foo lang:bar type:builtin").matches(&k));
        assert!(KernelSelector::parse("foo type:builtin").matches(&k));

        assert!(!KernelSelector::parse("quax").matches(&k));
        assert!(!KernelSelector::parse("name:quax").matches(&k));
        assert!(!KernelSelector::parse("lang:quax").matches(&k));
        assert!(!KernelSelector::parse("name:foo lang:quax").matches(&k));
        assert!(!KernelSelector::parse("name:foo lang:bar type:quax").matches(&k));
        assert!(!KernelSelector::parse("foo type:quax").matches(&k));
    }
}
<|endoftext|>


<commit_before>//! Utility functions and helpers specific to Windows

use std::mem::{transmute, size_of, MaybeUninit};
use std::os::raw::{c_int, c_void};
use std::ptr;

use winapi::um::handleapi::INVALID_HANDLE_VALUE;
use winapi::um::processenv::GetStdHandle;
pub use winapi::shared::windef::{HDC, HWND};
pub use winapi::shared::minwindef::DWORD;
use winapi::shared::minwindef::ULONG;
pub use winapi::shared::windef::COLORREF;  // = DWORD
use winapi::um::errhandlingapi::GetLastError;
use winapi::um::winbase::STD_ERROR_HANDLE;
use winapi::um::wincon::{GetConsoleWindow, GetConsoleScreenBufferInfo, GetCurrentConsoleFont};
pub use winapi::um::wincon::CONSOLE_SCREEN_BUFFER_INFO;
pub use winapi::um::wincontypes::CONSOLE_FONT_INFO;
use winapi::um::wingdi::{GetPixel, SetPixelV, StretchDIBits,
  BITMAPINFOHEADER, BITMAPINFO, BI_RGB, CLR_INVALID, DIB_RGB_COLORS, GDI_ERROR, RGB, RGBQUAD, SRCCOPY};
pub use winapi::um::winnt::HANDLE;
use winapi::um::winuser::{GetDC, ReleaseDC};

pub struct DeviceContext {
  /// cf. https://docs.microsoft.com/en-us/windows/console/getconsolewindow
  pub console_window: HWND,
  /// Device Context belonging to `console_window`
  pub dc: HDC,
  /// Hidden Error Handler: for when we can not return (such as in a `drop` RAII)
  pub heh: &'static dyn Fn (&'static str, DWORD),
  /// How wide can we paint, in pixels, set by `scan_size`
  pub width: i32,
  /// How far can we paint, in pixels, set by `scan_size`
  pub height: i32,
  /// Console Error: `STD_ERROR_HANDLE` retrieved with `GetStdHandle`,
  /// need it to get the font size and cursor position from the “console's active screen buffer”,
  /// to align graphics with text
  pub ce: HANDLE}

unsafe impl Send for DeviceContext {}

impl Drop for DeviceContext {
  fn drop (&mut self) {
    let rc = unsafe {ReleaseDC (self.console_window, self.dc)};
    if rc != 1 {(self.heh) ("ReleaseDC(dc)", unsafe {GetLastError()})}}}

impl DeviceContext {
  /// Obtains console window, Device Context and Console Error
  /// * `heh` - Error handler for when we can not return (such as in a `drop` RAII)
  pub fn with_heh (heh: &'static dyn Fn (&'static str, DWORD)) -> Result<DeviceContext, String> {
    let console_window = unsafe {GetConsoleWindow()};
    if console_window == ptr::null_mut() {return ERR! ("!GetConsoleWindow")}

    let dc = unsafe {GetDC (console_window)};
    if dc == ptr::null_mut() {return ERR! ("!GetDC")}

    let ce = unsafe {GetStdHandle (STD_ERROR_HANDLE)};
    if ce == INVALID_HANDLE_VALUE {return ERR! ("!GetStdHandle")}

    Ok (DeviceContext {
      console_window,
      dc,
      heh,
      width: 0,
      height: 0,
      ce})}

  /// Obtains console window, Device Context and Console Error
  pub fn new() -> Result<DeviceContext, String> {
    DeviceContext::with_heh (&|_label, _errno| {})}

  /// Packs RGB for a `stretch_to` pixel
  pub fn rgba (r: u8, g: u8, b: u8) -> u32 {
    let quad = RGBQUAD {
      rgbBlue: b,
      rgbGreen: g,
      rgbRed: r,
      rgbReserved: 0};
    unsafe {transmute (quad)}}

  /// Paints the given `rgba`
  /// Stretches the image if `w` <> `sw` or `h` <> `sh`
  /// `rgba` position `i = iy * sw + ix`
  pub fn stretch (&self, x: i32, y: i32, w: i32, h: i32, sx: i32, sy: i32, sw: i32, sh: i32, rgba: &[u32])
  -> Result<i32, DWORD> {
    let mut inf: BITMAPINFO = unsafe {MaybeUninit::zeroed().assume_init()};
    inf.bmiHeader.biSize = size_of::<BITMAPINFOHEADER>() as u32;
    inf.bmiHeader.biWidth = sw;
    inf.bmiHeader.biHeight = -sh;  // “top-down DIB”
    inf.bmiHeader.biPlanes = 1;
    inf.bmiHeader.biBitCount = 32;
    inf.bmiHeader.biCompression = BI_RGB;
    inf.bmiHeader.biSizeImage = (sw * sh * 4) as u32;

    // https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-stretchdibits
    let rc = unsafe {StretchDIBits (
      self.dc, x, y, w, h, sx, sy, sw, sh, rgba.as_ptr() as *const c_void, &inf, DIB_RGB_COLORS, SRCCOPY)};
    if rc == 0 || rc as ULONG == GDI_ERROR {Err (unsafe {GetLastError()})} else {Ok (rc)}}

  /// cf. https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-setpixelv
  pub fn set_pixel (&self, x: i32, y: i32, r: u8, g: u8, b: u8) -> Result<(), DWORD> {
    let rc = unsafe {SetPixelV (self.dc, x, y, RGB (r, g, b))};
    if rc == 0 {Err (unsafe {GetLastError()})} else {Ok(())}}

  /// cf. https://docs.microsoft.com/en-us/windows/win32/gdi/colorref
  /// NB: Looks like the window needs to be visible in order for `get_pixel` to work
  pub fn get_pixel (&self, x: i32, y: i32) -> Result<COLORREF, ()> {
    let rc = unsafe {GetPixel (self.dc, x as c_int, y as c_int)};
    if rc == CLR_INVALID {
      Err (())
    } else {
      Ok (rc)}}

  /// Experimentally determine max `width` and `height` in pixels
  /// NB: Looks like the window needs to be visible in order for `get_pixel` to work
  pub fn scan_size (&mut self) {
    if let Err (()) = self.get_pixel (1, 1) {  // Return early if `get_pixel` doesn't work (window hidden)
      let errno = unsafe {GetLastError()};
      if errno != 0 {(self.heh) ("get_pixel (1, 1)", errno)}
      return}

    // NB: GetDeviceCaps with HORZRES and VERTRES returns bogus values
    //   GetWindowRect too: it seems to match results obtained
    //   multiplying GetConsoleFontSize by GetConsoleScreenBufferInfo/dwSize,
    //   but the actual number of pixels is different
    let (mut width, mut height) = (0, 0);
    while self.get_pixel (width + 31, height + 31) .is_ok() {width += 31; height += 31}
    while self.get_pixel (width + 9, height) .is_ok() {width += 9}
    while self.get_pixel (width + 1, height) .is_ok() {width += 1}
    while self.get_pixel (width, height + 1) .is_ok() {height += 1}
    self.width = width + 1; self.height = height + 1}

  /// cf. https://docs.microsoft.com/en-us/windows/console/console-font-info-str
  pub fn font (&self) -> Result<CONSOLE_FONT_INFO, String> {
    let mut font: CONSOLE_FONT_INFO = unsafe {MaybeUninit::zeroed().assume_init()};
    let rc = unsafe {GetCurrentConsoleFont (self.ce, 0, &mut font)};
    if rc == 0 {ERR! ("!GetCurrentConsoleFont")} else {Ok (font)}}

  /// cf. https://docs.microsoft.com/en-us/windows/console/console-screen-buffer-info-str
  pub fn screen_buffer_info (&self) -> Result<CONSOLE_SCREEN_BUFFER_INFO, DWORD> {
    let mut sbi: CONSOLE_SCREEN_BUFFER_INFO = unsafe {MaybeUninit::zeroed().assume_init()};
    let rc = unsafe {GetConsoleScreenBufferInfo (self.ce, &mut sbi)};
    if rc == 0 {Err (unsafe {GetLastError()})} else {Ok (sbi)}}

  /// Bridges character position to pixels
  /// Depends on `scan_size` (called separately) to know the actual pixel dimensions
  pub fn translate (&self) -> Result<(Translation, CONSOLE_SCREEN_BUFFER_INFO), String> {
    let sbi = try_s! (self.screen_buffer_info());
    // The actual character size in Windows might differ from the one reported in `CONSOLE_FONT_INFO`
    let (mut tw, mut th) = (1, 2);
    let sw = (sbi.srWindow.Right - sbi.srWindow.Left) as i16;
    if sw > 0 {while (tw + 1) as i32 * sw as i32 <= self.width {tw += 1}}

    let sh = (sbi.srWindow.Bottom - sbi.srWindow.Top) as i16 + 1;
    if sh > 0 {while (th + 1) as i32 * sh as i32 <= self.height {th += 1}}
    //println! ("\nself.height {} vs th*sh= {}; th {}\n", self.height, th as i16 * sh, th);

    Ok ((Translation {
      cxa: sbi.dwCursorPosition.X as i16,
      left: sbi.srWindow.Left as i16,
      cya: sbi.dwCursorPosition.Y as i16,
      top: sbi.srWindow.Top as i16,
      sw,
      sh,
      tw,
      th
    }, sbi))}}

/// Bridges character position to pixels
#[derive(Clone, Debug)]
pub struct Translation {
  /// Cursor X, Absolute, in characters, 0-based
  pub cxa: i16,
  /// Horizontal scrolling
  pub left: i16,
  /// Cursor Y, Absolute, in characters, 0-based
  /// Mind the scrolling: if `cy` equals `sh` then the measurement
  /// was taken at the bottom of the visible screen
  /// Also with lines recently printed on
  /// the actual *paint* of characters by the terminal might happen after a small delay,
  /// overwriting whatever graphics we put there: should either wait for the terminal *paint* to settle
  /// or better yet maintain a set of overlays to be redrawn periodically
  pub cya: i16,
  /// Vertical scrolling
  pub top: i16,
  /// Screen Width in characters (`Right - Left`)
  pub sw: i16,
  /// Screen Height in characters (`Bottom - Top`)
  pub sh: i16,
  /// Text Width: a likely number of horisontal pixels in a character
  pub tw: i8,
  /// Text Height: a likely number of vertical pixels in a character
  pub th: i8}

impl Translation {
  pub fn cx (&self) -> i32 {
    self.cxa as i32 - self.left as i32}

  pub fn cy (&self) -> i32 {
    self.cya as i32 - self.top as i32}}
<commit_msg>Use usize width and height to match Vec capacity<commit_after>//! Utility functions and helpers specific to Windows

use std::mem::{transmute, size_of, MaybeUninit};
use std::os::raw::{c_int, c_void};
use std::ptr;

use winapi::um::handleapi::INVALID_HANDLE_VALUE;
use winapi::um::processenv::GetStdHandle;
pub use winapi::shared::windef::{HDC, HWND};
pub use winapi::shared::minwindef::DWORD;
use winapi::shared::minwindef::ULONG;
pub use winapi::shared::windef::COLORREF;  // = DWORD
use winapi::um::errhandlingapi::GetLastError;
use winapi::um::winbase::STD_ERROR_HANDLE;
use winapi::um::wincon::{GetConsoleWindow, GetConsoleScreenBufferInfo, GetCurrentConsoleFont};
pub use winapi::um::wincon::CONSOLE_SCREEN_BUFFER_INFO;
pub use winapi::um::wincontypes::CONSOLE_FONT_INFO;
use winapi::um::wingdi::{GetPixel, SetPixelV, StretchDIBits,
  BITMAPINFOHEADER, BITMAPINFO, BI_RGB, CLR_INVALID, DIB_RGB_COLORS, GDI_ERROR, RGB, RGBQUAD, SRCCOPY};
pub use winapi::um::winnt::HANDLE;
use winapi::um::winnt::LONG;
use winapi::um::winuser::{GetDC, ReleaseDC};

pub struct DeviceContext {
  /// cf. https://docs.microsoft.com/en-us/windows/console/getconsolewindow
  pub console_window: HWND,
  /// Device Context belonging to `console_window`
  pub dc: HDC,
  /// Hidden Error Handler: for when we can not return (such as in a `drop` RAII)
  pub heh: &'static dyn Fn (&'static str, DWORD),
  /// How wide can we paint, in pixels, set by `scan_size`
  pub width: usize,
  /// How far can we paint, in pixels, set by `scan_size`
  pub height: usize,
  /// Console Error: `STD_ERROR_HANDLE` retrieved with `GetStdHandle`,
  /// need it to get the font size and cursor position from the “console's active screen buffer”,
  /// to align graphics with text
  pub ce: HANDLE}

unsafe impl Send for DeviceContext {}

impl Drop for DeviceContext {
  fn drop (&mut self) {
    let rc = unsafe {ReleaseDC (self.console_window, self.dc)};
    if rc != 1 {(self.heh) ("ReleaseDC(dc)", unsafe {GetLastError()})}}}

impl DeviceContext {
  /// Obtains console window, Device Context and Console Error
  /// * `heh` - Error handler for when we can not return (such as in a `drop` RAII)
  pub fn with_heh (heh: &'static dyn Fn (&'static str, DWORD)) -> Result<DeviceContext, String> {
    let console_window = unsafe {GetConsoleWindow()};
    if console_window == ptr::null_mut() {return ERR! ("!GetConsoleWindow")}

    let dc = unsafe {GetDC (console_window)};
    if dc == ptr::null_mut() {return ERR! ("!GetDC")}

    let ce = unsafe {GetStdHandle (STD_ERROR_HANDLE)};
    if ce == INVALID_HANDLE_VALUE {return ERR! ("!GetStdHandle")}

    Ok (DeviceContext {
      console_window,
      dc,
      heh,
      width: 0,
      height: 0,
      ce})}

  /// Obtains console window, Device Context and Console Error
  pub fn new() -> Result<DeviceContext, String> {
    DeviceContext::with_heh (&|_label, _errno| {})}

  /// Packs RGB for a `stretch_to` pixel
  pub fn rgba (r: u8, g: u8, b: u8) -> u32 {
    let quad = RGBQUAD {
      rgbBlue: b,
      rgbGreen: g,
      rgbRed: r,
      rgbReserved: 0};
    unsafe {transmute (quad)}}

  /// Paints the given `rgba`
  /// Stretches the image if `w` <> `sw` or `h` <> `sh`
  /// `rgba` position `i = iy * sw + ix`
  pub fn stretch (&self, x: i32,  y: i32,  w: usize,  h: usize,
                        sx: i32, sy: i32, sw: usize, sh: usize, rgba: &[u32]) -> Result<i32, DWORD> {
    let mut inf: BITMAPINFO = unsafe {MaybeUninit::zeroed().assume_init()};
    inf.bmiHeader.biSize = size_of::<BITMAPINFOHEADER>() as u32;
    inf.bmiHeader.biWidth = sw as LONG;
    inf.bmiHeader.biHeight = - (sh as LONG);  // “top-down DIB”
    inf.bmiHeader.biPlanes = 1;
    inf.bmiHeader.biBitCount = 32;
    inf.bmiHeader.biCompression = BI_RGB;
    inf.bmiHeader.biSizeImage = (sw * sh * 4) as u32;

    // https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-stretchdibits
    let rc = unsafe {StretchDIBits (
      self.dc, x,  y,  w as c_int,  h as c_int,
              sx, sy, sw as c_int, sh as c_int, rgba.as_ptr() as *const c_void, &inf, DIB_RGB_COLORS, SRCCOPY)};
    if rc == 0 || rc as ULONG == GDI_ERROR {Err (unsafe {GetLastError()})} else {Ok (rc)}}

  /// cf. https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-setpixelv
  pub fn set_pixel (&self, x: i32, y: i32, r: u8, g: u8, b: u8) -> Result<(), DWORD> {
    let rc = unsafe {SetPixelV (self.dc, x, y, RGB (r, g, b))};
    if rc == 0 {Err (unsafe {GetLastError()})} else {Ok(())}}

  /// cf. https://docs.microsoft.com/en-us/windows/win32/gdi/colorref
  /// NB: Looks like the window needs to be visible in order for `get_pixel` to work
  pub fn get_pixel (&self, x: i32, y: i32) -> Result<COLORREF, ()> {
    let rc = unsafe {GetPixel (self.dc, x as c_int, y as c_int)};
    if rc == CLR_INVALID {
      Err (())
    } else {
      Ok (rc)}}

  /// Experimentally determine max `width` and `height` in pixels
  /// NB: Looks like the window needs to be visible in order for `get_pixel` to work
  pub fn scan_size (&mut self) {
    if let Err (()) = self.get_pixel (1, 1) {  // Return early if `get_pixel` doesn't work (window hidden)
      let errno = unsafe {GetLastError()};
      if errno != 0 {(self.heh) ("get_pixel (1, 1)", errno)}
      return}

    // NB: GetDeviceCaps with HORZRES and VERTRES returns bogus values
    //   GetWindowRect too: it seems to match results obtained
    //   multiplying GetConsoleFontSize by GetConsoleScreenBufferInfo/dwSize,
    //   but the actual number of pixels is different
    let (mut width, mut height) = (0, 0);
    while self.get_pixel (width + 31, height + 31) .is_ok() {width += 31; height += 31}
    while self.get_pixel (width + 9, height) .is_ok() {width += 9}
    while self.get_pixel (width + 1, height) .is_ok() {width += 1}
    while self.get_pixel (width, height + 1) .is_ok() {height += 1}
    self.width = width as usize + 1; self.height = height as usize + 1}

  /// cf. https://docs.microsoft.com/en-us/windows/console/console-font-info-str
  pub fn font (&self) -> Result<CONSOLE_FONT_INFO, String> {
    let mut font: CONSOLE_FONT_INFO = unsafe {MaybeUninit::zeroed().assume_init()};
    let rc = unsafe {GetCurrentConsoleFont (self.ce, 0, &mut font)};
    if rc == 0 {ERR! ("!GetCurrentConsoleFont")} else {Ok (font)}}

  /// cf. https://docs.microsoft.com/en-us/windows/console/console-screen-buffer-info-str
  pub fn screen_buffer_info (&self) -> Result<CONSOLE_SCREEN_BUFFER_INFO, DWORD> {
    let mut sbi: CONSOLE_SCREEN_BUFFER_INFO = unsafe {MaybeUninit::zeroed().assume_init()};
    let rc = unsafe {GetConsoleScreenBufferInfo (self.ce, &mut sbi)};
    if rc == 0 {Err (unsafe {GetLastError()})} else {Ok (sbi)}}

  /// Bridges character position to pixels
  /// Depends on `scan_size` (called separately) to know the actual pixel dimensions
  pub fn translate (&self) -> Result<(Translation, CONSOLE_SCREEN_BUFFER_INFO), String> {
    let sbi = try_s! (self.screen_buffer_info());
    // The actual character size in Windows might differ from the one reported in `CONSOLE_FONT_INFO`
    let (mut tw, mut th) = (1, 2);
    let sw = (sbi.srWindow.Right - sbi.srWindow.Left) as i16;
    if sw > 0 {while (tw + 1) as usize * sw as usize <= self.width {tw += 1}}

    let sh = (sbi.srWindow.Bottom - sbi.srWindow.Top) as i16 + 1;
    if sh > 0 {while (th + 1) as usize * sh as usize <= self.height {th += 1}}
    //println! ("\nself.height {} vs th*sh= {}; th {}\n", self.height, th as i16 * sh, th);

    Ok ((Translation {
      cxa: sbi.dwCursorPosition.X as i16,
      left: sbi.srWindow.Left as i16,
      cya: sbi.dwCursorPosition.Y as i16,
      top: sbi.srWindow.Top as i16,
      sw,
      sh,
      tw,
      th
    }, sbi))}}

/// Bridges character position to pixels
#[derive(Clone, Debug)]
pub struct Translation {
  /// Cursor X, Absolute, in characters, 0-based
  pub cxa: i16,
  /// Horizontal scrolling
  pub left: i16,
  /// Cursor Y, Absolute, in characters, 0-based
  /// Mind the scrolling: if `cy` equals `sh` then the measurement
  /// was taken at the bottom of the visible screen
  /// Also with lines recently printed on
  /// the actual *paint* of characters by the terminal might happen after a small delay,
  /// overwriting whatever graphics we put there: should either wait for the terminal *paint* to settle
  /// or better yet maintain a set of overlays to be redrawn periodically
  /// Caps around `9000` by default, see https://stackoverflow.com/a/34161156/257568
  pub cya: i16,
  /// Vertical scrolling
  pub top: i16,
  /// Screen Width in characters (`Right - Left`)
  pub sw: i16,
  /// Screen Height in characters (`Bottom - Top`)
  pub sh: i16,
  /// Text Width: a likely number of horisontal pixels in a character
  pub tw: i8,
  /// Text Height: a likely number of vertical pixels in a character
  pub th: i8}

impl Translation {
  pub fn cx (&self) -> i32 {
    self.cxa as i32 - self.left as i32}

  pub fn cy (&self) -> i32 {
    self.cya as i32 - self.top as i32}}
<|endoftext|>


<commit_before>use std::env;

#[allow(while_true)]
fn main() {
    let args: Vec<String> = env::args().collect();

    match args.len() {
        1 => {
            while true {
                println!("y");
            }
        },
        _ => {
            while true {
                println!("{}", args[1]);
            }
        },
    }
}
<commit_msg>Rust: Simplify solution, use `loop` for endless loop<commit_after>use std::env;

fn main() {
    let args: Vec<String> = env::args().collect();
    let args = &args[1..];

    let output = if args.is_empty() { "y".to_string() } else { args.join(" ") };
    loop {
        println!("{}", output)
    }
}
<|endoftext|>


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

use crate::{
    account_address::AccountAddress,
    account_config::{AccountResource, BalanceResource},
    account_state::AccountState,
    event::EventKey,
    ledger_info::LedgerInfo,
    proof::AccountStateProof,
    transaction::Version,
};
use anyhow::{anyhow, ensure, Error, Result};
use libra_crypto::{
    hash::{CryptoHash, CryptoHasher},
    HashValue,
};
use libra_crypto_derive::CryptoHasher;
#[cfg(any(test, feature = "fuzzing"))]
use proptest::{arbitrary::Arbitrary, prelude::*};
#[cfg(any(test, feature = "fuzzing"))]
use proptest_derive::Arbitrary;
use serde::{Deserialize, Serialize};
use std::{convert::TryFrom, fmt};

#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, CryptoHasher)]
pub struct AccountStateBlob {
    blob: Vec<u8>,
}

impl AccountStateBlob {
    pub fn blob(&self) -> &Vec<u8> {
        &self.blob
    }
}

impl fmt::Debug for AccountStateBlob {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let decoded = lcs::from_bytes(&self.blob)
            .map(|account_state: AccountState| format!("{:#?}", account_state))
            .unwrap_or_else(|_| String::from("[fail]"));

        write!(
            f,
            "AccountStateBlob {{ \n \
             Raw: 0x{} \n \
             Decoded: {} \n \
             }}",
            hex::encode(&self.blob),
            decoded,
        )
    }
}

impl AsRef<[u8]> for AccountStateBlob {
    fn as_ref(&self) -> &[u8] {
        &self.blob
    }
}

impl From<&AccountStateBlob> for Vec<u8> {
    fn from(account_state_blob: &AccountStateBlob) -> Vec<u8> {
        account_state_blob.blob.clone()
    }
}

impl From<AccountStateBlob> for Vec<u8> {
    fn from(account_state_blob: AccountStateBlob) -> Vec<u8> {
        Self::from(&account_state_blob)
    }
}

impl From<Vec<u8>> for AccountStateBlob {
    fn from(blob: Vec<u8>) -> AccountStateBlob {
        AccountStateBlob { blob }
    }
}

impl TryFrom<&AccountState> for AccountStateBlob {
    type Error = Error;

    fn try_from(account_state: &AccountState) -> Result<Self> {
        Ok(Self {
            blob: lcs::to_bytes(account_state)?,
        })
    }
}

impl TryFrom<&AccountStateBlob> for AccountState {
    type Error = Error;

    fn try_from(account_state_blob: &AccountStateBlob) -> Result<Self> {
        lcs::from_bytes(&account_state_blob.blob).map_err(Into::into)
    }
}

impl TryFrom<(&AccountResource, &BalanceResource)> for AccountStateBlob {
    type Error = Error;

    fn try_from(
        (account_resource, balance_resource): (&AccountResource, &BalanceResource),
    ) -> Result<Self> {
        Self::try_from(&AccountState::try_from((
            account_resource,
            balance_resource,
        ))?)
    }
}

impl TryFrom<&AccountStateBlob> for AccountResource {
    type Error = Error;

    fn try_from(account_state_blob: &AccountStateBlob) -> Result<Self> {
        AccountState::try_from(account_state_blob)?
            .get_account_resource()?
            .ok_or_else(|| anyhow!("AccountResource not found."))
    }
}

impl CryptoHash for AccountStateBlob {
    type Hasher = AccountStateBlobHasher;

    fn hash(&self) -> HashValue {
        let mut hasher = Self::Hasher::default();
        hasher.update(&self.blob);
        hasher.finish()
    }
}

#[cfg(any(test, feature = "fuzzing"))]
prop_compose! {
    fn account_state_blob_strategy()(account_resource in any::<AccountResource>(), balance_resource in any::<BalanceResource>()) -> AccountStateBlob {
        AccountStateBlob::try_from((&account_resource, &balance_resource)).unwrap()
    }
}

#[cfg(any(test, feature = "fuzzing"))]
impl Arbitrary for AccountStateBlob {
    type Parameters = ();
    fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
        account_state_blob_strategy().boxed()
    }

    type Strategy = BoxedStrategy<Self>;
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
pub struct AccountStateWithProof {
    /// The transaction version at which this account state is seen.
    pub version: Version,
    /// Blob value representing the account state. If this field is not set, it
    /// means the account does not exist.
    pub blob: Option<AccountStateBlob>,
    /// The proof the client can use to authenticate the value.
    pub proof: AccountStateProof,
}

impl AccountStateWithProof {
    /// Constructor.
    pub fn new(version: Version, blob: Option<AccountStateBlob>, proof: AccountStateProof) -> Self {
        Self {
            version,
            blob,
            proof,
        }
    }

    /// Verifies the the account state blob with the proof, both carried by `self`.
    ///
    /// Two things are ensured if no error is raised:
    ///   1. This account state exists in the ledger represented by `ledger_info`.
    ///   2. It belongs to account of `address` and is seen at the time the transaction at version
    /// `state_version` is just committed. To make sure this is the latest state, pass in
    /// `ledger_info.version()` as `state_version`.
    pub fn verify(
        &self,
        ledger_info: &LedgerInfo,
        version: Version,
        address: AccountAddress,
    ) -> Result<()> {
        ensure!(
            self.version == version,
            "State version ({}) is not expected ({}).",
            self.version,
            version,
        );

        self.proof
            .verify(ledger_info, version, address.hash(), self.blob.as_ref())
    }

    /// Returns the `EventKey` (if existent) and number of total events for
    /// an event stream specified by a query path.
    ///
    /// If the resource referred by the path that is supposed to hold the `EventHandle`
    /// doesn't exist, returns (None, 0). While if the path is invalid, raises error.
    ///
    /// For example:
    ///   1. if asked for DiscoverySetChange event from an ordinary user account,
    /// this returns (None, 0)
    ///   2. but if asked for a random path that we don't understand, it's an error.
    pub fn get_event_key_and_count_by_query_path(
        &self,
        path: &[u8],
    ) -> Result<(Option<EventKey>, u64)> {
        if let Some(account_blob) = &self.blob {
            if let Some(event_handle) =
                AccountState::try_from(account_blob)?.get_event_handle_by_query_path(path)?
            {
                Ok((Some(*event_handle.key()), event_handle.count()))
            } else {
                Ok((None, 0))
            }
        } else {
            Ok((None, 0))
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use lcs::test_helpers::assert_canonical_encode_decode;
    use proptest::collection::vec;

    fn hash_blob(blob: &[u8]) -> HashValue {
        let mut hasher = AccountStateBlobHasher::default();
        hasher.update(blob);
        hasher.finish()
    }

    proptest! {
        #[test]
        fn account_state_blob_hash(blob in vec(any::<u8>(), 1..100)) {
            prop_assert_eq!(hash_blob(&blob), AccountStateBlob::from(blob).hash());
        }

        #[test]
        fn account_state_blob_lcs_roundtrip(account_state_blob in any::<AccountStateBlob>()) {
            assert_canonical_encode_decode(account_state_blob);
        }

        #[test]
        fn account_state_with_proof_lcs_roundtrip(account_state_with_proof in any::<AccountStateWithProof>()) {
            assert_canonical_encode_decode(account_state_with_proof);
        }
    }

    #[test]
    fn test_debug_does_not_panic() {
        format!("{:#?}", AccountStateBlob::from(vec![1u8, 2u8, 3u8]));
    }
}
<commit_msg>Removing blob from types/src/account_state_blob.rs<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    account_address::AccountAddress,
    account_config::{AccountResource, BalanceResource},
    account_state::AccountState,
    event::EventKey,
    ledger_info::LedgerInfo,
    proof::AccountStateProof,
    transaction::Version,
};
use anyhow::{anyhow, ensure, Error, Result};
use libra_crypto::{
    hash::{CryptoHash, CryptoHasher},
    HashValue,
};
use libra_crypto_derive::CryptoHasher;
#[cfg(any(test, feature = "fuzzing"))]
use proptest::{arbitrary::Arbitrary, prelude::*};
#[cfg(any(test, feature = "fuzzing"))]
use proptest_derive::Arbitrary;
use serde::{Deserialize, Serialize};
use std::{convert::TryFrom, fmt};

#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, CryptoHasher)]
pub struct AccountStateBlob {
    blob: Vec<u8>,
}

impl fmt::Debug for AccountStateBlob {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let decoded = lcs::from_bytes(&self.blob)
            .map(|account_state: AccountState| format!("{:#?}", account_state))
            .unwrap_or_else(|_| String::from("[fail]"));

        write!(
            f,
            "AccountStateBlob {{ \n \
             Raw: 0x{} \n \
             Decoded: {} \n \
             }}",
            hex::encode(&self.blob),
            decoded,
        )
    }
}

impl AsRef<[u8]> for AccountStateBlob {
    fn as_ref(&self) -> &[u8] {
        &self.blob
    }
}

impl From<&AccountStateBlob> for Vec<u8> {
    fn from(account_state_blob: &AccountStateBlob) -> Vec<u8> {
        account_state_blob.blob.clone()
    }
}

impl From<AccountStateBlob> for Vec<u8> {
    fn from(account_state_blob: AccountStateBlob) -> Vec<u8> {
        Self::from(&account_state_blob)
    }
}

impl From<Vec<u8>> for AccountStateBlob {
    fn from(blob: Vec<u8>) -> AccountStateBlob {
        AccountStateBlob { blob }
    }
}

impl TryFrom<&AccountState> for AccountStateBlob {
    type Error = Error;

    fn try_from(account_state: &AccountState) -> Result<Self> {
        Ok(Self {
            blob: lcs::to_bytes(account_state)?,
        })
    }
}

impl TryFrom<&AccountStateBlob> for AccountState {
    type Error = Error;

    fn try_from(account_state_blob: &AccountStateBlob) -> Result<Self> {
        lcs::from_bytes(&account_state_blob.blob).map_err(Into::into)
    }
}

impl TryFrom<(&AccountResource, &BalanceResource)> for AccountStateBlob {
    type Error = Error;

    fn try_from(
        (account_resource, balance_resource): (&AccountResource, &BalanceResource),
    ) -> Result<Self> {
        Self::try_from(&AccountState::try_from((
            account_resource,
            balance_resource,
        ))?)
    }
}

impl TryFrom<&AccountStateBlob> for AccountResource {
    type Error = Error;

    fn try_from(account_state_blob: &AccountStateBlob) -> Result<Self> {
        AccountState::try_from(account_state_blob)?
            .get_account_resource()?
            .ok_or_else(|| anyhow!("AccountResource not found."))
    }
}

impl CryptoHash for AccountStateBlob {
    type Hasher = AccountStateBlobHasher;

    fn hash(&self) -> HashValue {
        let mut hasher = Self::Hasher::default();
        hasher.update(&self.blob);
        hasher.finish()
    }
}

#[cfg(any(test, feature = "fuzzing"))]
prop_compose! {
    fn account_state_blob_strategy()(account_resource in any::<AccountResource>(), balance_resource in any::<BalanceResource>()) -> AccountStateBlob {
        AccountStateBlob::try_from((&account_resource, &balance_resource)).unwrap()
    }
}

#[cfg(any(test, feature = "fuzzing"))]
impl Arbitrary for AccountStateBlob {
    type Parameters = ();
    fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
        account_state_blob_strategy().boxed()
    }

    type Strategy = BoxedStrategy<Self>;
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
pub struct AccountStateWithProof {
    /// The transaction version at which this account state is seen.
    pub version: Version,
    /// Blob value representing the account state. If this field is not set, it
    /// means the account does not exist.
    pub blob: Option<AccountStateBlob>,
    /// The proof the client can use to authenticate the value.
    pub proof: AccountStateProof,
}

impl AccountStateWithProof {
    /// Constructor.
    pub fn new(version: Version, blob: Option<AccountStateBlob>, proof: AccountStateProof) -> Self {
        Self {
            version,
            blob,
            proof,
        }
    }

    /// Verifies the the account state blob with the proof, both carried by `self`.
    ///
    /// Two things are ensured if no error is raised:
    ///   1. This account state exists in the ledger represented by `ledger_info`.
    ///   2. It belongs to account of `address` and is seen at the time the transaction at version
    /// `state_version` is just committed. To make sure this is the latest state, pass in
    /// `ledger_info.version()` as `state_version`.
    pub fn verify(
        &self,
        ledger_info: &LedgerInfo,
        version: Version,
        address: AccountAddress,
    ) -> Result<()> {
        ensure!(
            self.version == version,
            "State version ({}) is not expected ({}).",
            self.version,
            version,
        );

        self.proof
            .verify(ledger_info, version, address.hash(), self.blob.as_ref())
    }

    /// Returns the `EventKey` (if existent) and number of total events for
    /// an event stream specified by a query path.
    ///
    /// If the resource referred by the path that is supposed to hold the `EventHandle`
    /// doesn't exist, returns (None, 0). While if the path is invalid, raises error.
    ///
    /// For example:
    ///   1. if asked for DiscoverySetChange event from an ordinary user account,
    /// this returns (None, 0)
    ///   2. but if asked for a random path that we don't understand, it's an error.
    pub fn get_event_key_and_count_by_query_path(
        &self,
        path: &[u8],
    ) -> Result<(Option<EventKey>, u64)> {
        if let Some(account_blob) = &self.blob {
            if let Some(event_handle) =
                AccountState::try_from(account_blob)?.get_event_handle_by_query_path(path)?
            {
                Ok((Some(*event_handle.key()), event_handle.count()))
            } else {
                Ok((None, 0))
            }
        } else {
            Ok((None, 0))
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use lcs::test_helpers::assert_canonical_encode_decode;
    use proptest::collection::vec;

    fn hash_blob(blob: &[u8]) -> HashValue {
        let mut hasher = AccountStateBlobHasher::default();
        hasher.update(blob);
        hasher.finish()
    }

    proptest! {
        #[test]
        fn account_state_blob_hash(blob in vec(any::<u8>(), 1..100)) {
            prop_assert_eq!(hash_blob(&blob), AccountStateBlob::from(blob).hash());
        }

        #[test]
        fn account_state_blob_lcs_roundtrip(account_state_blob in any::<AccountStateBlob>()) {
            assert_canonical_encode_decode(account_state_blob);
        }

        #[test]
        fn account_state_with_proof_lcs_roundtrip(account_state_with_proof in any::<AccountStateWithProof>()) {
            assert_canonical_encode_decode(account_state_with_proof);
        }
    }

    #[test]
    fn test_debug_does_not_panic() {
        format!("{:#?}", AccountStateBlob::from(vec![1u8, 2u8, 3u8]));
    }
}
<|endoftext|>


<commit_before>//! BookmarkCollection module
//!
//! A BookmarkCollection is nothing more than a simple store entry. One can simply call functions
//! from the libimagentrylink::external::ExternalLinker trait on this to generate external links.
//!
//! The BookmarkCollection type offers helper functions to get all links or such things.
use std::ops::Deref;
use std::ops::DerefMut;

use regex::Regex;

use error::BookmarkError as BE;
use error::BookmarkErrorKind as BEK;
use error::MapErrInto;
use result::Result;
use module_path::ModuleEntryPath;

use libimagstore::store::Store;
use libimagstore::storeid::IntoStoreId;
use libimagstore::store::FileLockEntry;
use libimagentrylink::external::ExternalLinker;
use libimagentrylink::internal::InternalLinker;
use libimagentrylink::internal::Link as StoreLink;
use libimagerror::into::IntoError;
use url::Url;

use link::Link;

pub struct BookmarkCollection<'a> {
    fle: FileLockEntry<'a>,
    store: &'a Store,
}

/// {Internal, External}Linker is implemented as Deref is implemented
impl<'a> Deref for BookmarkCollection<'a> {
    type Target = FileLockEntry<'a>;

    fn deref(&self) -> &FileLockEntry<'a> {
        &self.fle
    }

}

impl<'a> DerefMut for BookmarkCollection<'a> {

    fn deref_mut(&mut self) -> &mut FileLockEntry<'a> {
        &mut self.fle
    }

}

impl<'a> BookmarkCollection<'a> {

    pub fn new(store: &'a Store, name: &str) -> Result<BookmarkCollection<'a>> {
        let id = ModuleEntryPath::new(name).into_storeid();
        store.create(id)
            .map(|fle| {
                BookmarkCollection {
                    fle: fle,
                    store: store,
                }
            })
            .map_err_into(BEK::StoreReadError)
    }

    pub fn get(store: &'a Store, name: &str) -> Result<BookmarkCollection<'a>> {
        let id = ModuleEntryPath::new(name).into_storeid();
        store.get(id)
            .map_err_into(BEK::StoreReadError)
            .and_then(|fle| {
                match fle {
                    None => Err(BEK::CollectionNotFound.into_error()),
                    Some(e) => Ok(BookmarkCollection {
                        fle: e,
                        store: store,
                    }),
                }
            })
    }

    pub fn delete(store: &Store, name: &str) -> Result<()> {
        store.delete(ModuleEntryPath::new(name).into_storeid()).map_err_into(BEK::StoreReadError)
    }

    pub fn links(&self) -> Result<Vec<Url>> {
        self.fle.get_external_links(&self.store).map_err_into(BEK::LinkError)
    }

    pub fn link_entries(&self) -> Result<Vec<StoreLink>> {
        use libimagentrylink::external::is_external_link_storeid;

        self.fle
            .get_internal_links()
            .map(|v| v.into_iter().filter(|id| is_external_link_storeid(id)).collect())
            .map_err_into(BEK::StoreReadError)
    }

    pub fn add_link(&mut self, l: Link) -> Result<()> {
        use link::IntoUrl;

        l.into_url()
            .and_then(|url| self.add_external_link(self.store, url).map_err_into(BEK::LinkingError))
            .map_err_into(BEK::LinkError)
    }

    pub fn get_links_matching(&self, r: Regex) -> Result<Option<Link>> {
        self.get_external_links(self.store)
            .map_err_into(BEK::LinkError)
            .map(|v| {
                v.into_iter()
                    .map(Url::into_string)
                    .filter(|urlstr| r.is_match(&urlstr[..]))
                    .map(Link::from)
                    .next()
            })
    }

    pub fn remove_link(&self, l: Link) -> Result<()> {
        unimplemented!()
    }

}

<commit_msg>fixup! Impl BookmarkCollection::get_links_matching()<commit_after>//! BookmarkCollection module
//!
//! A BookmarkCollection is nothing more than a simple store entry. One can simply call functions
//! from the libimagentrylink::external::ExternalLinker trait on this to generate external links.
//!
//! The BookmarkCollection type offers helper functions to get all links or such things.
use std::ops::Deref;
use std::ops::DerefMut;

use regex::Regex;

use error::BookmarkError as BE;
use error::BookmarkErrorKind as BEK;
use error::MapErrInto;
use result::Result;
use module_path::ModuleEntryPath;

use libimagstore::store::Store;
use libimagstore::storeid::IntoStoreId;
use libimagstore::store::FileLockEntry;
use libimagentrylink::external::ExternalLinker;
use libimagentrylink::internal::InternalLinker;
use libimagentrylink::internal::Link as StoreLink;
use libimagerror::into::IntoError;
use url::Url;

use link::Link;

pub struct BookmarkCollection<'a> {
    fle: FileLockEntry<'a>,
    store: &'a Store,
}

/// {Internal, External}Linker is implemented as Deref is implemented
impl<'a> Deref for BookmarkCollection<'a> {
    type Target = FileLockEntry<'a>;

    fn deref(&self) -> &FileLockEntry<'a> {
        &self.fle
    }

}

impl<'a> DerefMut for BookmarkCollection<'a> {

    fn deref_mut(&mut self) -> &mut FileLockEntry<'a> {
        &mut self.fle
    }

}

impl<'a> BookmarkCollection<'a> {

    pub fn new(store: &'a Store, name: &str) -> Result<BookmarkCollection<'a>> {
        let id = ModuleEntryPath::new(name).into_storeid();
        store.create(id)
            .map(|fle| {
                BookmarkCollection {
                    fle: fle,
                    store: store,
                }
            })
            .map_err_into(BEK::StoreReadError)
    }

    pub fn get(store: &'a Store, name: &str) -> Result<BookmarkCollection<'a>> {
        let id = ModuleEntryPath::new(name).into_storeid();
        store.get(id)
            .map_err_into(BEK::StoreReadError)
            .and_then(|fle| {
                match fle {
                    None => Err(BEK::CollectionNotFound.into_error()),
                    Some(e) => Ok(BookmarkCollection {
                        fle: e,
                        store: store,
                    }),
                }
            })
    }

    pub fn delete(store: &Store, name: &str) -> Result<()> {
        store.delete(ModuleEntryPath::new(name).into_storeid()).map_err_into(BEK::StoreReadError)
    }

    pub fn links(&self) -> Result<Vec<Url>> {
        self.fle.get_external_links(&self.store).map_err_into(BEK::LinkError)
    }

    pub fn link_entries(&self) -> Result<Vec<StoreLink>> {
        use libimagentrylink::external::is_external_link_storeid;

        self.fle
            .get_internal_links()
            .map(|v| v.into_iter().filter(|id| is_external_link_storeid(id)).collect())
            .map_err_into(BEK::StoreReadError)
    }

    pub fn add_link(&mut self, l: Link) -> Result<()> {
        use link::IntoUrl;

        l.into_url()
            .and_then(|url| self.add_external_link(self.store, url).map_err_into(BEK::LinkingError))
            .map_err_into(BEK::LinkError)
    }

    pub fn get_links_matching(&self, r: Regex) -> Result<Vec<Link>> {
        self.get_external_links(self.store)
            .map_err_into(BEK::LinkError)
            .map(|v| {
                v.into_iter()
                    .map(Url::into_string)
                    .filter(|urlstr| r.is_match(&urlstr[..]))
                    .map(Link::from)
                    .collect()
            })
    }

    pub fn remove_link(&self, l: Link) -> Result<()> {
        unimplemented!()
    }

}

<|endoftext|>