<commit_before>use std::collections::HashMap;
use std::fmt::Write;

use syntex_syntax::{ast, parse};
use syntex_syntax::ptr::P;
use syntex_syntax::symbol::Symbol;
use syntex_syntax::print::pprust;
use syntex_syntax::parse::ParseSess;

use ForeignerClassInfo;
use ForeignTypesMap;
use MethodVariant;
use types_map::{MethodSignatureWithForeignTypes, unpack_unique_typename};
use java_jni::java_code;
use utils::fmt_write_err_map;

pub(crate) fn generate_rust_code(parse_sess: &ParseSess,
                                 types_map: &mut ForeignTypesMap,
                                 package_name: &str,
                                 class: &ForeignerClassInfo,
                                 methods_sign: &[MethodSignatureWithForeignTypes])
                                 -> Result<Vec<P<ast::Item>>, String> {
    let mut gen_fnames = HashMap::<String, usize>::new(); //handle overload names
    for method in &class.methods {
        let val_ref = gen_fnames.entry(java_code::method_name(&*method));
        *val_ref.or_insert(0) += 1;
    }

    let get_constructor_ret_type = |cls: &ForeignerClassInfo| -> Result<ast::Ty, String> {
        let ret: ast::Ty = cls.constructor_ret_type
            .as_ref()
            .ok_or_else(|| {
                            format!("package_name {}, class_name {}, have methods, \
                                    but no constructor",
                                    package_name,
                                    class.name)
                        })?
            .clone();
        Ok(ret)
    };

    let get_real_constructor_ret_type = |cls: &ForeignerClassInfo| -> Result<ast::Ty, String> {
        let ret: ast::Ty = cls.this_type_for_method
            .as_ref()
            .ok_or_else(|| {
                            format!("package_name {}, class_name {}, have methods, \
                                    but no constructor this type for method",
                                    package_name,
                                    class.name)
                        })?
            .clone();
        Ok(ret)
    };

    let mut gen_code = Vec::<P<ast::Item>>::new();

    let mut have_constructor = false;

    for (method_idx, method) in class.methods.iter().enumerate() {
        let java_method_name = java_code::method_name(&*method);
        let method_overloading = gen_fnames[&java_method_name] > 1;
        let jni_func_name = generate_jni_func_name(package_name,
                                                   &class.name,
                                                   &java_method_name,
                                                   &methods_sign[method_idx],
                                                   method_overloading);
        let n_args = methods_sign[method_idx].rust_input.len();
        let (mut deps_code_in, convert_input_code) =
            types_map
                .convert_foreign_input(parse_sess,
                                       &*method,
                                       &methods_sign[method_idx],
                                       (0..n_args).map(|v| format!("a_{}", v)))?;
        let args_names = methods_sign[method_idx]
            .rust_input
            .iter()
            .enumerate()
            .map(|a| format!("a_{}, ", a.0))
            .fold(String::new(), |acc, x| acc + &x);
        let decl_func_args = generate_jni_args_with_types(&methods_sign[method_idx])?;

        let mut code = String::new();
        match method.variant {
            MethodVariant::StaticMethod => {
                let (mut deps_code_out, convert_output_code) =
                    types_map
                        .convert_output_to_foreign(parse_sess,
                                                   &*method,
                                                   &methods_sign[method_idx],
                                                   "ret")?;
                write!(&mut code, r#"
#[allow(non_snake_case, unused_variables, unused_mut)]
#[no_mangle]
pub fn {func_name}(env: *mut JNIEnv, _: jclass, {decl_func_args}) -> {jni_ret_type} {{
{convert_input_code}
    let mut ret = {rust_func_name}({args_names});
{convert_output_code}
    ret
}}
"#,
                       func_name = jni_func_name,
                       decl_func_args = decl_func_args,
                       jni_ret_type = unpack_unique_typename(methods_sign[method_idx].rust_output),
                       convert_input_code = convert_input_code,
                       rust_func_name = method.rust_id,
                       args_names = args_names,
                       convert_output_code = convert_output_code,
                ).map_err(fmt_write_err_map)?;

                for item in deps_code_in.drain(..).chain(deps_code_out.drain(..)) {
                    gen_code.push(P(item));
                }
                let mut jni_func_items = code_to_item(&code);
                gen_code.extend(jni_func_items.drain(..));
            }
            MethodVariant::Method => {
                let constructor_ret_type = get_real_constructor_ret_type(class)?;

                let (mut deps_code_out, convert_output_code) =
                    types_map
                        .convert_output_to_foreign(parse_sess,
                                                   &*method,
                                                   &methods_sign[method_idx],
                                                   "ret")?;
                write!(&mut code, r#"
#[allow(non_snake_case, unused_variables, unused_mut)]
#[no_mangle]
pub fn {func_name}(env: *mut JNIEnv, _: jclass, this: jlong, {decl_func_args}) -> {jni_ret_type} {{
{convert_input_code}
    let this: &mut {this_type} = unsafe {{
        jlong_to_pointer::<{this_type}>(this).as_mut().unwrap()
    }};
{convert_this}
    let mut ret = {rust_func_name}(&mut *this, {args_names});
{convert_output_code}
    ret
}}
"#,
                       func_name = jni_func_name,
                       decl_func_args = decl_func_args,
                       convert_input_code = convert_input_code,
                       jni_ret_type = unpack_unique_typename(methods_sign[method_idx].rust_output),
                       this_type = pprust::ty_to_string(&constructor_ret_type),
                       convert_this = generate_rust_to_convert_this(class, &constructor_ret_type)?,
                       rust_func_name = method.rust_id,
                       args_names = args_names,
                       convert_output_code = convert_output_code,
                ).map_err(fmt_write_err_map)?;
                for item in deps_code_in.drain(..).chain(deps_code_out.drain(..)) {
                    gen_code.push(P(item));
                }
                let mut jni_func_items = code_to_item(&code);
                gen_code.extend(jni_func_items.drain(..));
            }
            MethodVariant::Constructor => {
                have_constructor = true;
                let constructor_ret_type = get_constructor_ret_type(class)?;
                write!(&mut code, r#"
#[allow(non_snake_case)]
#[no_mangle]
#[allow(unused_variables)]
pub fn {func_name}(env: *mut JNIEnv, _: jclass, {decl_func_args}) -> jlong {{
{convert_input_code}
  let this = {rust_func_name}({args_names});
{convert_this}
  Box::into_raw(Box::new(this)) as jlong
}}
"#,
                       func_name = jni_func_name,
                       convert_this = jni_handle_result_from_constructor(class,
                                                                         &constructor_ret_type),
                       decl_func_args = decl_func_args,
                       convert_input_code = convert_input_code,
                       rust_func_name = method.rust_id,
                       args_names = args_names,
                ).map_err(fmt_write_err_map)?;
                for item in deps_code_in.drain(..) {
                    gen_code.push(P(item));
                }
                let mut jni_func_items = code_to_item(&code);
                gen_code.extend(jni_func_items.drain(..));
            }
        }
    }

    if have_constructor {
        let constructor_ret_type = get_real_constructor_ret_type(class)?;
        let mut code = String::new();
        write!(&mut code, r#"
#[allow(non_snake_case)]
#[no_mangle]
pub fn {jni_destructor_name}(_: *mut JNIEnv, _: jclass, this: jlong) {{
    let this: &mut {type_name} = unsafe {{
        jlong_to_pointer::<{type_name}>(this).as_mut().unwrap()
    }};
    let this = unsafe {{ Box::from_raw(this) }};
    drop(this)
}}
"#,
               jni_destructor_name = generate_jni_func_name(
                   package_name, &class.name,
                   "do_delete", &MethodSignatureWithForeignTypes {
                       foreign_input: Vec::new(),
                       rust_input: Vec::new(),
                       foreign_output: Symbol::intern(""),
                       rust_output: Symbol::intern(""),
                   }, false),
               type_name = pprust::ty_to_string(&constructor_ret_type),
        ).map_err(fmt_write_err_map)?;
        debug!("we generate and parse code: {}", code);
        let mut jni_func_items = code_to_item(&code);
        gen_code.extend(jni_func_items.drain(..));
    }

    Ok(gen_code)
}

lazy_static! {
    static ref JAVA_TYPE_NAMES_FOR_JNI_SIGNATURE: HashMap<Symbol, &'static str> = {
        let mut m = HashMap::new();
        m.insert(Symbol::intern("String"), "Ljava.lang.String;");
        m.insert(Symbol::intern("boolean"), "Z");
        m.insert(Symbol::intern("byte"), "B");
        m.insert(Symbol::intern("char"), "C");
        m.insert(Symbol::intern("double"), "D");
        m.insert(Symbol::intern("float"), "F");
        m.insert(Symbol::intern("int"), "I");
        m.insert(Symbol::intern("long"), "J");
        m.insert(Symbol::intern("object"), "L");
        m.insert(Symbol::intern("short"), "S");
        m.insert(Symbol::intern("void"), "V");
        m
    };
}

fn generate_jni_func_name(package_name: &str,
                          class_name: &str,
                          java_method_name: &str,
                          method: &MethodSignatureWithForeignTypes,
                          overloaded: bool)
                          -> String {
    let mut output = String::new();
    output.push_str("Java_");
    fn escape_underscore(input: &str, mut output: &mut String) {
        for c in input.chars() {
            match c {
                '.' => output.push('_'),
                '[' => output.push_str("_3"),
                '_' => output.push_str("_1"),
                ';' => output.push_str("_2"),
                _ => output.push(c),
            }
        }
    }
    escape_underscore(package_name, &mut output);
    output.push_str("_");
    escape_underscore(class_name, &mut output);
    output.push_str("_");
    escape_underscore(java_method_name, &mut output);

    if overloaded {
        output.push_str("__");
        for arg in &method.foreign_input {
            escape_underscore(
                JAVA_TYPE_NAMES_FOR_JNI_SIGNATURE
                    .get(&*arg)
                    .unwrap_or_else(|| {
                        panic!("generate_jni_func_name: Unknown Java type `{}`", *arg)
                    }),
                &mut output,
            );
        }
    }

    output
}

fn generate_jni_args_with_types(method: &MethodSignatureWithForeignTypes)
                                -> Result<String, String> {
    use std::fmt::Write;

    let mut buf = String::new();
    for (i, rust_type_name) in method.rust_input.iter().enumerate() {
        write!(&mut buf,
               "a_{}: {}, ",
               i,
               unpack_unique_typename(*rust_type_name))
            .map_err(fmt_write_err_map)?;
    }
    Ok(buf)
}

/// may panics
fn code_to_item(code: &str) -> Vec<P<ast::Item>> {
    let session = parse::ParseSess::new();
    let mut parser = parse::new_parser_from_source_str(&session, "conv code".into(), code.into());

    let mut krate = match parser.parse_crate_mod() {
        Ok(x) => x,
        Err(mut diag) => {
            diag.emit();
            panic!("{}: {}: Can not parse '{}'", file!(), line!(), code);
        }
    };
    let items: Vec<_> = krate.module.items.drain(..).collect();
    items
}

/// may panic
fn jni_handle_result_from_constructor(class: &ForeignerClassInfo,
                                      constructor_ret_type: &ast::Ty)
                                      -> String {
    let ret_typename = pprust::ty_to_string(constructor_ret_type);
    let self_typename = format!("{}", class.self_type);
    if ret_typename.starts_with(&format!("Result<{},", self_typename)) {
        r#"
  let this = match this {
    Ok(val) => val,
    Err(msg) => {
      jni_throw_exception(env, &msg);
      return 0;
    }
  };
"#
            .into()
    } else {
        String::new()
    }
}

fn generate_rust_to_convert_this(class: &ForeignerClassInfo,
                                 constructor_ret_type: &ast::Ty)
                                 -> Result<String, String> {
    let constructor_ret_type = pprust::ty_to_string(constructor_ret_type);
    let self_type = format!("{}", class.self_type);
    if constructor_ret_type == self_type {
        return Ok(String::new());
    }

    if format!("Arc<Mutex<{}>>", self_type) == constructor_ret_type {
        Ok("    let mut this = this.lock().unwrap();\n".into())
    } else if format!("Rc<RefCell<{}>>", self_type) == constructor_ret_type {
        Ok("    let mut this = this.borrow_mut();\n".into())
    } else if format!("Arc<{}>", self_type) == constructor_ret_type {
        Ok(String::new())
    } else {
        Err(format!("Not implemented conversation from '{}' to '{}'",
                    constructor_ret_type,
                    self_type))
    }
}
<commit_msg>cleanups: use Iterator::zip<commit_after>use std::collections::HashMap;
use std::fmt::Write;

use syntex_syntax::{ast, parse};
use syntex_syntax::ptr::P;
use syntex_syntax::symbol::Symbol;
use syntex_syntax::print::pprust;
use syntex_syntax::parse::ParseSess;

use ForeignerClassInfo;
use ForeignTypesMap;
use MethodVariant;
use types_map::{MethodSignatureWithForeignTypes, unpack_unique_typename};
use java_jni::java_code;
use utils::fmt_write_err_map;

pub(crate) fn generate_rust_code(parse_sess: &ParseSess,
                                 types_map: &mut ForeignTypesMap,
                                 package_name: &str,
                                 class: &ForeignerClassInfo,
                                 methods_sign: &[MethodSignatureWithForeignTypes])
                                 -> Result<Vec<P<ast::Item>>, String> {
    let mut gen_fnames = HashMap::<String, usize>::new(); //handle overload names
    for method in &class.methods {
        let val_ref = gen_fnames.entry(java_code::method_name(&*method));
        *val_ref.or_insert(0) += 1;
    }

    let get_constructor_ret_type = |cls: &ForeignerClassInfo| -> Result<ast::Ty, String> {
        let ret: ast::Ty = cls.constructor_ret_type
            .as_ref()
            .ok_or_else(|| {
                            format!("package_name {}, class_name {}, have methods, \
                                    but no constructor",
                                    package_name,
                                    class.name)
                        })?
            .clone();
        Ok(ret)
    };

    let get_real_constructor_ret_type = |cls: &ForeignerClassInfo| -> Result<ast::Ty, String> {
        let ret: ast::Ty = cls.this_type_for_method
            .as_ref()
            .ok_or_else(|| {
                            format!("package_name {}, class_name {}, have methods, \
                                    but no constructor this type for method",
                                    package_name,
                                    class.name)
                        })?
            .clone();
        Ok(ret)
    };

    let mut gen_code = Vec::<P<ast::Item>>::new();

    let mut have_constructor = false;

    for (method, method_sign) in class.methods.iter().zip(methods_sign.iter()) {
        let java_method_name = java_code::method_name(&*method);
        let method_overloading = gen_fnames[&java_method_name] > 1;
        let jni_func_name = generate_jni_func_name(package_name,
                                                   &class.name,
                                                   &java_method_name,
                                                   &method_sign,
                                                   method_overloading);
        let n_args = method_sign.rust_input.len();
        let (mut deps_code_in, convert_input_code) =
            types_map
                .convert_foreign_input(parse_sess,
                                       &*method,
                                       &method_sign,
                                       (0..n_args).map(|v| format!("a_{}", v)))?;
        let args_names = method_sign
            .rust_input
            .iter()
            .enumerate()
            .map(|a| format!("a_{}, ", a.0))
            .fold(String::new(), |acc, x| acc + &x);
        let decl_func_args = generate_jni_args_with_types(&method_sign)?;

        let mut code = String::new();
        match method.variant {
            MethodVariant::StaticMethod => {
                let (mut deps_code_out, convert_output_code) =
                    types_map
                        .convert_output_to_foreign(parse_sess,
                                                   &*method,
                                                   &method_sign,
                                                   "ret")?;
                write!(&mut code, r#"
#[allow(non_snake_case, unused_variables, unused_mut)]
#[no_mangle]
pub fn {func_name}(env: *mut JNIEnv, _: jclass, {decl_func_args}) -> {jni_ret_type} {{
{convert_input_code}
    let mut ret = {rust_func_name}({args_names});
{convert_output_code}
    ret
}}
"#,
                       func_name = jni_func_name,
                       decl_func_args = decl_func_args,
                       jni_ret_type = unpack_unique_typename(method_sign.rust_output),
                       convert_input_code = convert_input_code,
                       rust_func_name = method.rust_id,
                       args_names = args_names,
                       convert_output_code = convert_output_code,
                ).map_err(fmt_write_err_map)?;

                for item in deps_code_in.drain(..).chain(deps_code_out.drain(..)) {
                    gen_code.push(P(item));
                }
                let mut jni_func_items = code_to_item(&code);
                gen_code.extend(jni_func_items.drain(..));
            }
            MethodVariant::Method => {
                let constructor_ret_type = get_real_constructor_ret_type(class)?;

                let (mut deps_code_out, convert_output_code) =
                    types_map
                        .convert_output_to_foreign(parse_sess,
                                                   &*method,
                                                   &method_sign,
                                                   "ret")?;
                write!(&mut code, r#"
#[allow(non_snake_case, unused_variables, unused_mut)]
#[no_mangle]
pub fn {func_name}(env: *mut JNIEnv, _: jclass, this: jlong, {decl_func_args}) -> {jni_ret_type} {{
{convert_input_code}
    let this: &mut {this_type} = unsafe {{
        jlong_to_pointer::<{this_type}>(this).as_mut().unwrap()
    }};
{convert_this}
    let mut ret = {rust_func_name}(&mut *this, {args_names});
{convert_output_code}
    ret
}}
"#,
                       func_name = jni_func_name,
                       decl_func_args = decl_func_args,
                       convert_input_code = convert_input_code,
                       jni_ret_type = unpack_unique_typename(method_sign.rust_output),
                       this_type = pprust::ty_to_string(&constructor_ret_type),
                       convert_this = generate_rust_to_convert_this(class, &constructor_ret_type)?,
                       rust_func_name = method.rust_id,
                       args_names = args_names,
                       convert_output_code = convert_output_code,
                ).map_err(fmt_write_err_map)?;
                for item in deps_code_in.drain(..).chain(deps_code_out.drain(..)) {
                    gen_code.push(P(item));
                }
                let mut jni_func_items = code_to_item(&code);
                gen_code.extend(jni_func_items.drain(..));
            }
            MethodVariant::Constructor => {
                have_constructor = true;
                let constructor_ret_type = get_constructor_ret_type(class)?;
                write!(&mut code, r#"
#[allow(non_snake_case)]
#[no_mangle]
#[allow(unused_variables)]
pub fn {func_name}(env: *mut JNIEnv, _: jclass, {decl_func_args}) -> jlong {{
{convert_input_code}
  let this = {rust_func_name}({args_names});
{convert_this}
  Box::into_raw(Box::new(this)) as jlong
}}
"#,
                       func_name = jni_func_name,
                       convert_this = jni_handle_result_from_constructor(class,
                                                                         &constructor_ret_type),
                       decl_func_args = decl_func_args,
                       convert_input_code = convert_input_code,
                       rust_func_name = method.rust_id,
                       args_names = args_names,
                ).map_err(fmt_write_err_map)?;
                for item in deps_code_in.drain(..) {
                    gen_code.push(P(item));
                }
                let mut jni_func_items = code_to_item(&code);
                gen_code.extend(jni_func_items.drain(..));
            }
        }
    }

    if have_constructor {
        let constructor_ret_type = get_real_constructor_ret_type(class)?;
        let mut code = String::new();
        write!(&mut code, r#"
#[allow(non_snake_case)]
#[no_mangle]
pub fn {jni_destructor_name}(_: *mut JNIEnv, _: jclass, this: jlong) {{
    let this: &mut {type_name} = unsafe {{
        jlong_to_pointer::<{type_name}>(this).as_mut().unwrap()
    }};
    let this = unsafe {{ Box::from_raw(this) }};
    drop(this)
}}
"#,
               jni_destructor_name = generate_jni_func_name(
                   package_name, &class.name,
                   "do_delete", &MethodSignatureWithForeignTypes {
                       foreign_input: Vec::new(),
                       rust_input: Vec::new(),
                       foreign_output: Symbol::intern(""),
                       rust_output: Symbol::intern(""),
                   }, false),
               type_name = pprust::ty_to_string(&constructor_ret_type),
        ).map_err(fmt_write_err_map)?;
        debug!("we generate and parse code: {}", code);
        let mut jni_func_items = code_to_item(&code);
        gen_code.extend(jni_func_items.drain(..));
    }

    Ok(gen_code)
}

lazy_static! {
    static ref JAVA_TYPE_NAMES_FOR_JNI_SIGNATURE: HashMap<Symbol, &'static str> = {
        let mut m = HashMap::new();
        m.insert(Symbol::intern("String"), "Ljava.lang.String;");
        m.insert(Symbol::intern("boolean"), "Z");
        m.insert(Symbol::intern("byte"), "B");
        m.insert(Symbol::intern("char"), "C");
        m.insert(Symbol::intern("double"), "D");
        m.insert(Symbol::intern("float"), "F");
        m.insert(Symbol::intern("int"), "I");
        m.insert(Symbol::intern("long"), "J");
        m.insert(Symbol::intern("object"), "L");
        m.insert(Symbol::intern("short"), "S");
        m.insert(Symbol::intern("void"), "V");
        m
    };
}

fn generate_jni_func_name(package_name: &str,
                          class_name: &str,
                          java_method_name: &str,
                          method: &MethodSignatureWithForeignTypes,
                          overloaded: bool)
                          -> String {
    let mut output = String::new();
    output.push_str("Java_");
    fn escape_underscore(input: &str, mut output: &mut String) {
        for c in input.chars() {
            match c {
                '.' => output.push('_'),
                '[' => output.push_str("_3"),
                '_' => output.push_str("_1"),
                ';' => output.push_str("_2"),
                _ => output.push(c),
            }
        }
    }
    escape_underscore(package_name, &mut output);
    output.push_str("_");
    escape_underscore(class_name, &mut output);
    output.push_str("_");
    escape_underscore(java_method_name, &mut output);

    if overloaded {
        output.push_str("__");
        for arg in &method.foreign_input {
            escape_underscore(
                JAVA_TYPE_NAMES_FOR_JNI_SIGNATURE
                    .get(&*arg)
                    .unwrap_or_else(|| {
                        panic!("generate_jni_func_name: Unknown Java type `{}`", *arg)
                    }),
                &mut output,
            );
        }
    }

    output
}

fn generate_jni_args_with_types(method: &MethodSignatureWithForeignTypes)
                                -> Result<String, String> {
    use std::fmt::Write;

    let mut buf = String::new();
    for (i, rust_type_name) in method.rust_input.iter().enumerate() {
        write!(&mut buf,
               "a_{}: {}, ",
               i,
               unpack_unique_typename(*rust_type_name))
            .map_err(fmt_write_err_map)?;
    }
    Ok(buf)
}

/// may panics
fn code_to_item(code: &str) -> Vec<P<ast::Item>> {
    let session = parse::ParseSess::new();
    let mut parser = parse::new_parser_from_source_str(&session, "conv code".into(), code.into());

    let mut krate = match parser.parse_crate_mod() {
        Ok(x) => x,
        Err(mut diag) => {
            diag.emit();
            panic!("{}: {}: Can not parse '{}'", file!(), line!(), code);
        }
    };
    let items: Vec<_> = krate.module.items.drain(..).collect();
    items
}

/// may panic
fn jni_handle_result_from_constructor(class: &ForeignerClassInfo,
                                      constructor_ret_type: &ast::Ty)
                                      -> String {
    let ret_typename = pprust::ty_to_string(constructor_ret_type);
    let self_typename = format!("{}", class.self_type);
    if ret_typename.starts_with(&format!("Result<{},", self_typename)) {
        r#"
  let this = match this {
    Ok(val) => val,
    Err(msg) => {
      jni_throw_exception(env, &msg);
      return 0;
    }
  };
"#
            .into()
    } else {
        String::new()
    }
}

fn generate_rust_to_convert_this(class: &ForeignerClassInfo,
                                 constructor_ret_type: &ast::Ty)
                                 -> Result<String, String> {
    let constructor_ret_type = pprust::ty_to_string(constructor_ret_type);
    let self_type = format!("{}", class.self_type);
    if constructor_ret_type == self_type {
        return Ok(String::new());
    }

    if format!("Arc<Mutex<{}>>", self_type) == constructor_ret_type {
        Ok("    let mut this = this.lock().unwrap();\n".into())
    } else if format!("Rc<RefCell<{}>>", self_type) == constructor_ret_type {
        Ok("    let mut this = this.borrow_mut();\n".into())
    } else if format!("Arc<{}>", self_type) == constructor_ret_type {
        Ok(String::new())
    } else {
        Err(format!("Not implemented conversation from '{}' to '{}'",
                    constructor_ret_type,
                    self_type))
    }
}
<|endoftext|>


<commit_before>mod active_window_title;
mod clock;
mod pager;

pub use self::active_window_title::ActiveWindowTitle;
pub use self::clock::Clock;
pub use self::pager::Pager;

use std::time::Duration;

use futures::{Async, Stream, Poll};
use tokio_timer::Timer;
use text::Text;

pub trait Widget {
    fn stream(self: Box<Self>) -> Box<Stream<Item = Vec<Text>, Error = ()>>;
}

pub trait TimerUpdateWidget {
    fn update_interval(&self) -> Duration;
    fn tick(&self) -> Vec<Text>;
}

impl<T: 'static + TimerUpdateWidget> Widget for T {
    fn stream(self: Box<Self>) -> Box<Stream<Item = Vec<Text>, Error = ()>> {
        let timer_stream = Timer::default().interval(self.update_interval());
        let text_stream = timer_stream.map(move |_| self.tick());
        Box::new(text_stream.map_err(|_| ()))
    }
}

pub struct WidgetList {
    vec: Vec<Box<Stream<Item = Vec<Text>, Error = ()>>>,
    cached: Vec<Option<Vec<Text>>>,
}

impl WidgetList {
    pub fn new(widgets: Vec<Box<Widget>>) -> WidgetList {
        let len = widgets.len();
        WidgetList {
            vec: widgets.into_iter().map(|w| w.stream()).collect(),
            cached: vec![None; len]
        }
    }

    pub fn texts(&self) -> Vec<Text> {
        self.cached
            .clone()
            .into_iter()
            .filter_map(|o| o)
            .flat_map(|v| v)
            .collect()
    }
}

impl Stream for WidgetList {
    type Item = Vec<Text>;
    type Error = ();

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        let mut none_ready = true;

        for (i, stream) in self.vec.iter_mut().enumerate() {
            match stream.poll() {
                Ok(Async::Ready(texts)) => {
                    none_ready = false;
                    self.cached[i] = texts;
                },
                Ok(Async::NotReady) => {},
                Err(e) => return Err(e),
            }
        }

        if none_ready {
            return Ok(Async::NotReady);
        }

        Ok(Async::Ready(Some(self.texts())))
    }
}
<commit_msg>Silence clippy warning.<commit_after>mod active_window_title;
mod clock;
mod pager;

pub use self::active_window_title::ActiveWindowTitle;
pub use self::clock::Clock;
pub use self::pager::Pager;

use std::time::Duration;

use futures::{Async, Stream, Poll};
use tokio_timer::Timer;
use text::Text;

pub trait Widget {
    fn stream(self: Box<Self>) -> Box<Stream<Item = Vec<Text>, Error = ()>>;
}

pub trait TimerUpdateWidget {
    fn update_interval(&self) -> Duration;
    fn tick(&self) -> Vec<Text>;
}

impl<T: 'static + TimerUpdateWidget> Widget for T {
    #[allow(boxed_local)]
    fn stream(self: Box<Self>) -> Box<Stream<Item = Vec<Text>, Error = ()>> {
        let timer_stream = Timer::default().interval(self.update_interval());
        let text_stream = timer_stream.map(move |_| self.tick());
        Box::new(text_stream.map_err(|_| ()))
    }
}

pub struct WidgetList {
    vec: Vec<Box<Stream<Item = Vec<Text>, Error = ()>>>,
    cached: Vec<Option<Vec<Text>>>,
}

impl WidgetList {
    pub fn new(widgets: Vec<Box<Widget>>) -> WidgetList {
        let len = widgets.len();
        WidgetList {
            vec: widgets.into_iter().map(|w| w.stream()).collect(),
            cached: vec![None; len]
        }
    }

    pub fn texts(&self) -> Vec<Text> {
        self.cached
            .clone()
            .into_iter()
            .filter_map(|o| o)
            .flat_map(|v| v)
            .collect()
    }
}

impl Stream for WidgetList {
    type Item = Vec<Text>;
    type Error = ();

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        let mut none_ready = true;

        for (i, stream) in self.vec.iter_mut().enumerate() {
            match stream.poll() {
                Ok(Async::Ready(texts)) => {
                    none_ready = false;
                    self.cached[i] = texts;
                },
                Ok(Async::NotReady) => {},
                Err(e) => return Err(e),
            }
        }

        if none_ready {
            return Ok(Async::NotReady);
        }

        Ok(Async::Ready(Some(self.texts())))
    }
}
<|endoftext|>


<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/*!
RTOS support code.

This module is a higher level abstraction over hardware than hal. It might be
incompatible direct hal usage in some cases.
*/

// pub mod debug;
pub mod syscall;
#[cfg(cfg_multitasking)] pub mod task;
#[cfg(cfg_multitasking)] pub mod mutex;
#[cfg(cfg_multitasking)] pub mod cond_var;
<commit_msg>os::cond_var: Always compile<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/*!
RTOS support code.

This module is a higher level abstraction over hardware than hal. It might be
incompatible direct hal usage in some cases.
*/

// pub mod debug;
pub mod syscall;
#[cfg(cfg_multitasking)] pub mod task;
#[cfg(cfg_multitasking)] pub mod mutex;
pub mod cond_var;
<|endoftext|>


<commit_before>use std::path::PathBuf;

use chrono::prelude::*;
use chrono::Duration;
use chrono_english::*;
use structopt::clap::Shell;
use structopt::StructOpt;

#[derive(StructOpt, Debug)]
pub enum SubCommand {
    /// Enqueue a task for execution.
    Add {
        /// The command that should be added.
        #[structopt(required = true)]
        command: Vec<String>,

        /// Start the task immediately.
        #[structopt(name = "immediate", short, long, conflicts_with = "stashed")]
        start_immediately: bool,

        /// Create the task in stashed state.
        /// Useful to avoid immediate execution if the queue is empty.
        #[structopt(name = "stashed", short, long, conflicts_with = "immediate")]
        stashed: bool,

        /// Delays enqueueing the task until <delay> elapses. See "enqueue" for accepted formats.
        #[structopt(name = "delay", short, long, conflicts_with = "immediate", parse(try_from_str=parse_delay_until))]
        delay_until: Option<DateTime<Local>>,

        /// Assign the task to a group. Groups kind of act as separate queues.
        /// I.e. all groups run in parallel and you can specify the amount of parallel tasks for each group.
        /// If no group is specified, the default group will be used.
        #[structopt(name = "group", short, long)]
        group: Option<String>,

        /// Start the task once all specified tasks have successfully finished.
        /// As soon as one of the dependencies fails, this task will fail as well.
        #[structopt(name = "after", short, long)]
        dependencies: Vec<usize>,
    },
    /// Remove tasks from the list.
    /// Running or paused tasks need to be killed first.
    Remove {
        /// The task ids to be removed.
        #[structopt(required = true)]
        task_ids: Vec<usize>,
    },
    /// Switches the queue position of two commands. Only works on queued and stashed commands.
    Switch {
        /// The first task id.
        task_id_1: usize,
        /// The second task id.
        task_id_2: usize,
    },
    /// Stashed tasks won't be automatically started.
    /// Either enqueue them, to be normally handled or explicitly start them.
    Stash {
        /// The id(s) of the tasks you want to stash.
        #[structopt(required = true)]
        task_ids: Vec<usize>,
    },
    /// Enqueue stashed tasks. They'll be handled normally afterwards.
    #[structopt(after_help = "DELAY FORMAT:

    The --delay argument must be either a number of seconds or a \"date expression\" similar to GNU \
    `date -d` with some extensions. It does not attempt to parse all natural language, but is \
    incredibly flexible. Here are some supported examples.

    2020-04-01T18:30:00   // RFC 3339 timestamp
    2020-4-1 18:2:30      // Optional leading zeros
    2020-4-1 5:30pm       // Informal am/pm time
    2020-4-1 5pm          // Optional minutes and seconds
    April 1 2020 18:30:00 // English months
    1 Apr 8:30pm          // Implies current year
    4/1                   // American form date
    wednesday 10:30pm     // The closest wednesday in the future at 22:30
    wednesday             // The closest wednesday in the future
    4 months              // 4 months from today at 00:00:00
    1 week                // 1 week at the current time
    1days                 // 1 day from today at the current time
    1d 03:00              // The closest 3:00 after 1 day (24 hours)
    3h                    // 3 hours from now
    3600s                 // 3600 seconds from now
")]
    Enqueue {
        /// The id(s) of the tasks you want to enqueue.
        task_ids: Vec<usize>,

        /// Delay enqueuing the tasks until <delay> elapses. See DELAY FORMAT below.
        #[structopt(name = "delay", short, long, parse(try_from_str=parse_delay_until))]
        delay_until: Option<DateTime<Local>>,
    },

    /// Resume operation of specific tasks or groups of tasks.
    /// By default, this resumes the default queue and all it's tasks.
    /// Can also be used force specific tasks to start.
    #[structopt(verbatim_doc_comment)]
    Start {
        /// Enforce starting these tasks. Paused tasks will be started again.
        /// This does not affect anything other than these tasks.
        task_ids: Vec<usize>,

        /// Start a specific group and all paused tasks in it.
        #[structopt(short, long, group("start"))]
        group: Option<String>,

        /// Start a everything (Default queue and all groups)!
        /// All groups will be set to `running` and all paused tasks will be resumed.
        #[structopt(short, long, group("start"))]
        all: bool,

        /// Also resume direct child processes of your paused tasks.
        /// By default only the main process will get a SIGSTART.
        #[structopt(short, long, group("start"))]
        children: bool,
    },

    /// Restart task(s).
    /// Identical tasks will be created and by default enqueued.
    Restart {
        /// The tasks you want to restart.
        #[structopt(required = true)]
        task_ids: Vec<usize>,

        /// Immediately start the task(s).
        #[structopt(name = "immediate", short, long)]
        start_immediately: bool,

        /// Create the task in stashed state.
        /// Useful to avoid immediate execution.
        #[structopt(short, long, conflicts_with = "immediate")]
        stashed: bool,

        /// Edit the command of the task before restarting
        #[structopt(short, long)]
        edit: bool,

        /// Edit the path of the task before restarting
        #[structopt(short, long)]
        path: bool,
    },

    /// Pause either running tasks or specific groups of tasks.
    /// By default, pauses the default queue and all it's tasks.
    /// A paused queue (group) won't start any new tasks.
    /// Everything can be resumed with 'start'.
    #[structopt(verbatim_doc_comment)]
    Pause {
        /// Pause these specific tasks.
        /// Does not affect the default queue, groups or any other tasks.
        task_ids: Vec<usize>,

        /// Pause a specific group.
        #[structopt(short, long, group("pause"))]
        group: Option<String>,

        /// Pause everything (Default queue and all groups)!
        #[structopt(short, long, group("pause"))]
        all: bool,

        /// Don not pause already running tasks and let them finish by themselves,
        /// when pausing with `default`, `all` or `group`.
        #[structopt(short, long, group("pause"))]
        wait: bool,

        /// Also pause direct child processes of a task's main process.
        /// By default only the main process will get a SIGSTOP.
        /// This is useful when calling bash scripts, which start other processes themselves.
        /// This operation is not recursive!
        #[structopt(short, long, group("pause"))]
        children: bool,
    },

    /// Kill specific running tasks or various groups of tasks.
    Kill {
        /// The tasks that should be killed.
        task_ids: Vec<usize>,

        /// Kill all running tasks in the default queue. Pause the default queue.
        #[structopt(short, long, group("kill"))]
        default: bool,

        /// Kill all running in a group. Pauses the group.
        #[structopt(short, long, group("kill"))]
        group: Option<String>,

        /// Kill ALL running tasks. This also pauses everything
        #[structopt(short, long, group("kill"))]
        all: bool,

        /// Send the SIGTERM signal to all children as well.
        /// Useful when working with shell scripts.
        #[structopt(short, long, group("kill"))]
        children: bool,
    },

    /// Send something to a task. Useful for sending confirmations such as 'y\n'.
    Send {
        /// The id of the task.
        task_id: usize,

        /// The input that should be sent to the process.
        input: String,
    },

    /// Edit the command or path of a stashed or queued task.
    /// This edits the command of the task by default.
    #[structopt(verbatim_doc_comment)]
    Edit {
        /// The id of the task.
        task_id: usize,

        /// Edit the path of the task.
        #[structopt(short, long)]
        path: bool,
    },

    /// Manage groups.
    /// By default, this will simply display all known groups.
    Group {
        /// Add a group
        #[structopt(short, long)]
        add: Option<String>,

        /// Remove a group.
        /// This will move all tasks in this group to the default group!
        #[structopt(short, long)]
        remove: Option<String>,
    },

    /// Display the current status of all tasks.
    Status {
        /// Print the current state as json to stdout.
        /// This does not include stdout/stderr of tasks.
        /// Use `log -j` if you want everything.
        #[structopt(short, long)]
        json: bool,

        #[structopt(short, long)]
        /// Only show tasks of a specific group
        group: Option<String>,
    },

    /// Display the log output of finished tasks.
    /// Prints either all logs or only the logs of specified tasks.
    Log {
        /// Specify for which specific tasks you want to see the output.
        task_ids: Vec<usize>,
        /// Print the current state as json.
        /// Includes EVERYTHING.
        #[structopt(short, long)]
        json: bool,
    },

    /// Follow the output of a currently running task.
    /// This command works like `tail -f`.
    Follow {
        /// The id of the task you want to watch.
        /// If no or multiple tasks are running, you have to specify the id.
        /// If only a single task is running, you can omit the id.
        task_id: Option<usize>,

        /// Show stderr instead of stdout.
        #[structopt(short, long)]
        err: bool,
    },

    /// Remove all finished tasks from the list (also clears logs).
    Clean,

    /// Kill all running tasks, remove all tasks and reset max_task_id.
    Reset {
        /// Send the SIGTERM signal to all children as well.
        /// Useful when working with shell scripts.
        #[structopt(short, long)]
        children: bool,
    },

    /// Remotely shut down the daemon. Should only be used if the daemon isn't started by a service manager.
    Shutdown,

    /// Set the amount of allowed parallel tasks.
    Parallel {
        /// The amount of allowed parallel tasks.
        #[structopt(validator=min_one)]
        parallel_tasks: usize,

        /// Specify the amount of parallel tasks for a group.
        #[structopt(name = "group", short, long)]
        group: Option<String>,
    },

    /// Generates shell completion files.
    /// This can be ignored during normal operations.
    Completions {
        /// The target shell. Can be `bash`, `fish`, `powershell`, `elvish` and `zsh`.
        shell: Shell,
        /// The output directory to which the file should be written.
        output_directory: PathBuf,
    },
}

#[derive(StructOpt, Debug)]
#[structopt(
    name = "Pueue client",
    about = "Interact with the Pueue daemon",
    author = "Arne Beer <contact@arne.beer>"
)]
pub struct Opt {
    /// Verbose mode (-v, -vv, -vvv)
    #[structopt(short, long, parse(from_occurrences))]
    pub verbose: u8,

    /// The port for the daemon. Overwrites the port in the config file.
    /// Will force TCP mode.
    #[structopt(short, long)]
    pub port: Option<String>,

    /// The path to the unix socket.
    /// Overwrites the path in the config file.
    /// Will force Unix-socket mode.
    #[structopt(short, long, conflicts_with = "port")]
    pub unix_socket_path: Option<String>,

    #[structopt(subcommand)]
    pub cmd: SubCommand,
}

fn parse_delay_until(src: &str) -> Result<DateTime<Local>, String> {
    if let Ok(seconds) = src.parse::<i64>() {
        let delay_until = Local::now() + Duration::seconds(seconds);
        return Ok(delay_until);
    }

    if let Ok(date_time) = parse_date_string(src, Local::now(), Dialect::Us) {
        return Ok(date_time);
    }

    Err(String::from(
        "could not parse as seconds or date expression",
    ))
}

/// Validator function. The input string has to be parsable as int and bigger than 0
fn min_one(value: String) -> Result<(), String> {
    match value.parse::<usize>() {
        Ok(value) => {
            if value < 1 {
                return Err("You must provide a value that's bigger than 0".into());
            }
            Ok(())
        }
        Err(_) => Err("Failed to parse integer".into()),
    }
}
<commit_msg>Cli help<commit_after>use std::path::PathBuf;

use chrono::prelude::*;
use chrono::Duration;
use chrono_english::*;
use structopt::clap::Shell;
use structopt::StructOpt;

#[derive(StructOpt, Debug)]
pub enum SubCommand {
    /// Enqueue a task for execution.
    Add {
        /// The command that should be added.
        #[structopt(required = true)]
        command: Vec<String>,

        /// Start the task immediately.
        #[structopt(name = "immediate", short, long, conflicts_with = "stashed")]
        start_immediately: bool,

        /// Create the task in stashed state.
        /// Useful to avoid immediate execution if the queue is empty.
        #[structopt(name = "stashed", short, long, conflicts_with = "immediate")]
        stashed: bool,

        /// Delays enqueueing the task until <delay> elapses. See "enqueue" for accepted formats.
        #[structopt(name = "delay", short, long, conflicts_with = "immediate", parse(try_from_str=parse_delay_until))]
        delay_until: Option<DateTime<Local>>,

        /// Assign the task to a group. Groups kind of act as separate queues.
        /// I.e. all groups run in parallel and you can specify the amount of parallel tasks for each group.
        /// If no group is specified, the default group will be used.
        #[structopt(name = "group", short, long)]
        group: Option<String>,

        /// Start the task once all specified tasks have successfully finished.
        /// As soon as one of the dependencies fails, this task will fail as well.
        #[structopt(name = "after", short, long)]
        dependencies: Vec<usize>,
    },
    /// Remove tasks from the list.
    /// Running or paused tasks need to be killed first.
    Remove {
        /// The task ids to be removed.
        #[structopt(required = true)]
        task_ids: Vec<usize>,
    },
    /// Switches the queue position of two commands. Only works on queued and stashed commands.
    Switch {
        /// The first task id.
        task_id_1: usize,
        /// The second task id.
        task_id_2: usize,
    },
    /// Stashed tasks won't be automatically started.
    /// Either enqueue them, to be normally handled or explicitly start them.
    Stash {
        /// The id(s) of the tasks you want to stash.
        #[structopt(required = true)]
        task_ids: Vec<usize>,
    },
    /// Enqueue stashed tasks. They'll be handled normally afterwards.
    #[structopt(after_help = "DELAY FORMAT:

    The --delay argument must be either a number of seconds or a \"date expression\" similar to GNU \
    `date -d` with some extensions. It does not attempt to parse all natural language, but is \
    incredibly flexible. Here are some supported examples.

    2020-04-01T18:30:00   // RFC 3339 timestamp
    2020-4-1 18:2:30      // Optional leading zeros
    2020-4-1 5:30pm       // Informal am/pm time
    2020-4-1 5pm          // Optional minutes and seconds
    April 1 2020 18:30:00 // English months
    1 Apr 8:30pm          // Implies current year
    4/1                   // American form date
    wednesday 10:30pm     // The closest wednesday in the future at 22:30
    wednesday             // The closest wednesday in the future
    4 months              // 4 months from today at 00:00:00
    1 week                // 1 week at the current time
    1days                 // 1 day from today at the current time
    1d 03:00              // The closest 3:00 after 1 day (24 hours)
    3h                    // 3 hours from now
    3600s                 // 3600 seconds from now
")]
    Enqueue {
        /// The id(s) of the tasks you want to enqueue.
        task_ids: Vec<usize>,

        /// Delay enqueuing the tasks until <delay> elapses. See DELAY FORMAT below.
        #[structopt(name = "delay", short, long, parse(try_from_str=parse_delay_until))]
        delay_until: Option<DateTime<Local>>,
    },

    /// Resume operation of specific tasks or groups of tasks.
    /// By default, this resumes the default queue and all it's tasks.
    /// Can also be used force-start specific tasks.
    #[structopt(verbatim_doc_comment)]
    Start {
        /// Enforce starting these tasks. Paused tasks will be started again.
        /// This does not affect anything other than these tasks.
        task_ids: Vec<usize>,

        /// Start a specific group and all paused tasks in it.
        #[structopt(short, long, group("start"))]
        group: Option<String>,

        /// Start a everything (Default queue and all groups)!
        /// All groups will be set to `running` and all paused tasks will be resumed.
        #[structopt(short, long, group("start"))]
        all: bool,

        /// Also resume direct child processes of your paused tasks.
        /// By default only the main process will get a SIGSTART.
        #[structopt(short, long, group("start"))]
        children: bool,
    },

    /// Restart task(s).
    /// Identical tasks will be created and by default enqueued.
    Restart {
        /// The tasks you want to restart.
        #[structopt(required = true)]
        task_ids: Vec<usize>,

        /// Immediately start the task(s).
        #[structopt(name = "immediate", short, long)]
        start_immediately: bool,

        /// Create the task in stashed state.
        /// Useful to avoid immediate execution.
        #[structopt(short, long, conflicts_with = "immediate")]
        stashed: bool,

        /// Edit the command of the task before restarting
        #[structopt(short, long)]
        edit: bool,

        /// Edit the path of the task before restarting
        #[structopt(short, long)]
        path: bool,
    },

    /// Pause either running tasks or specific groups of tasks.
    /// By default, pauses the default queue and all it's tasks.
    /// A paused queue (group) won't start any new tasks.
    #[structopt(verbatim_doc_comment)]
    Pause {
        /// Pause these specific tasks.
        /// Does not affect the default queue, groups or any other tasks.
        task_ids: Vec<usize>,

        /// Pause a specific group.
        #[structopt(short, long, group("pause"))]
        group: Option<String>,

        /// Pause everything (Default queue and all groups)!
        #[structopt(short, long, group("pause"))]
        all: bool,

        /// Don not pause already running tasks and let them finish by themselves,
        /// when pausing with `default`, `all` or `group`.
        #[structopt(short, long, group("pause"))]
        wait: bool,

        /// Also pause direct child processes of a task's main process.
        /// By default only the main process will get a SIGSTOP.
        /// This is useful when calling bash scripts, which start other processes themselves.
        /// This operation is not recursive!
        #[structopt(short, long, group("pause"))]
        children: bool,
    },

    /// Kill specific running tasks or various groups of tasks.
    Kill {
        /// The tasks that should be killed.
        task_ids: Vec<usize>,

        /// Kill all running tasks in the default queue. Pause the default queue.
        #[structopt(short, long, group("kill"))]
        default: bool,

        /// Kill all running in a group. Pauses the group.
        #[structopt(short, long, group("kill"))]
        group: Option<String>,

        /// Kill ALL running tasks. This also pauses everything
        #[structopt(short, long, group("kill"))]
        all: bool,

        /// Send the SIGTERM signal to all children as well.
        /// Useful when working with shell scripts.
        #[structopt(short, long, group("kill"))]
        children: bool,
    },

    /// Send something to a task. Useful for sending confirmations such as 'y\n'.
    Send {
        /// The id of the task.
        task_id: usize,

        /// The input that should be sent to the process.
        input: String,
    },

    /// Edit the command or path of a stashed or queued task.
    /// This edits the command of the task by default.
    #[structopt(verbatim_doc_comment)]
    Edit {
        /// The id of the task.
        task_id: usize,

        /// Edit the path of the task.
        #[structopt(short, long)]
        path: bool,
    },

    /// Manage groups.
    /// By default, this will simply display all known groups.
    Group {
        /// Add a group
        #[structopt(short, long)]
        add: Option<String>,

        /// Remove a group.
        /// This will move all tasks in this group to the default group!
        #[structopt(short, long)]
        remove: Option<String>,
    },

    /// Display the current status of all tasks.
    Status {
        /// Print the current state as json to stdout.
        /// This does not include stdout/stderr of tasks.
        /// Use `log -j` if you want everything.
        #[structopt(short, long)]
        json: bool,

        #[structopt(short, long)]
        /// Only show tasks of a specific group
        group: Option<String>,
    },

    /// Display the log output of finished tasks.
    /// Prints either all logs or only the logs of specified tasks.
    Log {
        /// Specify for which specific tasks you want to see the output.
        task_ids: Vec<usize>,
        /// Print the current state as json.
        /// Includes EVERYTHING.
        #[structopt(short, long)]
        json: bool,
    },

    /// Follow the output of a currently running task.
    /// This command works like `tail -f`.
    Follow {
        /// The id of the task you want to watch.
        /// If no or multiple tasks are running, you have to specify the id.
        /// If only a single task is running, you can omit the id.
        task_id: Option<usize>,

        /// Show stderr instead of stdout.
        #[structopt(short, long)]
        err: bool,
    },

    /// Remove all finished tasks from the list (also clears logs).
    Clean,

    /// Kill all running tasks, remove all tasks and reset max_task_id.
    Reset {
        /// Send the SIGTERM signal to all children as well.
        /// Useful when working with shell scripts.
        #[structopt(short, long)]
        children: bool,
    },

    /// Remotely shut down the daemon. Should only be used if the daemon isn't started by a service manager.
    Shutdown,

    /// Set the amount of allowed parallel tasks.
    Parallel {
        /// The amount of allowed parallel tasks.
        #[structopt(validator=min_one)]
        parallel_tasks: usize,

        /// Specify the amount of parallel tasks for a group.
        #[structopt(name = "group", short, long)]
        group: Option<String>,
    },

    /// Generates shell completion files.
    /// This can be ignored during normal operations.
    Completions {
        /// The target shell. Can be `bash`, `fish`, `powershell`, `elvish` and `zsh`.
        shell: Shell,
        /// The output directory to which the file should be written.
        output_directory: PathBuf,
    },
}

#[derive(StructOpt, Debug)]
#[structopt(
    name = "Pueue client",
    about = "Interact with the Pueue daemon",
    author = "Arne Beer <contact@arne.beer>"
)]
pub struct Opt {
    /// Verbose mode (-v, -vv, -vvv)
    #[structopt(short, long, parse(from_occurrences))]
    pub verbose: u8,

    /// The port for the daemon. Overwrites the port in the config file.
    /// Will force TCP mode.
    #[structopt(short, long)]
    pub port: Option<String>,

    /// The path to the unix socket.
    /// Overwrites the path in the config file.
    /// Will force Unix-socket mode.
    #[structopt(short, long, conflicts_with = "port")]
    pub unix_socket_path: Option<String>,

    #[structopt(subcommand)]
    pub cmd: SubCommand,
}

fn parse_delay_until(src: &str) -> Result<DateTime<Local>, String> {
    if let Ok(seconds) = src.parse::<i64>() {
        let delay_until = Local::now() + Duration::seconds(seconds);
        return Ok(delay_until);
    }

    if let Ok(date_time) = parse_date_string(src, Local::now(), Dialect::Us) {
        return Ok(date_time);
    }

    Err(String::from(
        "could not parse as seconds or date expression",
    ))
}

/// Validator function. The input string has to be parsable as int and bigger than 0
fn min_one(value: String) -> Result<(), String> {
    match value.parse::<usize>() {
        Ok(value) => {
            if value < 1 {
                return Err("You must provide a value that's bigger than 0".into());
            }
            Ok(())
        }
        Err(_) => Err("Failed to parse integer".into()),
    }
}
<|endoftext|>


<commit_before>extern crate rand;

use std::fmt;
use rand::Rng;

// Define 'Point' Structure
struct Point {
    x: f64,
    y: f64,
}

// Implement 'new' method for 'Point' struct
impl Point {
    fn new(nx: f64, ny: f64) -> Point {
        Point {
            x: nx,
            y: ny
        }
    }
}

// Implement display trait for 'Point' Struct
impl fmt::Display for Point {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

fn closest(list: &[Point]) -> f64 {
    //ref mut nearest = &list[0];
    let mut shortest = std::f64::MAX;

    for point in &list[1..list.len()] {
        let distancesqured = (list[0].x - point.x) * (list[0].x - point.x)
         + (list[0].y - point.y) * (list[0].y - point.y);
        if distancesqured < shortest {
            shortest = distancesqured;
            //nearest = &point;
        }
    }
    shortest
}

// Main thread
fn main() {
    // Define mutable vector for 'Point's
    let mut points: Vec<Point> = Vec::new();

    // Populate 'points' vector with 10 random 'Point's
    for i in 0..10 {
        points.push(Point::new(rand::random::<f64>(), rand::random::<f64>()));
    }

    for i in 0..points.len() {
        // Claculate the distance between the current 'Point' and the rest
        let closer = closest(&points[i..points.len()]);
        println!("{}", closer);
    }

    for point in &points {
        println!("{}", point);
    }
}<commit_msg>Improve on use of language<commit_after>extern crate rand;

use std::fmt;

static number_of_points: isize = 10;

// Define 'Point' Structure
#[derive(Debug, Copy, Clone)]
struct Point {
    x: f64,
    y: f64,
}

// Implement 'new' method for 'Point' struct
impl Point {
    fn new(nx: f64, ny: f64) -> Point {
        Point {
            x: nx,
            y: ny
        }
    }
}

// Implement display trait for 'Point' Struct
impl fmt::Display for Point {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

fn closest(list: &[Point]) -> Option<(Point, Point, f64)> {
    //ref mut nearest = &list[0];
    let mut shortest = (Point::new(0.0, 0.0), Point::new(0.0, 0.0), std::f64::MAX);

    for point in &list[1..list.len()] {
        let distance = ((list[0].x - point.x) * (list[0].x - point.x)
         + (list[0].y - point.y) * (list[0].y - point.y)).sqrt();
        if distance < shortest.2 {
            shortest = (list[0], *point, distance);
        }
    }
    if shortest.2 == std::f64::MAX { None } else { Some(shortest) }
}

// Main thread
fn main() {
    // Define mutable vector for 'Point's
    let mut points: Vec<Point> = Vec::new();

    // Populate 'points' vector with 'number_of_points' random 'Point's
    for i in 0..number_of_points {
        points.push(Point::new(rand::random::<f64>(), rand::random::<f64>()));
    }

    for i in 0..points.len() {
        // Claculate the distance between the current 'Point' and the rest
        match closest(&points[i..points.len()]) {
            None => {},
            Some(v) => println!("| {} - {} | = {}", v.0, v.1, v.2)
        }
    }
}<|endoftext|>


<commit_before>use std;
use std::collections::HashMap;
use std::net::SocketAddr;
use std::sync::{Arc};

use jsonrpc::futures::{Stream, Poll, Async, Sink, Future};
use jsonrpc::futures::sync::mpsc;

use parking_lot::Mutex;

pub type SenderChannels = Mutex<HashMap<SocketAddr, mpsc::Sender<String>>>;

pub struct PeerMessageQueue<S: Stream> {
	up: S,
	receiver: mpsc::Receiver<String>,
	_addr: SocketAddr,
}

impl<S: Stream> PeerMessageQueue<S> {
	pub fn new(
		response_stream: S,
		receiver: mpsc::Receiver<String>,
		addr: SocketAddr,
	) -> Self {
		PeerMessageQueue {
			up: response_stream,
			receiver: receiver,
			_addr: addr,
		}
	}
}

/// Push Message Error
#[derive(Debug)]
pub enum PushMessageError {
	/// Invalid peer
	NoSuchPeer,
	/// Send error
	Send(mpsc::SendError<String>)
}

impl From<mpsc::SendError<String>> for PushMessageError {
	fn from(send_err: mpsc::SendError<String>) -> Self {
		PushMessageError::Send(send_err)
	}
}

/// Peer-messages dispatcher.
pub struct Dispatcher {
	channels: Arc<SenderChannels>,
}

impl Dispatcher {
	/// Creates a new dispatcher
	pub fn new(channels: Arc<SenderChannels>) -> Self {
		Dispatcher {
			channels: channels,
		}
	}

	/// Pushes message to given peer
	pub fn push_message(&self, peer_addr: &SocketAddr, msg: String) -> Result<(), PushMessageError> {
		let mut channels = self.channels.lock();

		match channels.get_mut(peer_addr) {
			Some(channel) => {
				// todo: maybe async here later?
				try!(channel.send(msg).wait().map_err(|e| PushMessageError::from(e)));
				Ok(())
			},
			None => {
				return Err(PushMessageError::NoSuchPeer);
			}
		}
	}

	/// Returns `true` if the peer is still connnected
	pub fn is_connected(&self, socket_addr: &SocketAddr) -> bool {
		self.channels.lock().contains_key(socket_addr)
	}

	/// Returns current peer count.
	pub fn peer_count(&self) -> usize {
		self.channels.lock().len()
	}
}

impl<S: Stream<Item=String, Error=std::io::Error>> Stream for PeerMessageQueue<S> {

	type Item = String;
	type Error = std::io::Error;

	fn poll(&mut self) -> Poll<Option<String>, std::io::Error> {
		// check if we have response pending
		match self.up.poll() {
			Ok(Async::Ready(Some(val))) => {
				return Ok(Async::Ready(Some(val)));
			},
			Ok(Async::Ready(None)) => {
				// this will ensure that this polling will end when incoming i/o stream ends
				return Ok(Async::Ready(None));
			},
			_ => {}
		}

		match self.receiver.poll() {
			Ok(result) => Ok(result),
			Err(send_err) => {
				// not sure if it can ever happen
				warn!("MPSC send error: {:?}", send_err);
				Err(std::io::Error::from(std::io::ErrorKind::Other))
			}
		}
	}
}
<commit_msg>add Clone to tcp::Dispatcher (#234)<commit_after>use std;
use std::collections::HashMap;
use std::net::SocketAddr;
use std::sync::{Arc};

use jsonrpc::futures::{Stream, Poll, Async, Sink, Future};
use jsonrpc::futures::sync::mpsc;

use parking_lot::Mutex;

pub type SenderChannels = Mutex<HashMap<SocketAddr, mpsc::Sender<String>>>;

pub struct PeerMessageQueue<S: Stream> {
	up: S,
	receiver: mpsc::Receiver<String>,
	_addr: SocketAddr,
}

impl<S: Stream> PeerMessageQueue<S> {
	pub fn new(
		response_stream: S,
		receiver: mpsc::Receiver<String>,
		addr: SocketAddr,
	) -> Self {
		PeerMessageQueue {
			up: response_stream,
			receiver: receiver,
			_addr: addr,
		}
	}
}

/// Push Message Error
#[derive(Debug)]
pub enum PushMessageError {
	/// Invalid peer
	NoSuchPeer,
	/// Send error
	Send(mpsc::SendError<String>)
}

impl From<mpsc::SendError<String>> for PushMessageError {
	fn from(send_err: mpsc::SendError<String>) -> Self {
		PushMessageError::Send(send_err)
	}
}

/// Peer-messages dispatcher.
#[derive(Clone)]
pub struct Dispatcher {
	channels: Arc<SenderChannels>,
}

impl Dispatcher {
	/// Creates a new dispatcher
	pub fn new(channels: Arc<SenderChannels>) -> Self {
		Dispatcher {
			channels: channels,
		}
	}

	/// Pushes message to given peer
	pub fn push_message(&self, peer_addr: &SocketAddr, msg: String) -> Result<(), PushMessageError> {
		let mut channels = self.channels.lock();

		match channels.get_mut(peer_addr) {
			Some(channel) => {
				// todo: maybe async here later?
				try!(channel.send(msg).wait().map_err(|e| PushMessageError::from(e)));
				Ok(())
			},
			None => {
				return Err(PushMessageError::NoSuchPeer);
			}
		}
	}

	/// Returns `true` if the peer is still connnected
	pub fn is_connected(&self, socket_addr: &SocketAddr) -> bool {
		self.channels.lock().contains_key(socket_addr)
	}

	/// Returns current peer count.
	pub fn peer_count(&self) -> usize {
		self.channels.lock().len()
	}
}

impl<S: Stream<Item=String, Error=std::io::Error>> Stream for PeerMessageQueue<S> {

	type Item = String;
	type Error = std::io::Error;

	fn poll(&mut self) -> Poll<Option<String>, std::io::Error> {
		// check if we have response pending
		match self.up.poll() {
			Ok(Async::Ready(Some(val))) => {
				return Ok(Async::Ready(Some(val)));
			},
			Ok(Async::Ready(None)) => {
				// this will ensure that this polling will end when incoming i/o stream ends
				return Ok(Async::Ready(None));
			},
			_ => {}
		}

		match self.receiver.poll() {
			Ok(result) => Ok(result),
			Err(send_err) => {
				// not sure if it can ever happen
				warn!("MPSC send error: {:?}", send_err);
				Err(std::io::Error::from(std::io::ErrorKind::Other))
			}
		}
	}
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;
use std::fmt::{Formatter, Display, Error, Debug};

use progress::Timestamp;
use progress::nested::summary::Summary;

use columnar::Columnar;

#[derive(Copy, Clone, Hash, Eq, PartialEq, Default)]
pub struct Product<TOuter, TInner> {
    pub outer: TOuter,
    pub inner: TInner,
}

impl<TOuter, TInner> Product<TOuter, TInner> {
    pub fn new(outer: TOuter, inner: TInner) -> Product<TOuter, TInner> {
        Product {
            outer: outer,
            inner: inner,
        }
    }
}

impl<TOuter: Display, TInner: Display> Display for Product<TOuter, TInner> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_str(&format!("({}, {})", self.outer, self.inner))
    }
}

impl<TOuter: Debug, TInner: Debug> Debug for Product<TOuter, TInner> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_str(&format!("({:?}, {:?})", self.outer, self.inner))
    }
}

impl<TOuter: PartialOrd, TInner: PartialOrd> PartialOrd for Product<TOuter, TInner> {
    fn partial_cmp(&self, other: &Product<TOuter, TInner>) -> Option<Ordering> {
        if let Some(cmp1) = self.outer.partial_cmp(&other.outer) {
            if let Some(cmp2) = self.inner.partial_cmp(&other.inner) {

                // if both are comparable we may have a result, as long as not LT and GT
                if cmp1 == cmp2 { Some(cmp1) }
                else {
                    if cmp1 == Ordering::Equal { Some(cmp2) } else
                    if cmp2 == Ordering::Equal { Some(cmp1) } else
                    { None }
                }
            }
            else { None }
        }
        else { None }
    }
}

impl<TOuter: Timestamp, TInner: Timestamp> Timestamp for Product<TOuter, TInner> {
    type Summary = Summary<TOuter::Summary, TInner::Summary>;
}

// columnar implementation because Product<T1, T2> : Copy.
impl<TOuter: Copy+Columnar, TInner: Copy+Columnar> Columnar for Product<TOuter, TInner> {
    type Stack = Vec<Product<TOuter, TInner>>;
}
<commit_msg>added le, ge methods out of fear that it was using partial_cmp<commit_after>use std::cmp::Ordering;
use std::fmt::{Formatter, Display, Error, Debug};

use progress::Timestamp;
use progress::nested::summary::Summary;

use columnar::Columnar;

#[derive(Copy, Clone, Hash, Eq, PartialEq, Default)]
pub struct Product<TOuter, TInner> {
    pub outer: TOuter,
    pub inner: TInner,
}

impl<TOuter, TInner> Product<TOuter, TInner> {
    pub fn new(outer: TOuter, inner: TInner) -> Product<TOuter, TInner> {
        Product {
            outer: outer,
            inner: inner,
        }
    }
}

impl<TOuter: Display, TInner: Display> Display for Product<TOuter, TInner> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_str(&format!("({}, {})", self.outer, self.inner))
    }
}

impl<TOuter: Debug, TInner: Debug> Debug for Product<TOuter, TInner> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_str(&format!("({:?}, {:?})", self.outer, self.inner))
    }
}

impl<TOuter: PartialOrd, TInner: PartialOrd> PartialOrd for Product<TOuter, TInner> {
    fn partial_cmp(&self, other: &Product<TOuter, TInner>) -> Option<Ordering> {
        if let Some(cmp1) = self.outer.partial_cmp(&other.outer) {
            if let Some(cmp2) = self.inner.partial_cmp(&other.inner) {

                // if both are comparable we may have a result, as long as not LT and GT
                if cmp1 == cmp2 { Some(cmp1) }
                else {
                    if cmp1 == Ordering::Equal { Some(cmp2) } else
                    if cmp2 == Ordering::Equal { Some(cmp1) } else
                    { None }
                }
            }
            else { None }
        }
        else { None }
    }
    fn le(&self, other: &Product<TOuter, TInner>) -> bool {
        self.outer <= other.outer && self.inner <= other.inner
    }
    fn ge(&self, other: &Product<TOuter, TInner>) -> bool {
        self.outer >= other.outer && self.inner >= other.inner
    }
}

impl<TOuter: Timestamp, TInner: Timestamp> Timestamp for Product<TOuter, TInner> {
    type Summary = Summary<TOuter::Summary, TInner::Summary>;
}

// columnar implementation because Product<T1, T2> : Copy.
impl<TOuter: Copy+Columnar, TInner: Copy+Columnar> Columnar for Product<TOuter, TInner> {
    type Stack = Vec<Product<TOuter, TInner>>;
}
<|endoftext|>


<commit_before>//! Module that defines the bindings for the desktop shell protocol
//! See https://github.com/swaywm/sway/blob/master/protocols/desktop-shell.xml
//! for more information about the spec

use self::generated::server::desktop_shell::DesktopShell;
use rustwlc::wayland::{get_display};
use rustwlc::handle::{wlc_handle_from_wl_output_resource, WlcOutput};
use ::layout::{lock_tree, IncompleteBackground};
use wayland_server::Resource;
use wayland_sys::server::{WAYLAND_SERVER_HANDLE, wl_client, wl_resource};
use std::os::raw::c_void;
use nix::libc::{c_int};

#[repr(C)]
/// Holds pointers to the functions that should be called when a Wayland request
/// is sent to Way Cooler that falls under the desktop shell's responsibility
struct DesktopShellImpl {
    set_background: unsafe extern "C" fn (*mut wl_client,
                                          *mut wl_resource,
                                          *mut wl_resource,
                                          *mut wl_resource),
    set_panel: unsafe extern "C" fn (*mut wl_client,
                                     *mut wl_resource,
                                     *mut wl_resource,
                                     *mut wl_resource),
    set_lock_surface: unsafe extern "C" fn (*mut wl_client,
                                            *mut wl_resource,
                                            *mut wl_resource),
    unlock: unsafe extern "C" fn (*mut wl_client,
                                  *mut wl_resource),
    set_grab_surface: unsafe extern "C" fn (*mut wl_client,
                                            *mut wl_resource,
                                            *mut wl_resource),
    desktop_ready: unsafe extern "C" fn (*mut wl_client,
                                         *mut wl_resource),
    set_panel_position: unsafe extern "C" fn (*mut wl_client,
                                              *mut wl_resource,
                                              u32)
}

static mut DESKTOP_SHELL_GLOBAL: DesktopShellImpl =
    DesktopShellImpl {
        set_background,
        set_panel,
        set_lock_surface,
        unlock,
        set_grab_surface,
        desktop_ready,
        set_panel_position
    };

mod generated {
    // Generated code generally doesn't follow standards
    #![allow(dead_code,non_camel_case_types,unused_unsafe,unused_variables)]
    #![allow(non_upper_case_globals,non_snake_case,unused_imports)]

    pub mod interfaces {
        #[doc(hidden)]
        use wayland_server::protocol_interfaces::{wl_output_interface, wl_surface_interface};
        include!(concat!(env!("OUT_DIR"), "/desktop-shell_interface.rs"));
    }

    pub mod server {
        #[doc(hidden)]
        use wayland_server::{Resource, Handler,
                                 Client, Liveness,
                                 EventLoopHandle, EventResult};
        #[doc(hidden)]
        use wayland_server::protocol::{wl_output, wl_surface};
        #[doc(hidden)]
        use super::interfaces;
        include!(concat!(env!("OUT_DIR"), "/desktop-shell_api.rs"));
    }
}

/// Binds the handler to a new Wayland resource, created by the client.
/// See https://github.com/vberger/wayland-rs/blob/451ccab330b3d0ec18eaaf72ae17ac35cf432370/wayland-server/src/event_loop.rs#L617
/// to see where I got this particular bit of magic from.
unsafe extern "C" fn bind(client: *mut wl_client,
                          _data: *mut c_void,
                          version: u32,
                          id: u32) {
    info!("Binding Desktop Shell resource");
    let cur_version = DesktopShell::supported_version();
    if version > cur_version {
        warn!("Unsupported desktop shell control protocol version {}!", version);
        warn!("We only support version {}", cur_version);
        return
    }
    let resource = ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                                 wl_resource_create,
                                 client,
                                 DesktopShell::interface_ptr(),
                                 version as c_int,
                                 id);
    if resource.is_null() {
        warn!("Out of memory, could not make a new wl_resource \
               for desktop shell");
        ffi_dispatch!(
            WAYLAND_SERVER_HANDLE,
            wl_client_post_no_memory,
            client
        );
    }
    let global_ptr = &mut DESKTOP_SHELL_GLOBAL as *mut _ as *mut c_void;
    ffi_dispatch!(
        WAYLAND_SERVER_HANDLE,
        wl_resource_set_implementation,
        resource,
        global_ptr,
        ::std::ptr::null_mut(),
        None
    );
}

unsafe extern "C" fn set_background(client: *mut wl_client,
                                    _resource: *mut wl_resource,
                                    output_: *mut wl_resource,
                                    surface: *mut wl_resource) {
    let output = wlc_handle_from_wl_output_resource(output_ as *const _);
    if output == 0 {
        return;
    }
    info!("Setting surface {:?} as background for output {}", surface, output);
    if let Ok(mut tree) = lock_tree() {
        tree.add_incomplete_background(IncompleteBackground::new(client), WlcOutput::dummy(output as _))
            .expect("Could not add incomplete background");
    }
}

unsafe extern "C" fn desktop_ready(_client: *mut wl_client,
                                   _resource: *mut wl_resource) {
    /* Intentionally left blank */
}

// TODO Implement
unsafe extern "C" fn set_lock_surface(_client: *mut wl_client,
                                      _resource: *mut wl_resource,
                                      _surface: *mut wl_resource) {}
unsafe extern "C" fn unlock(_client: *mut wl_client,
                            _resource: *mut wl_resource) {}
unsafe extern "C" fn set_grab_surface(_client: *mut wl_client,
                                      _resource: *mut wl_resource,
                                      _surface: *mut wl_resource) {}
unsafe extern "C" fn set_panel(_client: *mut wl_client,
                               _resource: *mut wl_resource,
                               _output_: *mut wl_resource,
                               _surface: *mut wl_resource) {}
unsafe extern "C" fn set_panel_position(_client: *mut wl_client,
                                        _resource:*mut wl_resource,
                                        _position: u32) {}

/// Sets up Way Cooler to announce the desktop-shell interface.
pub fn init() {
    let w_display = get_display();
    unsafe {
        info!("Initializing desktop shell");
        ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                    wl_global_create,
                    w_display as *mut _,
                    DesktopShell::interface_ptr(),
                    DesktopShell::supported_version() as i32,
                    ::std::ptr::null_mut(),
                    bind);
    }
}
<commit_msg>Fix the set_lock_surface interface<commit_after>//! Module that defines the bindings for the desktop shell protocol
//! See https://github.com/swaywm/sway/blob/master/protocols/desktop-shell.xml
//! for more information about the spec

use self::generated::server::desktop_shell::DesktopShell;
use rustwlc::wayland::{get_display};
use rustwlc::handle::{wlc_handle_from_wl_output_resource, WlcOutput};
use ::layout::{lock_tree, IncompleteBackground};
use wayland_server::Resource;
use wayland_sys::server::{WAYLAND_SERVER_HANDLE, wl_client, wl_resource};
use std::os::raw::c_void;
use nix::libc::{c_int};

#[repr(C)]
/// Holds pointers to the functions that should be called when a Wayland request
/// is sent to Way Cooler that falls under the desktop shell's responsibility
struct DesktopShellImpl {
    set_background: unsafe extern "C" fn (*mut wl_client,
                                          *mut wl_resource,
                                          *mut wl_resource,
                                          *mut wl_resource),
    set_panel: unsafe extern "C" fn (*mut wl_client,
                                     *mut wl_resource,
                                     *mut wl_resource,
                                     *mut wl_resource),
    set_lock_surface: unsafe extern "C" fn (*mut wl_client,
                                            *mut wl_resource,
                                            *mut wl_resource,
                                            *mut wl_resource),
    unlock: unsafe extern "C" fn (*mut wl_client,
                                  *mut wl_resource),
    set_grab_surface: unsafe extern "C" fn (*mut wl_client,
                                            *mut wl_resource,
                                            *mut wl_resource),
    desktop_ready: unsafe extern "C" fn (*mut wl_client,
                                         *mut wl_resource),
    set_panel_position: unsafe extern "C" fn (*mut wl_client,
                                              *mut wl_resource,
                                              u32)
}

static mut DESKTOP_SHELL_GLOBAL: DesktopShellImpl =
    DesktopShellImpl {
        set_background,
        set_panel,
        set_lock_surface,
        unlock,
        set_grab_surface,
        desktop_ready,
        set_panel_position
    };

mod generated {
    // Generated code generally doesn't follow standards
    #![allow(dead_code,non_camel_case_types,unused_unsafe,unused_variables)]
    #![allow(non_upper_case_globals,non_snake_case,unused_imports)]

    pub mod interfaces {
        #[doc(hidden)]
        use wayland_server::protocol_interfaces::{wl_output_interface, wl_surface_interface};
        include!(concat!(env!("OUT_DIR"), "/desktop-shell_interface.rs"));
    }

    pub mod server {
        #[doc(hidden)]
        use wayland_server::{Resource, Handler,
                                 Client, Liveness,
                                 EventLoopHandle, EventResult};
        #[doc(hidden)]
        use wayland_server::protocol::{wl_output, wl_surface};
        #[doc(hidden)]
        use super::interfaces;
        include!(concat!(env!("OUT_DIR"), "/desktop-shell_api.rs"));
    }
}

/// Binds the handler to a new Wayland resource, created by the client.
/// See https://github.com/vberger/wayland-rs/blob/451ccab330b3d0ec18eaaf72ae17ac35cf432370/wayland-server/src/event_loop.rs#L617
/// to see where I got this particular bit of magic from.
unsafe extern "C" fn bind(client: *mut wl_client,
                          _data: *mut c_void,
                          version: u32,
                          id: u32) {
    info!("Binding Desktop Shell resource");
    let cur_version = DesktopShell::supported_version();
    if version > cur_version {
        warn!("Unsupported desktop shell control protocol version {}!", version);
        warn!("We only support version {}", cur_version);
        return
    }
    let resource = ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                                 wl_resource_create,
                                 client,
                                 DesktopShell::interface_ptr(),
                                 version as c_int,
                                 id);
    if resource.is_null() {
        warn!("Out of memory, could not make a new wl_resource \
               for desktop shell");
        ffi_dispatch!(
            WAYLAND_SERVER_HANDLE,
            wl_client_post_no_memory,
            client
        );
    }
    let global_ptr = &mut DESKTOP_SHELL_GLOBAL as *mut _ as *mut c_void;
    ffi_dispatch!(
        WAYLAND_SERVER_HANDLE,
        wl_resource_set_implementation,
        resource,
        global_ptr,
        ::std::ptr::null_mut(),
        None
    );
}

unsafe extern "C" fn set_background(client: *mut wl_client,
                                    _resource: *mut wl_resource,
                                    output_: *mut wl_resource,
                                    surface: *mut wl_resource) {
    let output = wlc_handle_from_wl_output_resource(output_ as *const _);
    if output == 0 {
        return;
    }
    info!("Setting surface {:?} as background for output {}", surface, output);
    if let Ok(mut tree) = lock_tree() {
        tree.add_incomplete_background(IncompleteBackground::new(client), WlcOutput::dummy(output as _))
            .expect("Could not add incomplete background");
    }
}

unsafe extern "C" fn desktop_ready(_client: *mut wl_client,
                                   _resource: *mut wl_resource) {
    /* Intentionally left blank */
}

// TODO Implement
unsafe extern "C" fn set_lock_surface(_client: *mut wl_client,
                                      _resource: *mut wl_resource,
                                      _output: *mut wl_resource,
                                      _surface: *mut wl_resource) {}
unsafe extern "C" fn unlock(_client: *mut wl_client,
                            _resource: *mut wl_resource) {}
unsafe extern "C" fn set_grab_surface(_client: *mut wl_client,
                                      _resource: *mut wl_resource,
                                      _surface: *mut wl_resource) {}
unsafe extern "C" fn set_panel(_client: *mut wl_client,
                               _resource: *mut wl_resource,
                               _output_: *mut wl_resource,
                               _surface: *mut wl_resource) {}
unsafe extern "C" fn set_panel_position(_client: *mut wl_client,
                                        _resource:*mut wl_resource,
                                        _position: u32) {}

/// Sets up Way Cooler to announce the desktop-shell interface.
pub fn init() {
    let w_display = get_display();
    unsafe {
        info!("Initializing desktop shell");
        ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                    wl_global_create,
                    w_display as *mut _,
                    DesktopShell::interface_ptr(),
                    DesktopShell::supported_version() as i32,
                    ::std::ptr::null_mut(),
                    bind);
    }
}
<|endoftext|>


<commit_before>extern crate radix_trie;

use radix_trie::Trie;

fn main() {
    let mut t = Trie::new();
    t.insert("a", 5);
    t.insert("b", 6);
    t.insert("c", 50);

    let sum = t.child_iter().fold(0, |acc, c| {
        println!("{:#?}", c);
        acc + *c.value().unwrap_or(&0)
    });
    println!("{}", sum);
}
<commit_msg>Add an example of how to iterate through child nodes.<commit_after>extern crate radix_trie;

use radix_trie::Trie;

fn main() {
    let mut t = Trie::new();
    t.insert("z", 2);
    t.insert("aba", 5);
    t.insert("abb", 6);
    t.insert("abc", 50);

    // This is a bit of a hack that relies on knowing the binary representation of
    // strings... "abd" works, but "abz" doesn't...
    let ab_sum = t.get_raw_ancestor(&"abd").child_iter().fold(0, |acc, c| {
        println!("Iterating over child with value: {:?}", c.value());
        acc + *c.value().unwrap_or(&0)
    });

    println!("{}", ab_sum);
    assert_eq!(ab_sum, 5 + 6 + 50);
}
<|endoftext|>