<commit_before>extern crate dyon;
extern crate piston_window;
extern crate current;

use std::sync::Arc;
use piston_window::*;
use current::{Current, CurrentGuard};
use dyon::{error, load, Lt, Module, PreludeFunction, Runtime, Variable};

fn main() {
    let mut window: PistonWindow =
        WindowSettings::new("dyon: piston_window", [512; 2])
        .exit_on_esc(true)
        .samples(4)
        .build()
        .unwrap();
    let dyon_module = match load_module() {
        None => return,
        Some(m) => m
    };
    let mut dyon_runtime = Runtime::new();

    let window_guard = CurrentGuard::new(&mut window);
    if error(dyon_runtime.run(&dyon_module)) {
        return;
    }
    drop(window_guard);
}

fn load_module() -> Option<Module> {
    let mut module = Module::new();
    module.add(Arc::new("render".into()), dyon_render, PreludeFunction {
        lts: vec![],
        returns: true
    });
    module.add(Arc::new("update".into()), dyon_update, PreludeFunction {
        lts: vec![],
        returns: true
    });
    module.add(Arc::new("press".into()), dyon_press, PreludeFunction {
        lts: vec![],
        returns: true
    });
    module.add(Arc::new("release".into()), dyon_release, PreludeFunction {
        lts: vec![],
        returns: true
    });
    module.add(Arc::new("focus".into()), dyon_focus, PreludeFunction {
        lts: vec![],
        returns: true,
    });
    module.add(Arc::new("focus_arg".into()), dyon_focus_arg, PreludeFunction {
        lts: vec![],
        returns: true,
    });
    module.add(Arc::new("clear".into()), dyon_clear, PreludeFunction {
        lts: vec![Lt::Default],
        returns: false
    });
    module.add(Arc::new("draw_color_rect".into()),
        dyon_draw_color_rect, PreludeFunction {
            lts: vec![Lt::Default; 2],
            returns: false
        });
    module.add(Arc::new("draw_color_radius_line".into()),
        dyon_draw_color_radius_line, PreludeFunction {
            lts: vec![Lt::Default; 3],
            returns: false
        });
    module.add(Arc::new("next_event".into()),
        dyon_next_event, PreludeFunction {
            lts: vec![],
            returns: true
        });
    module.add(Arc::new("set_title".into()),
        dyon_set_title, PreludeFunction {
            lts: vec![Lt::Default],
            returns: false
        });
    module.add(Arc::new("update_dt".into()),
        dyon_update_dt, PreludeFunction {
            lts: vec![],
            returns: true
        });
    module.add(Arc::new("press_keyboard_key".into()),
        dyon_press_keyboard_key, PreludeFunction {
            lts: vec![],
            returns: true
        });
    module.add(Arc::new("release_keyboard_key".into()),
        dyon_release_keyboard_key, PreludeFunction {
            lts: vec![],
            returns: true
        });
    if error(load("source/piston_window/loader.rs", &mut module)) {
        None
    } else {
        Some(module)
    }
}

fn dyon_render(rt: &mut Runtime) -> Result<(), String> {
    let e = unsafe { &*Current::<PistonWindow>::new() };
    push_bool(rt, e.render_args().is_some());
    Ok(())
}

fn dyon_update(rt: &mut Runtime) -> Result<(), String> {
    let e = unsafe { &*Current::<PistonWindow>::new() };
    push_bool(rt, e.update_args().is_some());
    Ok(())
}

fn dyon_press(rt: &mut Runtime) -> Result<(), String> {
    let e = unsafe { &*Current::<PistonWindow>::new() };
    push_bool(rt, e.press_args().is_some());
    Ok(())
}

fn dyon_release(rt: &mut Runtime) -> Result<(), String> {
    let e = unsafe { &*Current::<PistonWindow>::new() };
    push_bool(rt, e.release_args().is_some());
    Ok(())
}

fn dyon_focus(rt: &mut Runtime) -> Result<(), String> {
    let e = unsafe { &*Current::<PistonWindow>::new() };
    push_bool(rt, e.focus_args().is_some());
    Ok(())
}

fn dyon_focus_arg(rt: &mut Runtime) -> Result<(), String> {
    let e = unsafe { &*Current::<PistonWindow>::new() };
    push_opt_bool(rt, e.focus_args());
    Ok(())
}

fn push_opt_bool(rt: &mut Runtime, val: Option<bool>) {
    match val {
        None => {
            rt.stack.push(Variable::Option(None))
        }
        Some(b) => {
            rt.stack.push(Variable::Option(Some(Box::new(Variable::Bool(b)))))
        }
    }
}

fn push_bool(rt: &mut Runtime, val: bool) {
    rt.stack.push(Variable::Bool(val))
}

fn push_opt_num(rt: &mut Runtime, val: Option<f64>) {
    match val {
        None => {
            rt.stack.push(Variable::Option(None))
        }
        Some(n) => {
            rt.stack.push(Variable::Option(Some(Box::new(Variable::F64(n)))))
        }
    }
}

fn pop_num(rt: &mut Runtime) -> Result<f64, String> {
    let num = rt.stack.pop().expect("Expected number");
    match rt.resolve(&num) {
        &Variable::F64(n) => Ok(n),
        _ => Err("Expected number".into())
    }
}

fn pop_color(rt: &mut Runtime) -> Result<[f32; 4], String> {
    let color = rt.stack.pop().expect("Expected color");
    match rt.resolve(&color) {
        &Variable::Array(ref arr) => {
            let r = match rt.resolve(&arr[0]) {
                &Variable::F64(r) => r,
                _ => return Err("Expected number".into())
            };
            let g = match rt.resolve(&arr[1]) {
                &Variable::F64(r) => r,
                _ => return Err("Expected number".into())
            };
            let b = match rt.resolve(&arr[2]) {
                &Variable::F64(r) => r,
                _ => return Err("Expected number".into())
            };
            let a = match rt.resolve(&arr[3]) {
                &Variable::F64(r) => r,
                _ => return Err("Expected number".into())
            };
            Ok([r as f32, g as f32, b as f32, a as f32])
        }
        _ => return Err("Expected color".into())
    }
}

fn pop_rect(rt: &mut Runtime) -> Result<[f64; 4], String> {
    let v = rt.stack.pop().expect("Expected rect");
    match rt.resolve(&v) {
        &Variable::Array(ref arr) => {
            let x = match rt.resolve(&arr[0]) {
                &Variable::F64(x) => x,
                _ => return Err("Expected number".into())
            };
            let y = match rt.resolve(&arr[1]) {
                &Variable::F64(y) => y,
                _ => return Err("Expected number".into())
            };
            let w = match rt.resolve(&arr[2]) {
                &Variable::F64(w) => w,
                _ => return Err("Expected number".into())
            };
            let h = match rt.resolve(&arr[3]) {
                &Variable::F64(h) => h,
                _ => return Err("Expected number".into())
            };
            Ok([x, y, w, h])
        }
        _ => return Err("Expected rect".into())
    }
}

fn pop_string(rt: &mut Runtime) -> Result<Arc<String>, String> {
    let v = rt.stack.pop().expect("Expected string");
    match rt.resolve(&v) {
        &Variable::Text(ref s) => Ok(s.clone()),
        _ => Err("Expected string".into())
    }
}

fn dyon_clear(rt: &mut Runtime) -> Result<(), String> {
    let e = unsafe { &mut *Current::<PistonWindow>::new() };
    let color = try!(pop_color(rt));
    e.draw_2d(|_c, g| {
        clear(color, g);
    });
    Ok(())
}

fn dyon_draw_color_rect(rt: &mut Runtime) -> Result<(), String> {
    let e = unsafe { &mut *Current::<PistonWindow>::new() };
    let rect = try!(pop_rect(rt));
    let color = try!(pop_color(rt));
    e.draw_2d(|c, g| {
        rectangle(color, rect, c.transform, g);
    });
    Ok(())
}

fn dyon_draw_color_radius_line(rt: &mut Runtime) -> Result<(), String> {
    let e = unsafe { &mut *Current::<PistonWindow>::new() };
    let rect = try!(pop_rect(rt));
    let radius = try!(pop_num(rt));
    let color = try!(pop_color(rt));
    e.draw_2d(|c, g| {
        line(color, radius, rect, c.transform, g);
    });
    Ok(())
}

fn dyon_next_event(rt: &mut Runtime) -> Result<(), String> {
    let e = unsafe { &mut *Current::<PistonWindow>::new() };
    if let Some(new_e) = e.next() {
        *e = new_e;
        push_bool(rt, true);
    } else {
        push_bool(rt, false);
    }
    Ok(())
}

fn dyon_set_title(rt: &mut Runtime) -> Result<(), String> {
    let e = unsafe { &mut *Current::<PistonWindow>::new() };
    let title = try!(pop_string(rt));
    e.set_title((*title).clone());
    Ok(())
}

fn dyon_update_dt(rt: &mut Runtime) -> Result<(), String> {
    let e = unsafe { &mut *Current::<PistonWindow>::new() };
    push_opt_num(rt, e.update_args().map(|args| args.dt));
    Ok(())
}

fn dyon_press_keyboard_key(rt: &mut Runtime) -> Result<(), String> {
    let e = unsafe { &mut *Current::<PistonWindow>::new() };
    if let Some(Button::Keyboard(key)) = e.press_args() {
        push_opt_num(rt, Some(key as u64 as f64));
    } else {
        push_opt_num(rt, None);
    }
    Ok(())
}

fn dyon_release_keyboard_key(rt: &mut Runtime) -> Result<(), String> {
    let e = unsafe { &mut *Current::<PistonWindow>::new() };
    if let Some(Button::Keyboard(key)) = e.release_args() {
        push_opt_num(rt, Some(key as u64 as f64));
    } else {
        push_opt_num(rt, None);
    }
    Ok(())
}
<commit_msg>Refactored functions in "piston_window" example<commit_after>extern crate dyon;
extern crate piston_window;
extern crate current;

use std::sync::Arc;
use piston_window::*;
use current::CurrentGuard;
use dyon::{error, load, Lt, Module, PreludeFunction, Runtime};

fn main() {
    let mut window: PistonWindow =
        WindowSettings::new("dyon: piston_window", [512; 2])
        .exit_on_esc(true)
        .samples(4)
        .build()
        .unwrap();
    let dyon_module = match load_module() {
        None => return,
        Some(m) => m
    };
    let mut dyon_runtime = Runtime::new();

    let window_guard = CurrentGuard::new(&mut window);
    if error(dyon_runtime.run(&dyon_module)) {
        return;
    }
    drop(window_guard);
}

fn load_module() -> Option<Module> {
    use dyon_functions::*;

    let mut module = Module::new();
    module.add(Arc::new("render".into()), render, PreludeFunction {
        lts: vec![],
        returns: true
    });
    module.add(Arc::new("update".into()), update, PreludeFunction {
        lts: vec![],
        returns: true
    });
    module.add(Arc::new("press".into()), press, PreludeFunction {
        lts: vec![],
        returns: true
    });
    module.add(Arc::new("release".into()), release, PreludeFunction {
        lts: vec![],
        returns: true
    });
    module.add(Arc::new("focus".into()), focus, PreludeFunction {
        lts: vec![],
        returns: true,
    });
    module.add(Arc::new("focus_arg".into()), focus_arg, PreludeFunction {
        lts: vec![],
        returns: true,
    });
    module.add(Arc::new("clear".into()), clear, PreludeFunction {
        lts: vec![Lt::Default],
        returns: false
    });
    module.add(Arc::new("draw_color_rect".into()),
        draw_color_rect, PreludeFunction {
            lts: vec![Lt::Default; 2],
            returns: false
        });
    module.add(Arc::new("draw_color_radius_line".into()),
        draw_color_radius_line, PreludeFunction {
            lts: vec![Lt::Default; 3],
            returns: false
        });
    module.add(Arc::new("next_event".into()),
        next_event, PreludeFunction {
            lts: vec![],
            returns: true
        });
    module.add(Arc::new("set_title".into()),
        set_title, PreludeFunction {
            lts: vec![Lt::Default],
            returns: false
        });
    module.add(Arc::new("update_dt".into()),
        update_dt, PreludeFunction {
            lts: vec![],
            returns: true
        });
    module.add(Arc::new("press_keyboard_key".into()),
        press_keyboard_key, PreludeFunction {
            lts: vec![],
            returns: true
        });
    module.add(Arc::new("release_keyboard_key".into()),
        release_keyboard_key, PreludeFunction {
            lts: vec![],
            returns: true
        });
    if error(load("source/piston_window/loader.rs", &mut module)) {
        None
    } else {
        Some(module)
    }
}

mod stack {
    use dyon::{Runtime, Variable};
    use std::sync::Arc;

    pub fn push_opt_bool(rt: &mut Runtime, val: Option<bool>) {
        match val {
            None => {
                rt.stack.push(Variable::Option(None))
            }
            Some(b) => {
                rt.stack.push(Variable::Option(Some(Box::new(Variable::Bool(b)))))
            }
        }
    }

    pub fn push_bool(rt: &mut Runtime, val: bool) {
        rt.stack.push(Variable::Bool(val))
    }

    pub fn push_opt_num(rt: &mut Runtime, val: Option<f64>) {
        match val {
            None => {
                rt.stack.push(Variable::Option(None))
            }
            Some(n) => {
                rt.stack.push(Variable::Option(Some(Box::new(Variable::F64(n)))))
            }
        }
    }

    pub fn pop_num(rt: &mut Runtime) -> Result<f64, String> {
        let num = rt.stack.pop().expect("Expected number");
        match rt.resolve(&num) {
            &Variable::F64(n) => Ok(n),
            _ => Err("Expected number".into())
        }
    }

    pub fn pop_color(rt: &mut Runtime) -> Result<[f32; 4], String> {
        let color = rt.stack.pop().expect("Expected color");
        match rt.resolve(&color) {
            &Variable::Array(ref arr) => {
                let r = match rt.resolve(&arr[0]) {
                    &Variable::F64(r) => r,
                    _ => return Err("Expected number".into())
                };
                let g = match rt.resolve(&arr[1]) {
                    &Variable::F64(r) => r,
                    _ => return Err("Expected number".into())
                };
                let b = match rt.resolve(&arr[2]) {
                    &Variable::F64(r) => r,
                    _ => return Err("Expected number".into())
                };
                let a = match rt.resolve(&arr[3]) {
                    &Variable::F64(r) => r,
                    _ => return Err("Expected number".into())
                };
                Ok([r as f32, g as f32, b as f32, a as f32])
            }
            _ => return Err("Expected color".into())
        }
    }

    pub fn pop_rect(rt: &mut Runtime) -> Result<[f64; 4], String> {
        let v = rt.stack.pop().expect("Expected rect");
        match rt.resolve(&v) {
            &Variable::Array(ref arr) => {
                let x = match rt.resolve(&arr[0]) {
                    &Variable::F64(x) => x,
                    _ => return Err("Expected number".into())
                };
                let y = match rt.resolve(&arr[1]) {
                    &Variable::F64(y) => y,
                    _ => return Err("Expected number".into())
                };
                let w = match rt.resolve(&arr[2]) {
                    &Variable::F64(w) => w,
                    _ => return Err("Expected number".into())
                };
                let h = match rt.resolve(&arr[3]) {
                    &Variable::F64(h) => h,
                    _ => return Err("Expected number".into())
                };
                Ok([x, y, w, h])
            }
            _ => return Err("Expected rect".into())
        }
    }

    pub fn pop_string(rt: &mut Runtime) -> Result<Arc<String>, String> {
        let v = rt.stack.pop().expect("Expected string");
        match rt.resolve(&v) {
            &Variable::Text(ref s) => Ok(s.clone()),
            _ => Err("Expected string".into())
        }
    }
}

mod dyon_functions {
    use dyon::Runtime;
    use current::Current;
    use stack::*;

    pub fn render(rt: &mut Runtime) -> Result<(), String> {
        use piston_window::*;

        let e = unsafe { &*Current::<PistonWindow>::new() };
        push_bool(rt, e.render_args().is_some());
        Ok(())
    }

    pub fn update(rt: &mut Runtime) -> Result<(), String> {
        use piston_window::*;

        let e = unsafe { &*Current::<PistonWindow>::new() };
        push_bool(rt, e.update_args().is_some());
        Ok(())
    }

    pub fn press(rt: &mut Runtime) -> Result<(), String> {
        use piston_window::*;

        let e = unsafe { &*Current::<PistonWindow>::new() };
        push_bool(rt, e.press_args().is_some());
        Ok(())
    }

    pub fn release(rt: &mut Runtime) -> Result<(), String> {
        use piston_window::*;

        let e = unsafe { &*Current::<PistonWindow>::new() };
        push_bool(rt, e.release_args().is_some());
        Ok(())
    }

    pub fn focus(rt: &mut Runtime) -> Result<(), String> {
        use piston_window::*;

        let e = unsafe { &*Current::<PistonWindow>::new() };
        push_bool(rt, e.focus_args().is_some());
        Ok(())
    }

    pub fn focus_arg(rt: &mut Runtime) -> Result<(), String> {
        use piston_window::*;

        let e = unsafe { &*Current::<PistonWindow>::new() };
        push_opt_bool(rt, e.focus_args());
        Ok(())
    }

    pub fn clear(rt: &mut Runtime) -> Result<(), String> {
        use piston_window::*;

        let e = unsafe { &mut *Current::<PistonWindow>::new() };
        let color = try!(pop_color(rt));
        e.draw_2d(|_c, g| {
            clear(color, g);
        });
        Ok(())
    }

    pub fn draw_color_rect(rt: &mut Runtime) -> Result<(), String> {
        use piston_window::*;

        let e = unsafe { &mut *Current::<PistonWindow>::new() };
        let rect = try!(pop_rect(rt));
        let color = try!(pop_color(rt));
        e.draw_2d(|c, g| {
            rectangle(color, rect, c.transform, g);
        });
        Ok(())
    }

    pub fn draw_color_radius_line(rt: &mut Runtime) -> Result<(), String> {
        use piston_window::*;

        let e = unsafe { &mut *Current::<PistonWindow>::new() };
        let rect = try!(pop_rect(rt));
        let radius = try!(pop_num(rt));
        let color = try!(pop_color(rt));
        e.draw_2d(|c, g| {
            line(color, radius, rect, c.transform, g);
        });
        Ok(())
    }

    pub fn next_event(rt: &mut Runtime) -> Result<(), String> {
        use piston_window::*;

        let e = unsafe { &mut *Current::<PistonWindow>::new() };
        if let Some(new_e) = e.next() {
            *e = new_e;
            push_bool(rt, true);
        } else {
            push_bool(rt, false);
        }
        Ok(())
    }

    pub fn set_title(rt: &mut Runtime) -> Result<(), String> {
        use piston_window::*;

        let e = unsafe { &mut *Current::<PistonWindow>::new() };
        let title = try!(pop_string(rt));
        e.set_title((*title).clone());
        Ok(())
    }

    pub fn update_dt(rt: &mut Runtime) -> Result<(), String> {
        use piston_window::*;

        let e = unsafe { &mut *Current::<PistonWindow>::new() };
        push_opt_num(rt, e.update_args().map(|args| args.dt));
        Ok(())
    }

    pub fn press_keyboard_key(rt: &mut Runtime) -> Result<(), String> {
        use piston_window::*;

        let e = unsafe { &mut *Current::<PistonWindow>::new() };
        if let Some(Button::Keyboard(key)) = e.press_args() {
            push_opt_num(rt, Some(key as u64 as f64));
        } else {
            push_opt_num(rt, None);
        }
        Ok(())
    }

    pub fn release_keyboard_key(rt: &mut Runtime) -> Result<(), String> {
        use piston_window::*;

        let e = unsafe { &mut *Current::<PistonWindow>::new() };
        if let Some(Button::Keyboard(key)) = e.release_args() {
            push_opt_num(rt, Some(key as u64 as f64));
        } else {
            push_opt_num(rt, None);
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! A higher level attributes based on TokenTree, with also some shortcuts.

use std::{ops, sync::Arc};

use cfg::{CfgExpr, CfgOptions};
use either::Either;
use hir_expand::{hygiene::Hygiene, AstId, InFile};
use itertools::Itertools;
use mbe::ast_to_token_tree;
use syntax::{
    ast::{self, AstNode, AttrsOwner},
    AstToken, SmolStr,
};
use tt::Subtree;

use crate::{
    db::DefDatabase,
    item_tree::{ItemTreeId, ItemTreeNode},
    nameres::ModuleSource,
    path::ModPath,
    src::HasChildSource,
    AdtId, AttrDefId, Lookup,
};

/// Holds documentation
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Documentation(String);

impl Documentation {
    pub fn as_str(&self) -> &str {
        &self.0
    }
}

impl Into<String> for Documentation {
    fn into(self) -> String {
        self.0
    }
}

#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct Attrs {
    entries: Option<Arc<[Attr]>>,
}

impl ops::Deref for Attrs {
    type Target = [Attr];

    fn deref(&self) -> &[Attr] {
        match &self.entries {
            Some(it) => &*it,
            None => &[],
        }
    }
}

impl Attrs {
    pub const EMPTY: Attrs = Attrs { entries: None };

    pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs {
        match def {
            AttrDefId::ModuleId(module) => {
                let def_map = db.crate_def_map(module.krate);
                let mod_data = &def_map[module.local_id];
                match mod_data.declaration_source(db) {
                    Some(it) => {
                        Attrs::from_attrs_owner(db, it.as_ref().map(|it| it as &dyn AttrsOwner))
                    }
                    None => Attrs::from_attrs_owner(
                        db,
                        mod_data.definition_source(db).as_ref().map(|src| match src {
                            ModuleSource::SourceFile(file) => file as &dyn AttrsOwner,
                            ModuleSource::Module(module) => module as &dyn AttrsOwner,
                        }),
                    ),
                }
            }
            AttrDefId::FieldId(it) => {
                let src = it.parent.child_source(db);
                match &src.value[it.local_id] {
                    Either::Left(_tuple) => Attrs::default(),
                    Either::Right(record) => Attrs::from_attrs_owner(db, src.with_value(record)),
                }
            }
            AttrDefId::EnumVariantId(var_id) => {
                let src = var_id.parent.child_source(db);
                let src = src.as_ref().map(|it| &it[var_id.local_id]);
                Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner))
            }
            AttrDefId::AdtId(it) => match it {
                AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db),
                AdtId::EnumId(it) => attrs_from_item_tree(it.lookup(db).id, db),
                AdtId::UnionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
            },
            AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db),
            AttrDefId::MacroDefId(it) => {
                it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db))
            }
            AttrDefId::ImplId(it) => attrs_from_item_tree(it.lookup(db).id, db),
            AttrDefId::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db),
            AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db),
            AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
            AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db),
        }
    }

    pub fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn AttrsOwner>) -> Attrs {
        let hygiene = Hygiene::new(db.upcast(), owner.file_id);
        Attrs::new(owner.value, &hygiene)
    }

    pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Attrs {
        let docs = ast::CommentIter::from_syntax_node(owner.syntax()).map(|docs_text| {
            (
                docs_text.syntax().text_range().start(),
                docs_text.doc_comment().map(|doc| Attr {
                    input: Some(AttrInput::Literal(SmolStr::new(doc))),
                    path: ModPath::from(hir_expand::name!(doc)),
                }),
            )
        });
        let attrs = owner
            .attrs()
            .map(|attr| (attr.syntax().text_range().start(), Attr::from_src(attr, hygiene)));
        // sort here by syntax node offset because the source can have doc attributes and doc strings be interleaved
        let attrs: Vec<_> = docs.chain(attrs).sorted_by_key(|&(offset, _)| offset).collect();
        let entries = if attrs.is_empty() {
            // Avoid heap allocation
            None
        } else {
            Some(attrs.into_iter().flat_map(|(_, attr)| attr).collect())
        };
        Attrs { entries }
    }

    pub fn merge(&self, other: Attrs) -> Attrs {
        match (&self.entries, &other.entries) {
            (None, None) => Attrs { entries: None },
            (Some(entries), None) | (None, Some(entries)) => {
                Attrs { entries: Some(entries.clone()) }
            }
            (Some(a), Some(b)) => {
                Attrs { entries: Some(a.iter().chain(b.iter()).cloned().collect()) }
            }
        }
    }

    pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> {
        AttrQuery { attrs: self, key }
    }

    pub fn cfg(&self) -> Option<CfgExpr> {
        // FIXME: handle cfg_attr :-)
        let mut cfgs = self.by_key("cfg").tt_values().map(CfgExpr::parse).collect::<Vec<_>>();
        match cfgs.len() {
            0 => None,
            1 => Some(cfgs.pop().unwrap()),
            _ => Some(CfgExpr::All(cfgs)),
        }
    }
    pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool {
        match self.cfg() {
            None => true,
            Some(cfg) => cfg_options.check(&cfg) != Some(false),
        }
    }

    pub fn docs(&self) -> Option<Documentation> {
        let docs = self
            .by_key("doc")
            .attrs()
            .flat_map(|attr| match attr.input.as_ref()? {
                AttrInput::Literal(s) => Some(s),
                AttrInput::TokenTree(_) => None,
            })
            .intersperse(&SmolStr::new_inline("\n"))
            .map(|it| it.as_str())
            .collect::<String>();
        if docs.is_empty() {
            None
        } else {
            Some(Documentation(docs.into()))
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Attr {
    pub(crate) path: ModPath,
    pub(crate) input: Option<AttrInput>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AttrInput {
    /// `#[attr = "string"]`
    Literal(SmolStr),
    /// `#[attr(subtree)]`
    TokenTree(Subtree),
}

impl Attr {
    fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> {
        let path = ModPath::from_src(ast.path()?, hygiene)?;
        let input = if let Some(lit) = ast.literal() {
            let value = match lit.kind() {
                ast::LiteralKind::String(string) => string.value()?.into(),
                _ => lit.syntax().first_token()?.text().trim_matches('"').into(),
            };
            Some(AttrInput::Literal(value))
        } else if let Some(tt) = ast.token_tree() {
            Some(AttrInput::TokenTree(ast_to_token_tree(&tt)?.0))
        } else {
            None
        };
        Some(Attr { path, input })
    }
}

#[derive(Debug, Clone, Copy)]
pub struct AttrQuery<'a> {
    attrs: &'a Attrs,
    key: &'static str,
}

impl<'a> AttrQuery<'a> {
    pub fn tt_values(self) -> impl Iterator<Item = &'a Subtree> {
        self.attrs().filter_map(|attr| match attr.input.as_ref()? {
            AttrInput::TokenTree(it) => Some(it),
            _ => None,
        })
    }

    pub fn string_value(self) -> Option<&'a SmolStr> {
        self.attrs().find_map(|attr| match attr.input.as_ref()? {
            AttrInput::Literal(it) => Some(it),
            _ => None,
        })
    }

    pub fn exists(self) -> bool {
        self.attrs().next().is_some()
    }

    fn attrs(self) -> impl Iterator<Item = &'a Attr> {
        let key = self.key;
        self.attrs
            .iter()
            .filter(move |attr| attr.path.as_ident().map_or(false, |s| s.to_string() == key))
    }
}

fn attrs_from_ast<N>(src: AstId<N>, db: &dyn DefDatabase) -> Attrs
where
    N: ast::AttrsOwner,
{
    let src = InFile::new(src.file_id, src.to_node(db.upcast()));
    Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner))
}

fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase) -> Attrs {
    let tree = db.item_tree(id.file_id);
    let mod_item = N::id_to_mod_item(id.value);
    tree.attrs(mod_item.into()).clone()
}
<commit_msg>Properly fetch inner and outer attributes on hir-level<commit_after>//! A higher level attributes based on TokenTree, with also some shortcuts.

use std::{ops, sync::Arc};

use cfg::{CfgExpr, CfgOptions};
use either::Either;
use hir_expand::{hygiene::Hygiene, AstId, InFile};
use itertools::Itertools;
use mbe::ast_to_token_tree;
use syntax::{
    ast::{self, AstNode, AttrsOwner},
    match_ast, AstToken, SmolStr, SyntaxNode,
};
use tt::Subtree;

use crate::{
    db::DefDatabase,
    item_tree::{ItemTreeId, ItemTreeNode},
    nameres::ModuleSource,
    path::ModPath,
    src::HasChildSource,
    AdtId, AttrDefId, Lookup,
};

/// Holds documentation
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Documentation(String);

impl Documentation {
    pub fn as_str(&self) -> &str {
        &self.0
    }
}

impl Into<String> for Documentation {
    fn into(self) -> String {
        self.0
    }
}

#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct Attrs {
    entries: Option<Arc<[Attr]>>,
}

impl ops::Deref for Attrs {
    type Target = [Attr];

    fn deref(&self) -> &[Attr] {
        match &self.entries {
            Some(it) => &*it,
            None => &[],
        }
    }
}

impl Attrs {
    pub const EMPTY: Attrs = Attrs { entries: None };

    pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs {
        match def {
            AttrDefId::ModuleId(module) => {
                let def_map = db.crate_def_map(module.krate);
                let mod_data = &def_map[module.local_id];
                match mod_data.declaration_source(db) {
                    Some(it) => {
                        Attrs::from_attrs_owner(db, it.as_ref().map(|it| it as &dyn AttrsOwner))
                    }
                    None => Attrs::from_attrs_owner(
                        db,
                        mod_data.definition_source(db).as_ref().map(|src| match src {
                            ModuleSource::SourceFile(file) => file as &dyn AttrsOwner,
                            ModuleSource::Module(module) => module as &dyn AttrsOwner,
                        }),
                    ),
                }
            }
            AttrDefId::FieldId(it) => {
                let src = it.parent.child_source(db);
                match &src.value[it.local_id] {
                    Either::Left(_tuple) => Attrs::default(),
                    Either::Right(record) => Attrs::from_attrs_owner(db, src.with_value(record)),
                }
            }
            AttrDefId::EnumVariantId(var_id) => {
                let src = var_id.parent.child_source(db);
                let src = src.as_ref().map(|it| &it[var_id.local_id]);
                Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner))
            }
            AttrDefId::AdtId(it) => match it {
                AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db),
                AdtId::EnumId(it) => attrs_from_item_tree(it.lookup(db).id, db),
                AdtId::UnionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
            },
            AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db),
            AttrDefId::MacroDefId(it) => {
                it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db))
            }
            AttrDefId::ImplId(it) => attrs_from_item_tree(it.lookup(db).id, db),
            AttrDefId::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db),
            AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db),
            AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
            AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db),
        }
    }

    pub fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn AttrsOwner>) -> Attrs {
        let hygiene = Hygiene::new(db.upcast(), owner.file_id);
        Attrs::new(owner.value, &hygiene)
    }

    pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Attrs {
        let outer_docs = ast::CommentIter::from_syntax_node(owner.syntax()).map(|docs_text| {
            (
                docs_text.syntax().text_range().start(),
                docs_text.doc_comment().map(|doc| Attr {
                    input: Some(AttrInput::Literal(SmolStr::new(doc))),
                    path: ModPath::from(hir_expand::name!(doc)),
                }),
            )
        });
        let outer_attrs = owner.attrs().filter(|attr| attr.excl_token().is_none());
        let inner_attrs = inner_attributes(owner.syntax()).into_iter().flatten();
        let attrs = outer_attrs
            .chain(inner_attrs)
            .map(|attr| (attr.syntax().text_range().start(), Attr::from_src(attr, hygiene)));
        // sort here by syntax node offset because the source can have doc attributes and doc strings be interleaved
        let attrs: Vec<_> = outer_docs.chain(attrs).sorted_by_key(|&(offset, _)| offset).collect();
        let entries = if attrs.is_empty() {
            // Avoid heap allocation
            None
        } else {
            Some(attrs.into_iter().flat_map(|(_, attr)| attr).collect())
        };
        Attrs { entries }
    }

    pub fn merge(&self, other: Attrs) -> Attrs {
        match (&self.entries, &other.entries) {
            (None, None) => Attrs { entries: None },
            (Some(entries), None) | (None, Some(entries)) => {
                Attrs { entries: Some(entries.clone()) }
            }
            (Some(a), Some(b)) => {
                Attrs { entries: Some(a.iter().chain(b.iter()).cloned().collect()) }
            }
        }
    }

    pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> {
        AttrQuery { attrs: self, key }
    }

    pub fn cfg(&self) -> Option<CfgExpr> {
        // FIXME: handle cfg_attr :-)
        let mut cfgs = self.by_key("cfg").tt_values().map(CfgExpr::parse).collect::<Vec<_>>();
        match cfgs.len() {
            0 => None,
            1 => Some(cfgs.pop().unwrap()),
            _ => Some(CfgExpr::All(cfgs)),
        }
    }
    pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool {
        match self.cfg() {
            None => true,
            Some(cfg) => cfg_options.check(&cfg) != Some(false),
        }
    }

    pub fn docs(&self) -> Option<Documentation> {
        let docs = self
            .by_key("doc")
            .attrs()
            .flat_map(|attr| match attr.input.as_ref()? {
                AttrInput::Literal(s) => Some(s),
                AttrInput::TokenTree(_) => None,
            })
            .intersperse(&SmolStr::new_inline("\n"))
            .map(|it| it.as_str())
            .collect::<String>();
        if docs.is_empty() {
            None
        } else {
            Some(Documentation(docs.into()))
        }
    }
}

fn inner_attributes(syntax: &SyntaxNode) -> Option<impl Iterator<Item = ast::Attr>> {
    let (attrs, _docs) = match_ast! {
        match syntax {
            ast::SourceFile(it) => (it.attrs(), None::<ast::Comment>),
            ast::ExternBlock(it) => {
                let extern_item_list = it.extern_item_list()?;
                (extern_item_list.attrs(), None)
            },
            ast::Fn(it) => {
                let body = it.body()?;
                (body.attrs(), None)
            },
            ast::Impl(it) => {
                let assoc_item_list = it.assoc_item_list()?;
                (assoc_item_list.attrs(), None)
            },
            ast::Module(it) => {
                let item_list = it.item_list()?;
                (item_list.attrs(), None)
            },
            // FIXME: BlockExpr's only accept inner attributes in specific cases
            // Excerpt from the reference:
                // Block expressions accept outer and inner attributes, but only when they are the outer
                // expression of an expression statement or the final expression of another block expression.
            ast::BlockExpr(it) => return None,
            _ => return None,
        }
    };
    let attrs = attrs.filter(|attr| attr.excl_token().is_some());
    Some(attrs)
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Attr {
    pub(crate) path: ModPath,
    pub(crate) input: Option<AttrInput>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AttrInput {
    /// `#[attr = "string"]`
    Literal(SmolStr),
    /// `#[attr(subtree)]`
    TokenTree(Subtree),
}

impl Attr {
    fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> {
        let path = ModPath::from_src(ast.path()?, hygiene)?;
        let input = if let Some(lit) = ast.literal() {
            let value = match lit.kind() {
                ast::LiteralKind::String(string) => string.value()?.into(),
                _ => lit.syntax().first_token()?.text().trim_matches('"').into(),
            };
            Some(AttrInput::Literal(value))
        } else if let Some(tt) = ast.token_tree() {
            Some(AttrInput::TokenTree(ast_to_token_tree(&tt)?.0))
        } else {
            None
        };
        Some(Attr { path, input })
    }
}

#[derive(Debug, Clone, Copy)]
pub struct AttrQuery<'a> {
    attrs: &'a Attrs,
    key: &'static str,
}

impl<'a> AttrQuery<'a> {
    pub fn tt_values(self) -> impl Iterator<Item = &'a Subtree> {
        self.attrs().filter_map(|attr| match attr.input.as_ref()? {
            AttrInput::TokenTree(it) => Some(it),
            _ => None,
        })
    }

    pub fn string_value(self) -> Option<&'a SmolStr> {
        self.attrs().find_map(|attr| match attr.input.as_ref()? {
            AttrInput::Literal(it) => Some(it),
            _ => None,
        })
    }

    pub fn exists(self) -> bool {
        self.attrs().next().is_some()
    }

    fn attrs(self) -> impl Iterator<Item = &'a Attr> {
        let key = self.key;
        self.attrs
            .iter()
            .filter(move |attr| attr.path.as_ident().map_or(false, |s| s.to_string() == key))
    }
}

fn attrs_from_ast<N>(src: AstId<N>, db: &dyn DefDatabase) -> Attrs
where
    N: ast::AttrsOwner,
{
    let src = InFile::new(src.file_id, src.to_node(db.upcast()));
    Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner))
}

fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase) -> Attrs {
    let tree = db.item_tree(id.file_id);
    let mod_item = N::id_to_mod_item(id.value);
    tree.attrs(mod_item.into()).clone()
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate tensorflow_sys as ffi;

use libc::{c_int, c_void, int64_t, size_t};
use std::ffi::{CStr, CString};
use std::path::Path;

macro_rules! nonnull(
    ($pointer:expr) => ({
        let pointer = $pointer;
        assert!(!pointer.is_null());
        pointer
    });
);

macro_rules! ok(
    ($status:expr) => ({
        if ffi::TF_GetCode($status) != ffi::TF_OK {
            panic!(CStr::from_ptr(ffi::TF_Message($status)).to_string_lossy().into_owned());
        }
    });
);

fn main() {
    use std::mem::size_of;
    use std::ptr::{null, null_mut};
    use std::slice::from_raw_parts;

    unsafe {
        let options = nonnull!(ffi::TF_NewSessionOptions());
        let status = nonnull!(ffi::TF_NewStatus());
        let session = nonnull!(ffi::TF_NewDeprecatedSession(options, status));

        let graph = read("examples/assets/multiplication.pb"); // c = a * b
        ffi::TF_ExtendGraph(session,
                            graph.as_ptr() as *const _,
                            graph.len() as size_t,
                            status);
        ok!(status);

        let mut input_names = vec![];
        let mut inputs = vec![];

        let name = CString::new("a").unwrap();
        let mut data = vec![1f32, 2.0, 3.0];
        let dims = vec![data.len() as int64_t];
        let tensor = nonnull!(ffi::TF_NewTensor(ffi::TF_FLOAT,
                                                dims.as_ptr(),
                                                dims.len() as c_int,
                                                data.as_mut_ptr() as *mut _,
                                                data.len() as size_t,
                                                Some(noop),
                                                null_mut()));

        input_names.push(name.as_ptr());
        inputs.push(tensor);

        let name = CString::new("b").unwrap();
        let mut data = vec![4f32, 5.0, 6.0];
        let dims = vec![data.len() as int64_t];
        let tensor = nonnull!(ffi::TF_NewTensor(ffi::TF_FLOAT,
                                                dims.as_ptr(),
                                                dims.len() as c_int,
                                                data.as_mut_ptr() as *mut _,
                                                data.len() as size_t,
                                                Some(noop),
                                                null_mut()));

        input_names.push(name.as_ptr());
        inputs.push(tensor);

        let mut output_names = vec![];
        let mut outputs = vec![];

        let name = CString::new("c").unwrap();

        output_names.push(name.as_ptr());
        outputs.push(null_mut());

        let mut target_names = vec![];

        ffi::TF_Run(session,
                    null(),
                    input_names.as_mut_ptr(),
                    inputs.as_mut_ptr(),
                    input_names.len() as c_int,
                    output_names.as_mut_ptr(),
                    outputs.as_mut_ptr(),
                    output_names.len() as c_int,
                    target_names.as_mut_ptr(),
                    target_names.len() as c_int,
                    null_mut(),
                    status);
        ok!(status);

        let tensor = nonnull!(outputs[0]);
        let data = nonnull!(ffi::TF_TensorData(tensor)) as *const f32;
        let data = from_raw_parts(data, ffi::TF_TensorByteSize(tensor) / size_of::<f32>());

        assert_eq!(data, &[1.0 * 4.0, 2.0 * 5.0, 3.0 * 6.0]);

        ffi::TF_CloseDeprecatedSession(session, status);

        ffi::TF_DeleteTensor(tensor);
        ffi::TF_DeleteDeprecatedSession(session, status);
        ffi::TF_DeleteStatus(status);
        ffi::TF_DeleteSessionOptions(options);
    }

    unsafe extern "C" fn noop(_: *mut c_void, _: size_t, _: *mut c_void) {}
}

fn read<T: AsRef<Path>>(path: T) -> Vec<u8> {
    use std::fs::File;
    use std::io::Read;

    let mut buffer = vec![];
    let mut file = File::open(path).unwrap();
    file.read_to_end(&mut buffer).unwrap();
    buffer
}
<commit_msg>Let `noop()` use `std::os::raw::c_void` instead of `libc::c_void`<commit_after>extern crate libc;
extern crate tensorflow_sys as ffi;

use libc::{c_int, int64_t, size_t};
use std::ffi::{CStr, CString};
use std::path::Path;

macro_rules! nonnull(
    ($pointer:expr) => ({
        let pointer = $pointer;
        assert!(!pointer.is_null());
        pointer
    });
);

macro_rules! ok(
    ($status:expr) => ({
        if ffi::TF_GetCode($status) != ffi::TF_OK {
            panic!(CStr::from_ptr(ffi::TF_Message($status)).to_string_lossy().into_owned());
        }
    });
);

fn main() {
    use std::mem::size_of;
    use std::ptr::{null, null_mut};
    use std::slice::from_raw_parts;

    unsafe {
        let options = nonnull!(ffi::TF_NewSessionOptions());
        let status = nonnull!(ffi::TF_NewStatus());
        let session = nonnull!(ffi::TF_NewDeprecatedSession(options, status));

        let graph = read("examples/assets/multiplication.pb"); // c = a * b
        ffi::TF_ExtendGraph(session,
                            graph.as_ptr() as *const _,
                            graph.len() as size_t,
                            status);
        ok!(status);

        let mut input_names = vec![];
        let mut inputs = vec![];

        let name = CString::new("a").unwrap();
        let mut data = vec![1f32, 2.0, 3.0];
        let dims = vec![data.len() as int64_t];
        let tensor = nonnull!(ffi::TF_NewTensor(ffi::TF_FLOAT,
                                                dims.as_ptr(),
                                                dims.len() as c_int,
                                                data.as_mut_ptr() as *mut _,
                                                data.len() as size_t,
                                                Some(noop),
                                                null_mut()));

        input_names.push(name.as_ptr());
        inputs.push(tensor);

        let name = CString::new("b").unwrap();
        let mut data = vec![4f32, 5.0, 6.0];
        let dims = vec![data.len() as int64_t];
        let tensor = nonnull!(ffi::TF_NewTensor(ffi::TF_FLOAT,
                                                dims.as_ptr(),
                                                dims.len() as c_int,
                                                data.as_mut_ptr() as *mut _,
                                                data.len() as size_t,
                                                Some(noop),
                                                null_mut()));

        input_names.push(name.as_ptr());
        inputs.push(tensor);

        let mut output_names = vec![];
        let mut outputs = vec![];

        let name = CString::new("c").unwrap();

        output_names.push(name.as_ptr());
        outputs.push(null_mut());

        let mut target_names = vec![];

        ffi::TF_Run(session,
                    null(),
                    input_names.as_mut_ptr(),
                    inputs.as_mut_ptr(),
                    input_names.len() as c_int,
                    output_names.as_mut_ptr(),
                    outputs.as_mut_ptr(),
                    output_names.len() as c_int,
                    target_names.as_mut_ptr(),
                    target_names.len() as c_int,
                    null_mut(),
                    status);
        ok!(status);

        let tensor = nonnull!(outputs[0]);
        let data = nonnull!(ffi::TF_TensorData(tensor)) as *const f32;
        let data = from_raw_parts(data, ffi::TF_TensorByteSize(tensor) / size_of::<f32>());

        assert_eq!(data, &[1.0 * 4.0, 2.0 * 5.0, 3.0 * 6.0]);

        ffi::TF_CloseDeprecatedSession(session, status);

        ffi::TF_DeleteTensor(tensor);
        ffi::TF_DeleteDeprecatedSession(session, status);
        ffi::TF_DeleteStatus(status);
        ffi::TF_DeleteSessionOptions(options);
    }

    unsafe extern "C" fn noop(_: *mut std::os::raw::c_void, _: size_t, _: *mut std::os::raw::c_void) {}
}

fn read<T: AsRef<Path>>(path: T) -> Vec<u8> {
    use std::fs::File;
    use std::io::Read;

    let mut buffer = vec![];
    let mut file = File::open(path).unwrap();
    file.read_to_end(&mut buffer).unwrap();
    buffer
}
<|endoftext|>


<commit_before>use palette::{FromColor, Hsv, IntoColor, Lab, LinSrgb, Pixel, Shade, Srgb};

use image::{GenericImage, GenericImageView, RgbImage};

fn main() {
    //The same color in linear RGB, CIE L*a*b*, and HSV
    let rgb = LinSrgb::new(0.5, 0.0, 0.0);
    let lab = Lab::from_color(rgb);
    let hsv = Hsv::from_color(rgb);

    let mut image = RgbImage::new(220, 193);

    for i in 0..11 {
        let rgb1 = Srgb::from_linear(rgb.darken(0.05 * i as f32))
            .into_format()
            .into_raw();
        let rgb2 = Srgb::from_linear(rgb.lighten(0.05 * i as f32))
            .into_format()
            .into_raw();

        {
            let mut sub_image = image.sub_image(i as u32 * 20, 0, 20, 31);
            let (width, height) = sub_image.dimensions();
            for x in 0..width {
                for y in 0..height {
                    sub_image.put_pixel(x, y, image::Rgb(rgb1));
                }
            }
        }

        {
            let mut sub_image = image.sub_image(i as u32 * 20, 32, 20, 31);
            let (width, height) = sub_image.dimensions();
            for x in 0..width {
                for y in 0..height {
                    sub_image.put_pixel(x, y, image::Rgb(rgb2));
                }
            }
        }

        let lab1 = Srgb::from_linear(lab.darken(0.05 * i as f32).into_color())
            .into_format()
            .into_raw();
        let lab2 = Srgb::from_linear(lab.lighten(0.05 * i as f32).into_color())
            .into_format()
            .into_raw();

        {
            let mut sub_image = image.sub_image(i as u32 * 20, 65, 20, 31);
            let (width, height) = sub_image.dimensions();
            for x in 0..width {
                for y in 0..height {
                    sub_image.put_pixel(x, y, image::Rgb(lab1));
                }
            }
        }

        {
            let mut sub_image = image.sub_image(i as u32 * 20, 97, 20, 31);
            let (width, height) = sub_image.dimensions();
            for x in 0..width {
                for y in 0..height {
                    sub_image.put_pixel(x, y, image::Rgb(lab2));
                }
            }
        }

        let hsv1 = Srgb::from_linear(hsv.darken(0.05 * i as f32).into_color())
            .into_format()
            .into_raw();
        let hsv2 = Srgb::from_linear(hsv.lighten(0.05 * i as f32).into_color())
            .into_format()
            .into_raw();

        {
            let mut sub_image = image.sub_image(i as u32 * 20, 130, 20, 31);
            let (width, height) = sub_image.dimensions();
            for x in 0..width {
                for y in 0..height {
                    sub_image.put_pixel(x, y, image::Rgb(hsv1));
                }
            }
        }

        {
            let mut sub_image = image.sub_image(i as u32 * 20, 162, 20, 31);
            let (width, height) = sub_image.dimensions();
            for x in 0..width {
                for y in 0..height {
                    sub_image.put_pixel(x, y, image::Rgb(hsv2));
                }
            }
        }
    }

    let _ = std::fs::create_dir("example-data/output");
    match image.save("example-data/output/shade.png") {
        Ok(()) => println!("see 'example-data/output/shade.png' for the result"),
        Err(e) => println!("failed to write 'example-data/output/shade.png': {}", e),
    }
}
<commit_msg>Increase the contrasts in the shade example file<commit_after>use palette::{FromColor, Hsv, IntoColor, Lab, LinSrgb, Pixel, Shade, Srgb};

use image::{GenericImage, GenericImageView, RgbImage};

fn main() {
    //The same color in linear RGB, CIE L*a*b*, and HSV
    let rgb = LinSrgb::new(0.5, 0.0, 0.0);
    let lab = Lab::from_color(rgb);
    let hsv = Hsv::from_color(rgb);

    let mut image = RgbImage::new(220, 193);

    for i in 0..11 {
        let rgb1 = Srgb::from_linear(rgb.darken(0.1 * i as f32))
            .into_format()
            .into_raw();
        let rgb2 = Srgb::from_linear(rgb.lighten(0.1 * i as f32))
            .into_format()
            .into_raw();

        {
            let mut sub_image = image.sub_image(i as u32 * 20, 0, 20, 31);
            let (width, height) = sub_image.dimensions();
            for x in 0..width {
                for y in 0..height {
                    sub_image.put_pixel(x, y, image::Rgb(rgb1));
                }
            }
        }

        {
            let mut sub_image = image.sub_image(i as u32 * 20, 32, 20, 31);
            let (width, height) = sub_image.dimensions();
            for x in 0..width {
                for y in 0..height {
                    sub_image.put_pixel(x, y, image::Rgb(rgb2));
                }
            }
        }

        let lab1 = Srgb::from_linear(lab.darken(0.1 * i as f32).into_color())
            .into_format()
            .into_raw();
        let lab2 = Srgb::from_linear(lab.lighten(0.1 * i as f32).into_color())
            .into_format()
            .into_raw();

        {
            let mut sub_image = image.sub_image(i as u32 * 20, 65, 20, 31);
            let (width, height) = sub_image.dimensions();
            for x in 0..width {
                for y in 0..height {
                    sub_image.put_pixel(x, y, image::Rgb(lab1));
                }
            }
        }

        {
            let mut sub_image = image.sub_image(i as u32 * 20, 97, 20, 31);
            let (width, height) = sub_image.dimensions();
            for x in 0..width {
                for y in 0..height {
                    sub_image.put_pixel(x, y, image::Rgb(lab2));
                }
            }
        }

        let hsv1 = Srgb::from_linear(hsv.darken(0.1 * i as f32).into_color())
            .into_format()
            .into_raw();
        let hsv2 = Srgb::from_linear(hsv.lighten(0.1 * i as f32).into_color())
            .into_format()
            .into_raw();

        {
            let mut sub_image = image.sub_image(i as u32 * 20, 130, 20, 31);
            let (width, height) = sub_image.dimensions();
            for x in 0..width {
                for y in 0..height {
                    sub_image.put_pixel(x, y, image::Rgb(hsv1));
                }
            }
        }

        {
            let mut sub_image = image.sub_image(i as u32 * 20, 162, 20, 31);
            let (width, height) = sub_image.dimensions();
            for x in 0..width {
                for y in 0..height {
                    sub_image.put_pixel(x, y, image::Rgb(hsv2));
                }
            }
        }
    }

    let _ = std::fs::create_dir("example-data/output");
    match image.save("example-data/output/shade.png") {
        Ok(()) => println!("see 'example-data/output/shade.png' for the result"),
        Err(e) => println!("failed to write 'example-data/output/shade.png': {}", e),
    }
}
<|endoftext|>


<commit_before>use rocket::response::NamedFile;
use std::io;
use std::path::{Path, PathBuf};

#[get("/<path..>", rank = 5)]
fn all(path: PathBuf) -> io::Result<NamedFile> {
    NamedFile::open(Path::new("static/").join(path))
}
<commit_msg>Return 404 on missing static file in todo example.<commit_after>use std::path::{Path, PathBuf};
use rocket::response::NamedFile;

#[get("/<path..>", rank = 5)]
fn all(path: PathBuf) -> Option<NamedFile> {
    NamedFile::open(Path::new("static/").join(path)).ok()
}
<|endoftext|>


<commit_before>// This example uses the callback mechanism to find out which file descriptors
// c-ares cares about.  This is a good fit for an event loop; here we use mio.
extern crate c_ares;
extern crate mio;

use std::collections::HashSet;
use std::error::Error;
use std::net::IpAddr;
use std::sync::mpsc;
use std::thread;

// Messages for the event loop.
enum CAresHandlerMessage {
    // 'Notify me when this file descriptor becomes readable, or writable'
    // The first bool is for 'readable' and the second is for 'writable'.  It's
    // allowed to set both of these - or neither, meaning 'I am no longer
    // interested in this file descriptor'.
    RegisterInterest(c_ares::Socket, bool, bool),

    // 'Shut down'.
    ShutDown,
}

struct CAresEventHandler {
    // Since the event handler owns the Channel, it's tricky to submit further
    // queries once the event loop is running.  If you want to do that,
    // either:
    //
    // -  share the Channel by using an Arc<Mutex<c_ares::Channel>>, OR
    // -  send requests to the event handler as messages, and have it make the
    //    queries
    ares_channel: c_ares::Channel,
    tracked_fds: HashSet<c_ares::Socket>,
}

impl mio::Handler for CAresEventHandler {
    type Timeout = ();
    type Message = CAresHandlerMessage;

    // mio notifies us that a file descriptor is readable or writable, so we
    // tell the Channel the same.
    fn ready(
        &mut self,
        _event_loop: &mut mio::EventLoop<CAresEventHandler>,
        token: mio::Token,
        events: mio::EventSet) {
        let fd = token.as_usize() as c_ares::Socket;
        let read_fd = if events.is_readable() {
            fd
        } else {
            c_ares::SOCKET_BAD
        };
        let write_fd = if events.is_writable() {
            fd
        } else {
            c_ares::SOCKET_BAD
        };
        self.ares_channel.process_fd(read_fd, write_fd);
    }

    // Process received messages.  Either:
    // - we're asked to register interest (or non-interest) in a file
    // descriptor
    // - we're asked to shut down the event loop.
    fn notify(
        &mut self,
        event_loop:&mut mio::EventLoop<CAresEventHandler>,
        msg: Self::Message) {
        match msg {
            CAresHandlerMessage::RegisterInterest(fd, read, write) => {
                let efd = mio::unix::EventedFd(&fd);
                if !read && !write {
                    self.tracked_fds.remove(&fd);
                    event_loop
                        .deregister(&efd)
                        .expect("failed to deregister interest");
                } else {
                    let mut interest = mio::EventSet::none();
                    if read {
                        interest = interest | mio::EventSet::readable();
                    }
                    if write {
                        interest = interest | mio::EventSet::writable();
                    }
                    let token = mio::Token(fd as usize);
                    let register_result = if !self.tracked_fds.insert(fd) {
                        event_loop
                            .reregister(
                                &efd,
                                token,
                                interest,
                                mio::PollOpt::edge())
                    } else {
                        event_loop
                            .register(
                                &efd,
                                token,
                                interest,
                                mio::PollOpt::edge())
                    };
                    register_result.expect("failed to register interest");
                }
            },

            CAresHandlerMessage::ShutDown => event_loop.shutdown(),
        }
    }

    // We run a recurring timer so that we can spot non-responsive servers.
    //
    // In that case we won't get a callback saying that anything is happening
    // on any file descriptor, but nevertheless need to give the Channel an
    // opportunity to notice that it has timed-out requests pending.
    fn timeout(
        &mut self,
        event_loop: &mut mio::EventLoop<CAresEventHandler>,
        _timeout: Self::Timeout) {
        self.ares_channel.process_fd(c_ares::SOCKET_BAD, c_ares::SOCKET_BAD);
        event_loop.timeout_ms((), 500).unwrap();
    }
}

impl CAresEventHandler {
    fn new(ares_channel: c_ares::Channel) -> CAresEventHandler {
        CAresEventHandler {
            ares_channel: ares_channel,
            tracked_fds: HashSet::new(),
        }
    }
}

fn print_host_results(result: Result<c_ares::HostResults, c_ares::AresError>) {
    match result {
        Err(e) => {
            println!("Host lookup failed with error '{}'", e.description());
        }
        Ok(host_results) => {
            println!("Successful host lookup...");
            println!("Hostname: {}", host_results.hostname());
            for alias in host_results.aliases() {
                println!("Alias: {}", alias);
            }
            for address in host_results.addresses() {
                match address {
                    IpAddr::V4(v4) => println!("IPv4: {}", v4),
                    IpAddr::V6(v6) => println!("IPv6: {}", v6),
                }
            }
        }
    }
}

pub fn main() {
    // Create an event loop.
    let mut event_loop = mio::EventLoop::new()
        .expect("failed to create event loop");
    let event_loop_channel = event_loop.channel();

    // Socket state callback for the c_ares::Channel will be to kick the event
    // loop.
    let event_loop_channel_clone = event_loop_channel.clone();
    let sock_callback =
        move |fd: c_ares::Socket, readable: bool, writable: bool| {
        let _ = event_loop_channel_clone
            .send(
                CAresHandlerMessage::RegisterInterest(fd, readable, writable));
    };

    // Create a c_ares::Channel.
    let mut options = c_ares::Options::new();
    options
        .set_socket_state_callback(sock_callback)
        .set_flags(c_ares::flags::STAYOPEN | c_ares::flags::EDNS)
        .set_timeout(500)
        .set_tries(3);
    let mut ares_channel = c_ares::Channel::new(options)
        .expect("Failed to create channel");
    ares_channel.set_servers(&["8.8.8.8"]).expect("Failed to set servers");

    // Set up some queries.
    let (results_tx, results_rx) = mpsc::channel();
    let tx = results_tx.clone();
    ares_channel.get_host_by_name(
        "google.com",
        c_ares::AddressFamily::INET,
        move |result| {
            println!("");
            print_host_results(result);
            tx.send(()).unwrap()
        }
    );

    let tx = results_tx.clone();
    let ipv4 = "216.58.208.78".parse::<IpAddr>().unwrap();
    ares_channel.get_host_by_address(&ipv4, move |results| {
        println!("");
        print_host_results(results);
        tx.send(()).unwrap()
    });

    let tx = results_tx.clone();
    let ipv6 = "2a00:1450:4009:80a::200e".parse::<IpAddr>().unwrap();
    ares_channel.get_host_by_address(&ipv6, move |results| {
        println!("");
        print_host_results(results);
        tx.send(()).unwrap()
    });

    // Set the first instance of the recurring timer on the event loop.
    event_loop.timeout_ms((), 500).unwrap();

    // Kick off the event loop.
    let mut event_handler = CAresEventHandler::new(ares_channel);
    let handle = thread::spawn(move || {
        event_loop
            .run(&mut event_handler)
            .expect("failed to run event loop")
    });

    // Wait for results to roll in.
    for _ in 0..3 {
        results_rx.recv().unwrap();
    }

    // Shut down the event loop and wait for it to finish.
    event_loop_channel
        .send(CAresHandlerMessage::ShutDown)
        .expect("failed to shut down event loop");
    handle.join().unwrap();
}
<commit_msg>Better example IPv6 lookup<commit_after>// This example uses the callback mechanism to find out which file descriptors
// c-ares cares about.  This is a good fit for an event loop; here we use mio.
extern crate c_ares;
extern crate mio;

use std::collections::HashSet;
use std::error::Error;
use std::net::IpAddr;
use std::sync::mpsc;
use std::thread;

// Messages for the event loop.
enum CAresHandlerMessage {
    // 'Notify me when this file descriptor becomes readable, or writable'
    // The first bool is for 'readable' and the second is for 'writable'.  It's
    // allowed to set both of these - or neither, meaning 'I am no longer
    // interested in this file descriptor'.
    RegisterInterest(c_ares::Socket, bool, bool),

    // 'Shut down'.
    ShutDown,
}

struct CAresEventHandler {
    // Since the event handler owns the Channel, it's tricky to submit further
    // queries once the event loop is running.  If you want to do that,
    // either:
    //
    // -  share the Channel by using an Arc<Mutex<c_ares::Channel>>, OR
    // -  send requests to the event handler as messages, and have it make the
    //    queries
    ares_channel: c_ares::Channel,
    tracked_fds: HashSet<c_ares::Socket>,
}

impl mio::Handler for CAresEventHandler {
    type Timeout = ();
    type Message = CAresHandlerMessage;

    // mio notifies us that a file descriptor is readable or writable, so we
    // tell the Channel the same.
    fn ready(
        &mut self,
        _event_loop: &mut mio::EventLoop<CAresEventHandler>,
        token: mio::Token,
        events: mio::EventSet) {
        let fd = token.as_usize() as c_ares::Socket;
        let read_fd = if events.is_readable() {
            fd
        } else {
            c_ares::SOCKET_BAD
        };
        let write_fd = if events.is_writable() {
            fd
        } else {
            c_ares::SOCKET_BAD
        };
        self.ares_channel.process_fd(read_fd, write_fd);
    }

    // Process received messages.  Either:
    // - we're asked to register interest (or non-interest) in a file
    // descriptor
    // - we're asked to shut down the event loop.
    fn notify(
        &mut self,
        event_loop:&mut mio::EventLoop<CAresEventHandler>,
        msg: Self::Message) {
        match msg {
            CAresHandlerMessage::RegisterInterest(fd, read, write) => {
                let efd = mio::unix::EventedFd(&fd);
                if !read && !write {
                    self.tracked_fds.remove(&fd);
                    event_loop
                        .deregister(&efd)
                        .expect("failed to deregister interest");
                } else {
                    let mut interest = mio::EventSet::none();
                    if read {
                        interest = interest | mio::EventSet::readable();
                    }
                    if write {
                        interest = interest | mio::EventSet::writable();
                    }
                    let token = mio::Token(fd as usize);
                    let register_result = if !self.tracked_fds.insert(fd) {
                        event_loop
                            .reregister(
                                &efd,
                                token,
                                interest,
                                mio::PollOpt::edge())
                    } else {
                        event_loop
                            .register(
                                &efd,
                                token,
                                interest,
                                mio::PollOpt::edge())
                    };
                    register_result.expect("failed to register interest");
                }
            },

            CAresHandlerMessage::ShutDown => event_loop.shutdown(),
        }
    }

    // We run a recurring timer so that we can spot non-responsive servers.
    //
    // In that case we won't get a callback saying that anything is happening
    // on any file descriptor, but nevertheless need to give the Channel an
    // opportunity to notice that it has timed-out requests pending.
    fn timeout(
        &mut self,
        event_loop: &mut mio::EventLoop<CAresEventHandler>,
        _timeout: Self::Timeout) {
        self.ares_channel.process_fd(c_ares::SOCKET_BAD, c_ares::SOCKET_BAD);
        event_loop.timeout_ms((), 500).unwrap();
    }
}

impl CAresEventHandler {
    fn new(ares_channel: c_ares::Channel) -> CAresEventHandler {
        CAresEventHandler {
            ares_channel: ares_channel,
            tracked_fds: HashSet::new(),
        }
    }
}

fn print_host_results(result: Result<c_ares::HostResults, c_ares::AresError>) {
    match result {
        Err(e) => {
            println!("Host lookup failed with error '{}'", e.description());
        }
        Ok(host_results) => {
            println!("Successful host lookup...");
            println!("Hostname: {}", host_results.hostname());
            for alias in host_results.aliases() {
                println!("Alias: {}", alias);
            }
            for address in host_results.addresses() {
                match address {
                    IpAddr::V4(v4) => println!("IPv4: {}", v4),
                    IpAddr::V6(v6) => println!("IPv6: {}", v6),
                }
            }
        }
    }
}

pub fn main() {
    // Create an event loop.
    let mut event_loop = mio::EventLoop::new()
        .expect("failed to create event loop");
    let event_loop_channel = event_loop.channel();

    // Socket state callback for the c_ares::Channel will be to kick the event
    // loop.
    let event_loop_channel_clone = event_loop_channel.clone();
    let sock_callback =
        move |fd: c_ares::Socket, readable: bool, writable: bool| {
        let _ = event_loop_channel_clone
            .send(
                CAresHandlerMessage::RegisterInterest(fd, readable, writable));
    };

    // Create a c_ares::Channel.
    let mut options = c_ares::Options::new();
    options
        .set_socket_state_callback(sock_callback)
        .set_flags(c_ares::flags::STAYOPEN | c_ares::flags::EDNS)
        .set_timeout(500)
        .set_tries(3);
    let mut ares_channel = c_ares::Channel::new(options)
        .expect("Failed to create channel");
    ares_channel.set_servers(&["8.8.8.8"]).expect("Failed to set servers");

    // Set up some queries.
    let (results_tx, results_rx) = mpsc::channel();
    let tx = results_tx.clone();
    ares_channel.get_host_by_name(
        "google.com",
        c_ares::AddressFamily::INET,
        move |result| {
            println!("");
            print_host_results(result);
            tx.send(()).unwrap()
        }
    );

    let tx = results_tx.clone();
    let ipv4 = "216.58.208.78".parse::<IpAddr>().unwrap();
    ares_channel.get_host_by_address(&ipv4, move |results| {
        println!("");
        print_host_results(results);
        tx.send(()).unwrap()
    });

    let tx = results_tx.clone();
    let ipv6 = "2001:4860:4860::8888".parse::<IpAddr>().unwrap();
    ares_channel.get_host_by_address(&ipv6, move |results| {
        println!("");
        print_host_results(results);
        tx.send(()).unwrap()
    });

    // Set the first instance of the recurring timer on the event loop.
    event_loop.timeout_ms((), 500).unwrap();

    // Kick off the event loop.
    let mut event_handler = CAresEventHandler::new(ares_channel);
    let handle = thread::spawn(move || {
        event_loop
            .run(&mut event_handler)
            .expect("failed to run event loop")
    });

    // Wait for results to roll in.
    for _ in 0..3 {
        results_rx.recv().unwrap();
    }

    // Shut down the event loop and wait for it to finish.
    event_loop_channel
        .send(CAresHandlerMessage::ShutDown)
        .expect("failed to shut down event loop");
    handle.join().unwrap();
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;

use std::fs::File;
use std::io::{Read,Write};

// [Macro clap::clap_app](https://docs.rs/clap/2.33.0/clap/macro.clap_app.html)

fn gpu_freq_stat(tail: &str) -> String {
    format!("/sys/class/devfreq/gpufreq/{}", tail)
}

fn ddr_freq_stat(tail: &str) -> String {
    format!("/sys/class/devfreq/ddrfreq/{}", tail)
}

fn cpu_freq_stat(id: usize, tail: &str) -> String {
    format!("/sys/devices/system/cpu/cpu{}/cpufreq/{}", id, tail)
}

struct AvailableFrequencies
{
    gpu: Vec<u64>,
    ddr: Vec<u64>,
    cpu_little: Vec<u64>,
    cpu_medium: Vec<u64>,
    cpu_big: Vec<u64>,
}

struct ActualFrequencies
{
    gpu: u64,
    ddr: u64,
    cpu_little: u64,
    cpu_medium: u64,
    cpu_big: u64,
}

impl ActualFrequencies {
    fn cons() -> ActualFrequencies {
        ActualFrequencies { gpu: 0, ddr: 0, cpu_little: 0, cpu_medium: 0, cpu_big: 0, }
    }

    fn init(gpu: u64, ddr: u64, cpu_l: u64, cpu_m: u64, cpu_b: u64) -> ActualFrequencies {
        ActualFrequencies { gpu: gpu, ddr: ddr, cpu_little: cpu_l, cpu_medium: cpu_m, cpu_big: cpu_b, }
    }
}

fn read_sys_record(sys_path: &str) -> String {
    let mut read_buf = String::new();
    if let Ok(mut file) = File::open(sys_path) {
        let sz = file.read_to_string(&mut read_buf).expect("cannot read sysfs");
        assert!(sz > 0);
    }
    read_buf.trim().to_string()
}

fn read_sys_as_u64(sys_path: &str) -> u64 {
    let str_buf = read_sys_record(sys_path);
    str_buf.parse().expect("cannot parse to u64")
}

fn read_gpu_frequency() -> u64 {
    read_sys_as_u64(&gpu_freq_stat("cur_freq"))
}

fn get_device_available_frequencies() -> AvailableFrequencies {
    fn get_sys_freqs(sys_path: &str) -> Vec<u64> {
        let mut freqs: Vec<u64> = Vec::new();
        if let Ok(mut file) = File::open(sys_path) {
            let mut read_buf = String::new();
            let sz = file.read_to_string(&mut read_buf).expect("cannot read sysfs");
            assert!(sz > 0);
            let vec: Vec<&str> = read_buf.trim().split(' ').collect();
            freqs = vec.into_iter().map(|x| x.parse().expect("cannot parse to u64")).collect();
        }
        freqs
    }
    AvailableFrequencies { gpu: get_sys_freqs(&gpu_freq_stat("available_frequencies")),
                           ddr: Vec::new(), cpu_little: Vec::new(), cpu_medium: Vec::new(), cpu_big: Vec::new(), }
}

fn main() {
    let matches = clap_app!(gf =>
        (version: "0.1")
        (author: "Alexander Samoilov <alexander.samoilov@gmail.com>")
        (about: "ARM Android cross-compile sample project")
        (@arg AVAILABLE: -a --available "display available frequencies")
        (@arg SHOW: -s --show "show current frequencies")
        (@arg SET_GPU: -g --gpu +takes_value "set GPU frequency")
        (@arg LOCK_FREQ: -l --lock ... +takes_value "lock GPU/DDR/CPU frequencies")
        (@arg VERBOSE: -v --verbose "be verbose")
    ).get_matches();

    if matches.is_present("VERBOSE") {
        println!("gf_freq command line args matches: {:?}", matches);
    }

    if matches.is_present("AVAILABLE") {
        let avail = get_device_available_frequencies();
        println!("GPU available frequencies: {:?}", avail.gpu);
    }

    if matches.is_present("SHOW") {
        println!("show device current frequencies: gpu: {}", read_gpu_frequency());
    }

    if let Ok(gpu_freq) = value_t!(matches, "SET_GPU", u64) {
        println!("Set GPU frequency to: {}", gpu_freq);
    }

    if let Ok(freq_vec) = values_t!(matches, "LOCK_FREQ", u64) {
        println!("freq_vec: {:?}", freq_vec);
        for v in freq_vec {
            println!("Set frequency to: {}", v);
        }
    }

}
<commit_msg>lock gpu freq.<commit_after>#[macro_use]
extern crate clap;

use std::fs::File;
use std::io::{Read,Write};

// [Macro clap::clap_app](https://docs.rs/clap/2.33.0/clap/macro.clap_app.html)

fn gpu_freq_stat(tail: &str) -> String {
    format!("/sys/class/devfreq/gpufreq/{}", tail)
}

fn ddr_freq_stat(tail: &str) -> String {
    format!("/sys/class/devfreq/ddrfreq/{}", tail)
}

fn cpu_freq_stat(id: usize, tail: &str) -> String {
    format!("/sys/devices/system/cpu/cpu{}/cpufreq/{}", id, tail)
}

struct AvailableFrequencies
{
    gpu: Vec<u64>,
    ddr: Vec<u64>,
    cpu_little: Vec<u64>,
    cpu_medium: Vec<u64>,
    cpu_big: Vec<u64>,
}

struct ActualFrequencies
{
    gpu: u64,
    ddr: u64,
    cpu_little: u64,
    cpu_medium: u64,
    cpu_big: u64,
}

impl ActualFrequencies {
    fn cons() -> ActualFrequencies {
        ActualFrequencies { gpu: 0, ddr: 0, cpu_little: 0, cpu_medium: 0, cpu_big: 0, }
    }

    fn init(gpu: u64, ddr: u64, cpu_l: u64, cpu_m: u64, cpu_b: u64) -> ActualFrequencies {
        ActualFrequencies { gpu: gpu, ddr: ddr, cpu_little: cpu_l, cpu_medium: cpu_m, cpu_big: cpu_b, }
    }
}

fn read_sys_str(sys_path: &str) -> String {
    let mut read_buf = String::new();
    if let Ok(mut file) = File::open(sys_path) {
        let sz = file.read_to_string(&mut read_buf).expect("cannot read from sysfs");
        assert!(sz > 0);
    }
    read_buf.trim().to_string()
}

fn read_sys_as_u64(sys_path: &str) -> u64 {
    let str_buf = read_sys_str(sys_path);
    str_buf.parse().expect("cannot parse to u64")
}

fn write_sys_str(sys_path: &str, val: &str) {
    if let Ok(mut file) = File::create(sys_path) {
        let sz = file.write(&val.as_bytes()).expect("cannot write to sysfs");
        assert!(sz > 0);
    }
}

fn write_sys_u64(sys_path: &str, val: u64) {
    write_sys_str(sys_path, &format!("{}", val))
}

fn read_gpu_frequency() -> u64 {
    read_sys_as_u64(&gpu_freq_stat("cur_freq"))
}

fn get_device_available_frequencies() -> AvailableFrequencies {
    fn get_sys_freqs(sys_path: &str) -> Vec<u64> {
        let mut freqs: Vec<u64> = Vec::new();
        if let Ok(mut file) = File::open(sys_path) {
            let mut read_buf = String::new();
            let sz = file.read_to_string(&mut read_buf).expect("cannot read sysfs");
            assert!(sz > 0);
            let vec: Vec<&str> = read_buf.trim().split(' ').collect();
            freqs = vec.into_iter().map(|x| x.parse().expect("cannot parse to u64")).collect();
        }
        freqs
    }
    AvailableFrequencies { gpu: get_sys_freqs(&gpu_freq_stat("available_frequencies")),
                           ddr: Vec::new(), cpu_little: Vec::new(), cpu_medium: Vec::new(), cpu_big: Vec::new(), }
}

fn lock_sys_freq(freq: u64, cur_freq: u64, sys_min_freq: &str, sys_max_freq: &str)
{
    if freq < cur_freq {
        write_sys_u64(sys_min_freq, freq);
        write_sys_u64(sys_max_freq, freq)
    } else if freq > cur_freq {
        write_sys_u64(sys_max_freq, freq);
        write_sys_u64(sys_min_freq, freq)
    }
}

fn lock_gpu_frequency(freq: u64)
{
    lock_sys_freq(freq, read_gpu_frequency(), &gpu_freq_stat("min_freq"), &gpu_freq_stat("max_freq"))
}

fn main() {
    let matches = clap_app!(gf =>
        (version: "0.1")
        (author: "Alexander Samoilov <alexander.samoilov@gmail.com>")
        (about: "ARM Android cross-compile sample project")
        (@arg AVAILABLE: -a --available "display available frequencies")
        (@arg SHOW: -s --show "show current frequencies")
        (@arg SET_GPU: -g --gpu +takes_value "set GPU frequency")
        (@arg LOCK_FREQ: -l --lock ... +takes_value "lock GPU/DDR/CPU frequencies")
        (@arg VERBOSE: -v --verbose "be verbose")
    ).get_matches();

    if matches.is_present("VERBOSE") {
        println!("gf_freq command line args matches: {:?}", matches)
    }

    if matches.is_present("AVAILABLE") {
        let avail = get_device_available_frequencies();
        println!("GPU available frequencies: {:?}", avail.gpu)
    }

    if matches.is_present("SHOW") {
        println!("show device current frequencies: gpu: {}", read_gpu_frequency());
    }

    if let Ok(gpu_freq) = value_t!(matches, "SET_GPU", u64) {
        println!("Set GPU frequency to: {}", gpu_freq);
        lock_gpu_frequency(gpu_freq)
    }

    if let Ok(freq_vec) = values_t!(matches, "LOCK_FREQ", u64) {
        println!("freq_vec: {:?}", freq_vec);
        for v in freq_vec {
            println!("Set frequency to: {}", v)
        }
    }

}
<|endoftext|>