<commit_before>use super::{
    function_body_chunk,
    general::{
        cfg_condition, cfg_deprecated, doc_hidden, not_version_condition, version_condition,
    },
    parameter::ToParameter,
    return_value::{out_parameters_as_return, ToReturnValue},
};
use crate::{
    analysis::{
        self,
        bounds::{Bound, Bounds},
        functions::Visibility,
        namespaces,
    },
    chunk::{ffi_function_todo, Chunk},
    env::Env,
    library,
    writer::{primitives::tabs, ToCode},
};
use log::warn;
use std::{
    fmt,
    io::{Result, Write},
    result::Result as StdResult,
};

pub fn generate(
    w: &mut dyn Write,
    env: &Env,
    analysis: &analysis::functions::Info,
    in_trait: bool,
    only_declaration: bool,
    indent: usize,
) -> Result<()> {
    if analysis.is_async_finish(env) {
        return Ok(());
    }

    let mut commented = false;
    let mut comment_prefix = "";
    let mut pub_prefix = if in_trait { "" } else { "pub " };

    match analysis.visibility {
        Visibility::Public => {}
        Visibility::Comment => {
            commented = true;
            comment_prefix = "//";
        }
        Visibility::Private => {
            if in_trait {
                warn!(
                    "Generating trait method for private function {}",
                    analysis.glib_name
                );
            } else {
                pub_prefix = "";
            }
        }
        Visibility::Hidden => return Ok(()),
    }
    let declaration = declaration(env, analysis);
    let suffix = if only_declaration { ";" } else { " {" };

    writeln!(w)?;
    if !in_trait || only_declaration {
        cfg_deprecated(w, env, analysis.deprecated_version, commented, indent)?;
    }
    cfg_condition(w, &analysis.cfg_condition, commented, indent)?;
    version_condition(w, env, analysis.version, commented, indent)?;
    not_version_condition(w, analysis.not_version, commented, indent)?;
    doc_hidden(w, analysis.doc_hidden, comment_prefix, indent)?;
    writeln!(
        w,
        "{}{}{}{}{}",
        tabs(indent),
        comment_prefix,
        pub_prefix,
        declaration,
        suffix,
    )?;

    if !only_declaration {
        let body = body_chunk(env, analysis).to_code(env);
        for s in body {
            writeln!(w, "{}{}", tabs(indent), s)?;
        }
    }

    if analysis.async_future.is_some() {
        let declaration = declaration_futures(env, analysis);
        let suffix = if only_declaration { ";" } else { " {" };

        writeln!(w)?;
        if !in_trait || only_declaration {
            cfg_deprecated(w, env, analysis.deprecated_version, commented, indent)?;
        }

        writeln!(
            w,
            "{}{}",
            tabs(indent),
            comment_prefix
        )?;
        cfg_condition(w, &analysis.cfg_condition, commented, indent)?;
        version_condition(w, env, analysis.version, commented, indent)?;
        not_version_condition(w, analysis.not_version, commented, indent)?;
        doc_hidden(w, analysis.doc_hidden, comment_prefix, indent)?;
        writeln!(
            w,
            "{}{}{}{}{}",
            tabs(indent),
            comment_prefix,
            pub_prefix,
            declaration,
            suffix
        )?;

        if !only_declaration {
            let body = body_chunk_futures(env, analysis).unwrap();
            for s in body.lines() {
                if !s.is_empty() {
                    writeln!(w, "{}{}{}", tabs(indent + 1), comment_prefix, s)?;
                } else {
                    writeln!(w)?;
                }
            }
            writeln!(w, "{}{}}}", tabs(indent), comment_prefix)?;
        }
    }

    Ok(())
}

pub fn declaration(env: &Env, analysis: &analysis::functions::Info) -> String {
    let outs_as_return = !analysis.outs.is_empty();
    let return_str = if outs_as_return {
        out_parameters_as_return(env, analysis)
    } else if analysis.ret.bool_return_is_error.is_some() {
        if env.namespaces.glib_ns_id == namespaces::MAIN {
            " -> Result<(), error::BoolError>".into()
        } else {
            " -> Result<(), glib::error::BoolError>".into()
        }
    } else {
        analysis.ret.to_return_value(env, false)
    };
    let mut param_str = String::with_capacity(100);

    let (bounds, _) = bounds(&analysis.bounds, &[], false, false);

    for par in analysis.parameters.rust_parameters.iter() {
        if !param_str.is_empty() {
            param_str.push_str(", ")
        }
        let c_par = &analysis.parameters.c_parameters[par.ind_c];
        let s = c_par.to_parameter(env, &analysis.bounds);
        param_str.push_str(&s);
    }

    format!(
        "fn {}{}({}){}",
        analysis.name, bounds, param_str, return_str,
    )
}

pub fn declaration_futures(env: &Env, analysis: &analysis::functions::Info) -> String {
    let async_future = analysis.async_future.as_ref().unwrap();

    let return_str = format!(
        " -> Pin<Box_<dyn std::future::Future<Output = Result<{}, {}>> + 'static>>",
        async_future.success_parameters, async_future.error_parameters
    );

    let mut param_str = String::with_capacity(100);

    let mut skipped = 0;
    let mut skipped_bounds = vec![];
    for (pos, par) in analysis.parameters.rust_parameters.iter().enumerate() {
        let c_par = &analysis.parameters.c_parameters[par.ind_c];

        if c_par.name == "callback" || c_par.name == "cancellable" {
            skipped += 1;
            if let Some((t, _)) = analysis.bounds.get_parameter_alias_info(&c_par.name) {
                skipped_bounds.push(t);
                if let Some(p) = analysis.bounds.get_base_alias(t) {
                    skipped_bounds.push(p);
                }
            }
            continue;
        }

        if pos - skipped > 0 {
            param_str.push_str(", ")
        }

        let s = c_par.to_parameter(env, &analysis.bounds);
        param_str.push_str(&s);
    }

    let (bounds, _) = bounds(&analysis.bounds, skipped_bounds.as_ref(), true, false);

    format!(
        "fn {}{}({}){}",
        async_future.name, bounds, param_str, return_str,
    )
}

pub fn bound_to_string(bound: &Bound, r#async: bool) -> String {
    use crate::analysis::bounds::BoundType::*;

    match bound.bound_type {
        NoWrapper => format!("{}: {}", bound.alias, bound.type_str),
        IsA(Some(lifetime)) => format!(
            "{}: IsA<{}> + {}",
            bound.alias,
            bound.type_str,
            if r#async {
                "Clone + 'static".into()
            } else {
                format!("'{}", lifetime)
            }
        ),
        IsA(None) => format!(
            "{}: IsA<{}>{}",
            bound.alias,
            bound.type_str,
            if r#async { " + Clone + 'static" } else { "" }
        ),
        // This case should normally never happened
        AsRef(Some(_ /*lifetime*/)) => {
            unreachable!();
            // format!("{}: AsRef<{}> + '{}", bound.alias, bound.type_str, lifetime)
        }
        AsRef(None) => format!("{}: AsRef<{}>", bound.alias, bound.type_str),
    }
}

pub fn bounds(
    bounds: &Bounds,
    skip: &[char],
    r#async: bool,
    filter_callback_modified: bool,
) -> (String, Vec<String>) {
    use crate::analysis::bounds::BoundType::*;

    if bounds.is_empty() {
        return (String::new(), Vec::new());
    }

    let skip_lifetimes = bounds
        .iter()
        .filter(|bound| skip.contains(&bound.alias))
        .filter_map(|bound| match bound.bound_type {
            IsA(Some(lifetime)) | AsRef(Some(lifetime)) => Some(lifetime),
            _ => None,
        })
        .collect::<Vec<_>>();

    let strs: Vec<String> = bounds
        .iter_lifetimes()
        .filter(|s| !skip_lifetimes.contains(s))
        .map(|s| format!("'{}", s))
        .chain(
            bounds
                .iter()
                .filter(|bound| {
                    !skip.contains(&bound.alias)
                        && (!filter_callback_modified || !bound.callback_modified)
                })
                .map(|b| bound_to_string(b, r#async)),
        )
        .collect();

    if strs.is_empty() {
        (String::new(), Vec::new())
    } else {
        let bounds = bounds
            .iter_lifetimes()
            .filter(|s| !skip_lifetimes.contains(s))
            .map(|s| format!("'{}", s))
            .chain(
                bounds
                    .iter()
                    .filter(|bound| {
                        !skip.contains(&bound.alias)
                            && (!filter_callback_modified || !bound.callback_modified)
                    })
                    .map(|b| b.alias.to_string()),
            )
            .collect::<Vec<_>>();
        (format!("<{}>", strs.join(", ")), bounds)
    }
}

pub fn body_chunk(env: &Env, analysis: &analysis::functions::Info) -> Chunk {
    if analysis.visibility == Visibility::Comment {
        return ffi_function_todo(env, &analysis.glib_name);
    }

    let outs_as_return = !analysis.outs.is_empty();

    let mut builder = function_body_chunk::Builder::new();
    builder
        .glib_name(&format!(
            "{}::{}",
            env.main_sys_crate_name(),
            analysis.glib_name
        ))
        .assertion(analysis.assertion)
        .ret(&analysis.ret)
        .transformations(&analysis.parameters.transformations)
        .outs_mode(analysis.outs.mode);

    if analysis.r#async {
        if let Some(ref trampoline) = analysis.trampoline {
            builder.async_trampoline(trampoline);
        } else {
            warn!(
                "Async function {} has no associated _finish function",
                analysis.name
            );
        }
    } else {
        for trampoline in analysis.callbacks.iter() {
            builder.callback(trampoline);
        }
        for trampoline in analysis.destroys.iter() {
            builder.destroy(trampoline);
        }
    }

    for par in &analysis.parameters.c_parameters {
        if outs_as_return && analysis.outs.iter().any(|p| p.name == par.name) {
            builder.out_parameter(env, par);
        } else {
            builder.parameter();
        }
    }

    let (bounds, bounds_names) = bounds(&analysis.bounds, &[], false, true);

    builder.generate(env, bounds, bounds_names.join(", "))
}

pub fn body_chunk_futures(
    env: &Env,
    analysis: &analysis::functions::Info,
) -> StdResult<String, fmt::Error> {
    use crate::analysis::ref_mode::RefMode;
    use std::fmt::Write;

    let async_future = analysis.async_future.as_ref().unwrap();

    let mut body = String::new();

    if env.config.library_name != "Gio" {
        writeln!(body, "use gio::GioFuture;")?;
    } else {
        writeln!(body, "use GioFuture;")?;
    }
    writeln!(body, "use fragile::Fragile;")?;
    writeln!(body)?;

    let skip = if async_future.is_method { 1 } else { 0 };

    // Skip the instance parameter
    for par in analysis.parameters.rust_parameters.iter().skip(skip) {
        if par.name == "cancellable" || par.name == "callback" {
            continue;
        }

        let c_par = &analysis.parameters.c_parameters[par.ind_c];

        let type_ = env.type_(par.typ);
        let is_str = if let library::Type::Fundamental(library::Fundamental::Utf8) = *type_ {
            true
        } else {
            false
        };

        if *c_par.nullable {
            writeln!(
                body,
                "let {} = {}.map(ToOwned::to_owned);",
                par.name, par.name
            )?;
        } else if is_str {
            writeln!(body, "let {} = String::from({});", par.name, par.name)?;
        } else if c_par.ref_mode != RefMode::None {
            writeln!(body, "let {} = {}.clone();", par.name, par.name)?;
        }
    }

    if async_future.is_method {
        writeln!(body, "GioFuture::new(self, move |obj, send| {{")?;
    } else {
        writeln!(body, "GioFuture::new(&(), move |_obj, send| {{")?;
    }

    if env.config.library_name != "Gio" {
        writeln!(body, "\tlet cancellable = gio::Cancellable::new();")?;
    } else {
        writeln!(body, "\tlet cancellable = Cancellable::new();")?;
    }
    writeln!(body, "\tlet send = Fragile::new(send);")?;

    if async_future.is_method {
        writeln!(body, "\tobj.{}(", analysis.name)?;
    } else if analysis.type_name.is_ok() {
        writeln!(body, "\tSelf::{}(", analysis.name)?;
    } else {
        writeln!(body, "\t{}(", analysis.name)?;
    }

    // Skip the instance parameter
    for par in analysis.parameters.rust_parameters.iter().skip(skip) {
        if par.name == "cancellable" {
            writeln!(body, "\t\tSome(&cancellable),")?;
        } else if par.name == "callback" {
            continue;
        } else {
            let c_par = &analysis.parameters.c_parameters[par.ind_c];

            if *c_par.nullable {
                writeln!(
                    body,
                    "\t\t{}.as_ref().map(::std::borrow::Borrow::borrow),",
                    par.name
                )?;
            } else if c_par.ref_mode != RefMode::None {
                writeln!(body, "\t\t&{},", par.name)?;
            } else {
                writeln!(body, "\t\t{},", par.name)?;
            }
        }
    }

    writeln!(body, "\t\tmove |res| {{")?;
    writeln!(body, "\t\t\tlet _ = send.into_inner().send(res);")?;
    writeln!(body, "\t\t}},")?;
    writeln!(body, "\t);")?;
    writeln!(body)?;
    writeln!(body, "\tcancellable")?;
    writeln!(body, "}})")?;

    Ok(body)
}
<commit_msg>Reformat<commit_after>use super::{
    function_body_chunk,
    general::{
        cfg_condition, cfg_deprecated, doc_hidden, not_version_condition, version_condition,
    },
    parameter::ToParameter,
    return_value::{out_parameters_as_return, ToReturnValue},
};
use crate::{
    analysis::{
        self,
        bounds::{Bound, Bounds},
        functions::Visibility,
        namespaces,
    },
    chunk::{ffi_function_todo, Chunk},
    env::Env,
    library,
    writer::{primitives::tabs, ToCode},
};
use log::warn;
use std::{
    fmt,
    io::{Result, Write},
    result::Result as StdResult,
};

pub fn generate(
    w: &mut dyn Write,
    env: &Env,
    analysis: &analysis::functions::Info,
    in_trait: bool,
    only_declaration: bool,
    indent: usize,
) -> Result<()> {
    if analysis.is_async_finish(env) {
        return Ok(());
    }

    let mut commented = false;
    let mut comment_prefix = "";
    let mut pub_prefix = if in_trait { "" } else { "pub " };

    match analysis.visibility {
        Visibility::Public => {}
        Visibility::Comment => {
            commented = true;
            comment_prefix = "//";
        }
        Visibility::Private => {
            if in_trait {
                warn!(
                    "Generating trait method for private function {}",
                    analysis.glib_name
                );
            } else {
                pub_prefix = "";
            }
        }
        Visibility::Hidden => return Ok(()),
    }
    let declaration = declaration(env, analysis);
    let suffix = if only_declaration { ";" } else { " {" };

    writeln!(w)?;
    if !in_trait || only_declaration {
        cfg_deprecated(w, env, analysis.deprecated_version, commented, indent)?;
    }
    cfg_condition(w, &analysis.cfg_condition, commented, indent)?;
    version_condition(w, env, analysis.version, commented, indent)?;
    not_version_condition(w, analysis.not_version, commented, indent)?;
    doc_hidden(w, analysis.doc_hidden, comment_prefix, indent)?;
    writeln!(
        w,
        "{}{}{}{}{}",
        tabs(indent),
        comment_prefix,
        pub_prefix,
        declaration,
        suffix,
    )?;

    if !only_declaration {
        let body = body_chunk(env, analysis).to_code(env);
        for s in body {
            writeln!(w, "{}{}", tabs(indent), s)?;
        }
    }

    if analysis.async_future.is_some() {
        let declaration = declaration_futures(env, analysis);
        let suffix = if only_declaration { ";" } else { " {" };

        writeln!(w)?;
        if !in_trait || only_declaration {
            cfg_deprecated(w, env, analysis.deprecated_version, commented, indent)?;
        }

        writeln!(w, "{}{}", tabs(indent), comment_prefix)?;
        cfg_condition(w, &analysis.cfg_condition, commented, indent)?;
        version_condition(w, env, analysis.version, commented, indent)?;
        not_version_condition(w, analysis.not_version, commented, indent)?;
        doc_hidden(w, analysis.doc_hidden, comment_prefix, indent)?;
        writeln!(
            w,
            "{}{}{}{}{}",
            tabs(indent),
            comment_prefix,
            pub_prefix,
            declaration,
            suffix
        )?;

        if !only_declaration {
            let body = body_chunk_futures(env, analysis).unwrap();
            for s in body.lines() {
                if !s.is_empty() {
                    writeln!(w, "{}{}{}", tabs(indent + 1), comment_prefix, s)?;
                } else {
                    writeln!(w)?;
                }
            }
            writeln!(w, "{}{}}}", tabs(indent), comment_prefix)?;
        }
    }

    Ok(())
}

pub fn declaration(env: &Env, analysis: &analysis::functions::Info) -> String {
    let outs_as_return = !analysis.outs.is_empty();
    let return_str = if outs_as_return {
        out_parameters_as_return(env, analysis)
    } else if analysis.ret.bool_return_is_error.is_some() {
        if env.namespaces.glib_ns_id == namespaces::MAIN {
            " -> Result<(), error::BoolError>".into()
        } else {
            " -> Result<(), glib::error::BoolError>".into()
        }
    } else {
        analysis.ret.to_return_value(env, false)
    };
    let mut param_str = String::with_capacity(100);

    let (bounds, _) = bounds(&analysis.bounds, &[], false, false);

    for par in analysis.parameters.rust_parameters.iter() {
        if !param_str.is_empty() {
            param_str.push_str(", ")
        }
        let c_par = &analysis.parameters.c_parameters[par.ind_c];
        let s = c_par.to_parameter(env, &analysis.bounds);
        param_str.push_str(&s);
    }

    format!(
        "fn {}{}({}){}",
        analysis.name, bounds, param_str, return_str,
    )
}

pub fn declaration_futures(env: &Env, analysis: &analysis::functions::Info) -> String {
    let async_future = analysis.async_future.as_ref().unwrap();

    let return_str = format!(
        " -> Pin<Box_<dyn std::future::Future<Output = Result<{}, {}>> + 'static>>",
        async_future.success_parameters, async_future.error_parameters
    );

    let mut param_str = String::with_capacity(100);

    let mut skipped = 0;
    let mut skipped_bounds = vec![];
    for (pos, par) in analysis.parameters.rust_parameters.iter().enumerate() {
        let c_par = &analysis.parameters.c_parameters[par.ind_c];

        if c_par.name == "callback" || c_par.name == "cancellable" {
            skipped += 1;
            if let Some((t, _)) = analysis.bounds.get_parameter_alias_info(&c_par.name) {
                skipped_bounds.push(t);
                if let Some(p) = analysis.bounds.get_base_alias(t) {
                    skipped_bounds.push(p);
                }
            }
            continue;
        }

        if pos - skipped > 0 {
            param_str.push_str(", ")
        }

        let s = c_par.to_parameter(env, &analysis.bounds);
        param_str.push_str(&s);
    }

    let (bounds, _) = bounds(&analysis.bounds, skipped_bounds.as_ref(), true, false);

    format!(
        "fn {}{}({}){}",
        async_future.name, bounds, param_str, return_str,
    )
}

pub fn bound_to_string(bound: &Bound, r#async: bool) -> String {
    use crate::analysis::bounds::BoundType::*;

    match bound.bound_type {
        NoWrapper => format!("{}: {}", bound.alias, bound.type_str),
        IsA(Some(lifetime)) => format!(
            "{}: IsA<{}> + {}",
            bound.alias,
            bound.type_str,
            if r#async {
                "Clone + 'static".into()
            } else {
                format!("'{}", lifetime)
            }
        ),
        IsA(None) => format!(
            "{}: IsA<{}>{}",
            bound.alias,
            bound.type_str,
            if r#async { " + Clone + 'static" } else { "" }
        ),
        // This case should normally never happened
        AsRef(Some(_ /*lifetime*/)) => {
            unreachable!();
            // format!("{}: AsRef<{}> + '{}", bound.alias, bound.type_str, lifetime)
        }
        AsRef(None) => format!("{}: AsRef<{}>", bound.alias, bound.type_str),
    }
}

pub fn bounds(
    bounds: &Bounds,
    skip: &[char],
    r#async: bool,
    filter_callback_modified: bool,
) -> (String, Vec<String>) {
    use crate::analysis::bounds::BoundType::*;

    if bounds.is_empty() {
        return (String::new(), Vec::new());
    }

    let skip_lifetimes = bounds
        .iter()
        .filter(|bound| skip.contains(&bound.alias))
        .filter_map(|bound| match bound.bound_type {
            IsA(Some(lifetime)) | AsRef(Some(lifetime)) => Some(lifetime),
            _ => None,
        })
        .collect::<Vec<_>>();

    let strs: Vec<String> = bounds
        .iter_lifetimes()
        .filter(|s| !skip_lifetimes.contains(s))
        .map(|s| format!("'{}", s))
        .chain(
            bounds
                .iter()
                .filter(|bound| {
                    !skip.contains(&bound.alias)
                        && (!filter_callback_modified || !bound.callback_modified)
                })
                .map(|b| bound_to_string(b, r#async)),
        )
        .collect();

    if strs.is_empty() {
        (String::new(), Vec::new())
    } else {
        let bounds = bounds
            .iter_lifetimes()
            .filter(|s| !skip_lifetimes.contains(s))
            .map(|s| format!("'{}", s))
            .chain(
                bounds
                    .iter()
                    .filter(|bound| {
                        !skip.contains(&bound.alias)
                            && (!filter_callback_modified || !bound.callback_modified)
                    })
                    .map(|b| b.alias.to_string()),
            )
            .collect::<Vec<_>>();
        (format!("<{}>", strs.join(", ")), bounds)
    }
}

pub fn body_chunk(env: &Env, analysis: &analysis::functions::Info) -> Chunk {
    if analysis.visibility == Visibility::Comment {
        return ffi_function_todo(env, &analysis.glib_name);
    }

    let outs_as_return = !analysis.outs.is_empty();

    let mut builder = function_body_chunk::Builder::new();
    builder
        .glib_name(&format!(
            "{}::{}",
            env.main_sys_crate_name(),
            analysis.glib_name
        ))
        .assertion(analysis.assertion)
        .ret(&analysis.ret)
        .transformations(&analysis.parameters.transformations)
        .outs_mode(analysis.outs.mode);

    if analysis.r#async {
        if let Some(ref trampoline) = analysis.trampoline {
            builder.async_trampoline(trampoline);
        } else {
            warn!(
                "Async function {} has no associated _finish function",
                analysis.name
            );
        }
    } else {
        for trampoline in analysis.callbacks.iter() {
            builder.callback(trampoline);
        }
        for trampoline in analysis.destroys.iter() {
            builder.destroy(trampoline);
        }
    }

    for par in &analysis.parameters.c_parameters {
        if outs_as_return && analysis.outs.iter().any(|p| p.name == par.name) {
            builder.out_parameter(env, par);
        } else {
            builder.parameter();
        }
    }

    let (bounds, bounds_names) = bounds(&analysis.bounds, &[], false, true);

    builder.generate(env, bounds, bounds_names.join(", "))
}

pub fn body_chunk_futures(
    env: &Env,
    analysis: &analysis::functions::Info,
) -> StdResult<String, fmt::Error> {
    use crate::analysis::ref_mode::RefMode;
    use std::fmt::Write;

    let async_future = analysis.async_future.as_ref().unwrap();

    let mut body = String::new();

    if env.config.library_name != "Gio" {
        writeln!(body, "use gio::GioFuture;")?;
    } else {
        writeln!(body, "use GioFuture;")?;
    }
    writeln!(body, "use fragile::Fragile;")?;
    writeln!(body)?;

    let skip = if async_future.is_method { 1 } else { 0 };

    // Skip the instance parameter
    for par in analysis.parameters.rust_parameters.iter().skip(skip) {
        if par.name == "cancellable" || par.name == "callback" {
            continue;
        }

        let c_par = &analysis.parameters.c_parameters[par.ind_c];

        let type_ = env.type_(par.typ);
        let is_str = if let library::Type::Fundamental(library::Fundamental::Utf8) = *type_ {
            true
        } else {
            false
        };

        if *c_par.nullable {
            writeln!(
                body,
                "let {} = {}.map(ToOwned::to_owned);",
                par.name, par.name
            )?;
        } else if is_str {
            writeln!(body, "let {} = String::from({});", par.name, par.name)?;
        } else if c_par.ref_mode != RefMode::None {
            writeln!(body, "let {} = {}.clone();", par.name, par.name)?;
        }
    }

    if async_future.is_method {
        writeln!(body, "GioFuture::new(self, move |obj, send| {{")?;
    } else {
        writeln!(body, "GioFuture::new(&(), move |_obj, send| {{")?;
    }

    if env.config.library_name != "Gio" {
        writeln!(body, "\tlet cancellable = gio::Cancellable::new();")?;
    } else {
        writeln!(body, "\tlet cancellable = Cancellable::new();")?;
    }
    writeln!(body, "\tlet send = Fragile::new(send);")?;

    if async_future.is_method {
        writeln!(body, "\tobj.{}(", analysis.name)?;
    } else if analysis.type_name.is_ok() {
        writeln!(body, "\tSelf::{}(", analysis.name)?;
    } else {
        writeln!(body, "\t{}(", analysis.name)?;
    }

    // Skip the instance parameter
    for par in analysis.parameters.rust_parameters.iter().skip(skip) {
        if par.name == "cancellable" {
            writeln!(body, "\t\tSome(&cancellable),")?;
        } else if par.name == "callback" {
            continue;
        } else {
            let c_par = &analysis.parameters.c_parameters[par.ind_c];

            if *c_par.nullable {
                writeln!(
                    body,
                    "\t\t{}.as_ref().map(::std::borrow::Borrow::borrow),",
                    par.name
                )?;
            } else if c_par.ref_mode != RefMode::None {
                writeln!(body, "\t\t&{},", par.name)?;
            } else {
                writeln!(body, "\t\t{},", par.name)?;
            }
        }
    }

    writeln!(body, "\t\tmove |res| {{")?;
    writeln!(body, "\t\t\tlet _ = send.into_inner().send(res);")?;
    writeln!(body, "\t\t}},")?;
    writeln!(body, "\t);")?;
    writeln!(body)?;
    writeln!(body, "\tcancellable")?;
    writeln!(body, "}})")?;

    Ok(body)
}
<|endoftext|>


<commit_before>// Copyright (C) 2020, Cloudflare, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use crate::Error;
use crate::Result;

use std::collections::VecDeque;

const DGRAM_QUEUE_DEFAULT_LEN: usize = 256;

/// Keeps track of DATAGRAM frames.
#[derive(Default)]
pub struct DatagramQueue {
    queue: VecDeque<Vec<u8>>,
    queue_max_len: usize,
    queue_bytes_size: usize,
}

impl DatagramQueue {
    pub fn new(queue_max_len: usize) -> Self {
        DatagramQueue {
            queue: VecDeque::with_capacity(
                DGRAM_QUEUE_DEFAULT_LEN.min(queue_max_len),
            ),
            queue_bytes_size: 0,
            queue_max_len,
        }
    }

    pub fn push(&mut self, data: Vec<u8>) -> Result<()> {
        if self.is_full() {
            return Err(Error::Done);
        }

        self.queue_bytes_size += data.len();
        self.queue.push_back(data);

        Ok(())
    }

    pub fn peek_front_len(&self) -> Option<usize> {
        self.queue.front().map(|d| d.len())
    }

    pub fn peek_front_bytes(&self, buf: &mut [u8], len: usize) -> Result<usize> {
        match self.queue.front() {
            Some(d) => {
                let len = std::cmp::min(len, d.len());
                if buf.len() < len {
                    return Err(Error::BufferTooShort);
                }

                buf[..len].copy_from_slice(&d[..len]);
                Ok(len)
            },

            None => Err(Error::Done),
        }
    }

    pub fn pop(&mut self) -> Option<Vec<u8>> {
        if let Some(d) = self.queue.pop_front() {
            self.queue_bytes_size = self.queue_bytes_size.saturating_sub(d.len());
            return Some(d);
        }

        None
    }

    pub fn has_pending(&self) -> bool {
        !self.queue.is_empty()
    }

    pub fn purge<F: Fn(&[u8]) -> bool>(&mut self, f: F) {
        self.queue.retain(|d| !f(d));
        self.queue_bytes_size =
            self.queue.iter().fold(0, |total, d| total + d.len());
    }

    pub fn is_full(&self) -> bool {
        self.queue.len() == self.queue_max_len
    }

    pub fn len(&self) -> usize {
        self.queue.len()
    }

    pub fn byte_size(&self) -> usize {
        self.queue_bytes_size
    }
}
<commit_msg>dgram: dont pre-allocate queue<commit_after>// Copyright (C) 2020, Cloudflare, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use crate::Error;
use crate::Result;

use std::collections::VecDeque;

/// Keeps track of DATAGRAM frames.
#[derive(Default)]
pub struct DatagramQueue {
    queue: Option<VecDeque<Vec<u8>>>,
    queue_max_len: usize,
    queue_bytes_size: usize,
}

impl DatagramQueue {
    pub fn new(queue_max_len: usize) -> Self {
        DatagramQueue {
            queue: None,
            queue_bytes_size: 0,
            queue_max_len,
        }
    }

    pub fn push(&mut self, data: Vec<u8>) -> Result<()> {
        if self.is_full() {
            return Err(Error::Done);
        }

        self.queue_bytes_size += data.len();
        self.queue
            .get_or_insert_with(Default::default)
            .push_back(data);

        Ok(())
    }

    pub fn peek_front_len(&self) -> Option<usize> {
        self.queue.as_ref().and_then(|q| q.front().map(|d| d.len()))
    }

    pub fn peek_front_bytes(&self, buf: &mut [u8], len: usize) -> Result<usize> {
        match self.queue.as_ref().and_then(|q| q.front()) {
            Some(d) => {
                let len = std::cmp::min(len, d.len());
                if buf.len() < len {
                    return Err(Error::BufferTooShort);
                }

                buf[..len].copy_from_slice(&d[..len]);
                Ok(len)
            },

            None => Err(Error::Done),
        }
    }

    pub fn pop(&mut self) -> Option<Vec<u8>> {
        if let Some(d) = self.queue.as_mut().and_then(|q| q.pop_front()) {
            self.queue_bytes_size = self.queue_bytes_size.saturating_sub(d.len());
            return Some(d);
        }

        None
    }

    pub fn has_pending(&self) -> bool {
        !self.queue.as_ref().map(|q| q.is_empty()).unwrap_or(true)
    }

    pub fn purge<F: Fn(&[u8]) -> bool>(&mut self, f: F) {
        if let Some(q) = self.queue.as_mut() {
            q.retain(|d| !f(d));
            self.queue_bytes_size = q.iter().fold(0, |total, d| total + d.len());
        }
    }

    pub fn is_full(&self) -> bool {
        self.len() == self.queue_max_len
    }

    pub fn len(&self) -> usize {
        self.queue.as_ref().map(|q| q.len()).unwrap_or(0)
    }

    pub fn byte_size(&self) -> usize {
        self.queue_bytes_size
    }
}
<|endoftext|>


<commit_before>use output::cell::{TextCell, DisplayWidth};
use output::colours::Colours;
use fs::fields as f;

impl f::Git {
    pub fn render(&self, colours: &Colours) -> TextCell {
        let git_char = |status| match status {
            &f::GitStatus::NotModified  => colours.punctuation.paint("-"),
            &f::GitStatus::New          => colours.git.new.paint("N"),
            &f::GitStatus::Modified     => colours.git.modified.paint("M"),
            &f::GitStatus::Deleted      => colours.git.deleted.paint("D"),
            &f::GitStatus::Renamed      => colours.git.renamed.paint("R"),
            &f::GitStatus::TypeChange   => colours.git.typechange.paint("T"),
        };

        TextCell {
            width: DisplayWidth::from(2),
            contents: vec![
                git_char(&self.staged),
                git_char(&self.unstaged)
            ].into(),
        }
    }
}

#[cfg(test)]
pub mod test {
    use output::details::Details;
    use output::cell::{TextCell, DisplayWidth};
    use fs::fields as f;

    use ansi_term::Colour::*;

    #[test]
    fn git_blank() {
        let mut details = Details::default();
        details.colours.punctuation = Fixed(44).normal();

        let stati = f::Git {
            staged:   f::GitStatus::NotModified,
            unstaged: f::GitStatus::NotModified,
        };

        let expected = TextCell {
            width: DisplayWidth::from(2),
            contents: vec![
                Fixed(44).paint("-"),
                Fixed(44).paint("-"),
            ].into(),
        };

        assert_eq!(expected, stati.render(&details.colours).into())
    }

    #[test]
    fn git_new_changed() {
        let mut details = Details::default();
        details.colours.git.new = Red.normal();
        details.colours.git.modified = Purple.normal();

        let stati = f::Git {
            staged:   f::GitStatus::New,
            unstaged: f::GitStatus::Modified,
        };

        let expected = TextCell {
            width: DisplayWidth::from(2),
            contents: vec![
                Red.paint("N"),
                Purple.paint("M"),
            ].into(),
        };

        assert_eq!(expected, stati.render(&details.colours).into())
    }
}
<commit_msg>A Git status character should render itself, too<commit_after>use ansi_term::ANSIString;

use output::cell::{TextCell, DisplayWidth};
use output::colours::Colours;
use fs::fields as f;

impl f::Git {
    pub fn render(&self, colours: &Colours) -> TextCell {
        TextCell {
            width: DisplayWidth::from(2),
            contents: vec![
                self.staged.render(colours),
                self.unstaged.render(colours),
            ].into(),
        }
    }
}

impl f::GitStatus {
    fn render(&self, colours: &Colours) -> ANSIString<'static> {
        match *self {
            f::GitStatus::NotModified  => colours.punctuation.paint("-"),
            f::GitStatus::New          => colours.git.new.paint("N"),
            f::GitStatus::Modified     => colours.git.modified.paint("M"),
            f::GitStatus::Deleted      => colours.git.deleted.paint("D"),
            f::GitStatus::Renamed      => colours.git.renamed.paint("R"),
            f::GitStatus::TypeChange   => colours.git.typechange.paint("T"),
        }
    }
}

#[cfg(test)]
pub mod test {
    use output::details::Details;
    use output::cell::{TextCell, DisplayWidth};
    use fs::fields as f;

    use ansi_term::Colour::*;

    #[test]
    fn git_blank() {
        let mut details = Details::default();
        details.colours.punctuation = Fixed(44).normal();

        let stati = f::Git {
            staged:   f::GitStatus::NotModified,
            unstaged: f::GitStatus::NotModified,
        };

        let expected = TextCell {
            width: DisplayWidth::from(2),
            contents: vec![
                Fixed(44).paint("-"),
                Fixed(44).paint("-"),
            ].into(),
        };

        assert_eq!(expected, stati.render(&details.colours).into())
    }

    #[test]
    fn git_new_changed() {
        let mut details = Details::default();
        details.colours.git.new = Red.normal();
        details.colours.git.modified = Purple.normal();

        let stati = f::Git {
            staged:   f::GitStatus::New,
            unstaged: f::GitStatus::Modified,
        };

        let expected = TextCell {
            width: DisplayWidth::from(2),
            contents: vec![
                Red.paint("N"),
                Purple.paint("M"),
            ].into(),
        };

        assert_eq!(expected, stati.render(&details.colours).into())
    }
}
<|endoftext|>


<commit_before>use std::num::{FloatMath};
use std::collections::HashMap;
use time;
use calx::{V2};
use calx::{Context, Rgb};
use calx::color::*;
use calx::timing;
use world::TerrainType;
use world::{Location, Chart};
use world::{FovStatus, EntityKind, MobType, MOB_SPECS};
use world::{Entity};
use viewutil::{chart_to_screen, cells_on_screen};
use viewutil::{FLOOR_Z, BLOCK_Z};
use drawable::{Drawable};
use tilecache;
use tilecache::tile::*;

pub fn draw_world<C: Chart>(chart: &C, ctx: &mut Context, damage_timers: &HashMap<Entity, uint>) {
    for pt in cells_on_screen() {
        let screen_pos = chart_to_screen(pt);
        let loc = *chart + pt;
        let cell_drawable = CellDrawable::new(loc, loc.fov_status(), damage_timers);
        cell_drawable.draw(ctx, screen_pos);
    }
}

/// Drawable representation of a single map location.
pub struct CellDrawable<'a> {
    loc: Location,
    fov: Option<FovStatus>,
    damage_timers: &'a HashMap<Entity, uint>
}

impl<'a> Drawable for CellDrawable<'a> {
    fn draw(&self, ctx: &mut Context, offset: V2<int>) {
        match self.fov {
            Some(_) => {
                self.draw_cell(ctx, offset)
            }
            None => {
                let (front_of_wall, is_door) = classify(self);
                if front_of_wall && !is_door {
                    self.draw_tile(ctx, CUBE, offset, BLOCK_Z, &BLACK);
                } else if !front_of_wall {
                    self.draw_tile(ctx, BLOCK_DARK, offset, BLOCK_Z, &BLACK);
                }
            }
        }

        fn classify(c: &CellDrawable) -> (bool, bool) {
            let mut front_of_wall = false;
            let mut is_door = false;
            let nw = c.loc + V2(-1, 0);
            let ne = c.loc + V2(0, -1);

            for &p in vec![nw, ne].iter() {
                let t = p.terrain();
                if t.is_wall() {
                    front_of_wall = true;
                    if !t.blocks_walk() { is_door = true; }
                }
            }
            (front_of_wall, is_door)
        }
    }
}

impl<'a> CellDrawable<'a> {
    pub fn new(
        loc: Location,
        fov: Option<FovStatus>,
        damage_timers: &'a HashMap<Entity, uint>) -> CellDrawable<'a> {
        CellDrawable {
            loc: loc,
            fov: fov,
            damage_timers: damage_timers,
        }
    }

    fn draw_tile(&'a self, ctx: &mut Context, idx: uint, offset: V2<int>, z: f32, color: &Rgb) {
        let color = match self.fov {
            Some(FovStatus::Remembered) => Rgb::new(0x22u8, 0x22u8, 0x11u8),
            _ => *color,
        };
        ctx.draw_image(offset, z, tilecache::get(idx), &color);
    }

    fn draw_cell(&'a self, ctx: &mut Context, offset: V2<int>) {
        self.draw_terrain(ctx, offset);

        if self.fov == Some(FovStatus::Seen) {
            for e in self.loc.entities().iter() {
                self.draw_entity(ctx, offset, e);
            }
        }
    }

    fn draw_terrain(&'a self, ctx: &mut Context, offset: V2<int>) {
        let k = Kernel::new(|loc| loc.terrain(), self.loc);
        match k.center {
            TerrainType::Void => {
                self.draw_tile(ctx, BLANK_FLOOR, offset, FLOOR_Z, &BLACK);
            },
            TerrainType::Water => {
                self.draw_tile(ctx, WATER, offset, FLOOR_Z, &ROYALBLUE);
            },
            TerrainType::Shallows => {
                self.draw_tile(ctx, SHALLOWS, offset, FLOOR_Z, &CORNFLOWERBLUE);
            },
            TerrainType::Magma => {
                self.draw_tile(ctx, MAGMA, offset, FLOOR_Z, &DARKRED);
            },
            TerrainType::Tree => {
                // A two-toner, with floor, using two z-layers
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                self.draw_tile(ctx, TREE_TRUNK, offset, BLOCK_Z, &SADDLEBROWN);
                self.draw_tile(ctx, TREE_FOLIAGE, offset, BLOCK_Z, &GREEN);
            },
            TerrainType::Floor => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
            },
            TerrainType::Chasm => {
                self.draw_tile(ctx, CHASM, offset, FLOOR_Z, &DARKSLATEGRAY);
            },
            TerrainType::Grass => {
                self.draw_tile(ctx, GRASS, offset, FLOOR_Z, &DARKGREEN);
            },
            TerrainType::Downstairs => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                self.draw_tile(ctx, DOWNSTAIRS, offset, BLOCK_Z, &SLATEGRAY);
            },
            TerrainType::Portal => {
                let glow = (127.0 *(1.0 + (time::precise_time_s()).sin())) as u8;
                let portal_col = Rgb::new(glow, glow, 255);
                self.draw_tile(ctx, PORTAL, offset, BLOCK_Z, &portal_col);
            },
            TerrainType::Rock => {
                blockform(self, ctx, &k, offset, BLOCK, &DARKGOLDENROD);
            }
            TerrainType::Wall => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                wallform(self, ctx, &k, offset, WALL, &LIGHTSLATEGRAY, true);
            },
            TerrainType::RockWall => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                wallform(self, ctx, &k, offset, ROCKWALL, &LIGHTSLATEGRAY, true);
            },
            TerrainType::Fence => {
                // The floor type beneath the fence tile is visible, make it grass
                // if there's grass behind the fence. Otherwise make it regular
                // floor.
                if k.n == TerrainType::Grass || k.ne == TerrainType::Grass || k.nw == TerrainType::Grass {
                    self.draw_tile(ctx, GRASS, offset, FLOOR_Z, &DARKGREEN);
                } else {
                    self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                }
                wallform(self, ctx, &k, offset, FENCE, &DARKGOLDENROD, false);
            },
            TerrainType::Bars => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                wallform(self, ctx, &k, offset, BARS, &GAINSBORO, false);
            },
            TerrainType::Stalagmite => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                self.draw_tile(ctx, STALAGMITE, offset, BLOCK_Z, &DARKGOLDENROD);
            },
            TerrainType::Window => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                wallform(self, ctx, &k, offset, WINDOW, &LIGHTSLATEGRAY, false);
            },
            TerrainType::Door => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                wallform(self, ctx, &k, offset, DOOR, &LIGHTSLATEGRAY, true);
                wallform(self, ctx, &k, offset, DOOR + 4, &SADDLEBROWN, false);
            },
            TerrainType::OpenDoor => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                wallform(self, ctx, &k, offset, DOOR, &LIGHTSLATEGRAY, true);
            },
            TerrainType::Table => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                self.draw_tile(ctx, TABLE, offset, BLOCK_Z, &DARKGOLDENROD);
            },
            TerrainType::Fountain => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                self.draw_tile(ctx, FOUNTAIN, offset, BLOCK_Z, &GAINSBORO);
            },
            TerrainType::Altar => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                self.draw_tile(ctx, ALTAR, offset, BLOCK_Z, &GAINSBORO);
            },
            TerrainType::Barrel => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                self.draw_tile(ctx, BARREL, offset, BLOCK_Z, &DARKGOLDENROD);
            },
            TerrainType::Grave => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                self.draw_tile(ctx, GRAVE, offset, BLOCK_Z, &SLATEGRAY);
            },
            TerrainType::Stone => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                self.draw_tile(ctx, STONE, offset, BLOCK_Z, &SLATEGRAY);
            },
            TerrainType::Menhir => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                self.draw_tile(ctx, MENHIR, offset, BLOCK_Z, &SLATEGRAY);
            },
            TerrainType::DeadTree => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                self.draw_tile(ctx, TREE_TRUNK, offset, BLOCK_Z, &SADDLEBROWN);
            },
            TerrainType::TallGrass => {
                self.draw_tile(ctx, TALLGRASS, offset, BLOCK_Z, &GOLD);
            },
        }

        fn blockform(c: &CellDrawable, ctx: &mut Context, k: &Kernel<TerrainType>, offset: V2<int>, idx: uint, color: &Rgb) {
            c.draw_tile(ctx, idx, offset, BLOCK_Z, color);
            // Back lines for blocks with open floor behind them.
            if !k.nw.is_wall() {
                c.draw_tile(ctx, BLOCK_NW, offset, BLOCK_Z, color);
            }
            if !k.n.is_wall() {
                c.draw_tile(ctx, BLOCK_N, offset, BLOCK_Z, color);
            }
            if !k.ne.is_wall() {
                c.draw_tile(ctx, BLOCK_NE, offset, BLOCK_Z, color);
            }
        }

        fn wallform(c: &CellDrawable, ctx: &mut Context, k: &Kernel<TerrainType>, offset: V2<int>, idx: uint, color: &Rgb, opaque: bool) {
            let (left_wall, right_wall, block) = wall_flags_lrb(k);
            if block {
                if opaque {
                    c.draw_tile(ctx, CUBE, offset, BLOCK_Z, color);
                } else {
                    c.draw_tile(ctx, idx + 2, offset, BLOCK_Z, color);
                    return;
                }
            }
            if left_wall && right_wall {
                c.draw_tile(ctx, idx + 2, offset, BLOCK_Z, color);
            } else if left_wall {
                c.draw_tile(ctx, idx, offset, BLOCK_Z, color);
            } else if right_wall {
                c.draw_tile(ctx, idx + 1, offset, BLOCK_Z, color);
            } else if !block || !k.s.is_wall() {
                // NB: This branch has some actual local kernel logic not
                // handled by wall_flags_lrb.
                let idx = if k.n.is_wall() {
                    // TODO: Walltile-specific XY-walls
                    XYWALL
                } else {
                    idx + 3
                };
                c.draw_tile(ctx, idx, offset, BLOCK_Z, color);
            }
        }

        // Return code:
        // (there is a wall piece to the left front of the tile,
        //  there is a wall piece to the right front of the tile,
        //  there is a solid block in the tile)
        fn wall_flags_lrb(k: &Kernel<TerrainType>) -> (bool, bool, bool) {
            if k.nw.is_wall() && k.n.is_wall() && k.ne.is_wall() {
                // If there is open space to east or west, even if this block
                // has adjacent walls to the southeast or the southwest, those
                // will be using thin wall sprites, so this block needs to have
                // the corresponding wall bit to make the wall line not have
                // gaps.
                (!k.w.is_wall() || !k.sw.is_wall(), !k.e.is_wall() || !k.se.is_wall(), true)
            } else {
                (k.nw.is_wall(), k.ne.is_wall(), false)
            }
        }
    }

    fn draw_entity(&'a self, ctx: &mut Context, offset: V2<int>, entity: &Entity) {
        match entity.kind() {
            EntityKind::Mob(m) => {
                let body_pos =
                    if entity.is_bobbing() {
                        offset + *(timing::cycle_anim(
                                0.3f64,
                                &[V2(0, 0), V2(0, -1)]))
                    } else { offset };

                let (icon, mut color) = (
                    MOB_SPECS[m as uint].sprite,
                    MOB_SPECS[m as uint].color);

                if let Some(&t) = self.damage_timers.get(entity) {
                    color = if t % 2 == 0 { &WHITE } else { &BLACK };
                }

                if m == MobType::Serpent {
                    // Special case, Serpent sprite is made of two parts.
                    // Body
                    self.draw_tile(ctx, icon, body_pos, BLOCK_Z, color);
                    // Ground mound, doesn't bob.
                    self.draw_tile(ctx, icon + 1, offset, BLOCK_Z, color);
                } else {
                    self.draw_tile(ctx, icon, body_pos, BLOCK_Z, color);
                }
            }
            todo => { println!("TODO: Draw {} entity", todo) }
        }
    }
}

/// 3x3 grid of terrain cells. Use this as the input for terrain tile
/// computation, which will need to consider the immediate vicinity of cells.
struct Kernel<C> {
    n: C,
    ne: C,
    e: C,
    nw: C,
    center: C,
    se: C,
    w: C,
    sw: C,
    s: C,
}

impl<C: Clone> Kernel<C> {
    pub fn new(get: |Location| -> C, loc: Location) -> Kernel<C> {
        Kernel {
            n: get(loc + V2(-1, -1)),
            ne: get(loc + V2(0, -1)),
            e: get(loc + V2(1, -1)),
            nw: get(loc + V2(-1, 0)),
            center: get(loc),
            se: get(loc + V2(1, 0)),
            w: get(loc + V2(-1, 1)),
            sw: get(loc + V2(0, 1)),
            s: get(loc + V2(1, 1)),
        }
    }
}
<commit_msg>Tweak XY-wall logic<commit_after>use std::num::{FloatMath};
use std::collections::HashMap;
use time;
use calx::{V2};
use calx::{Context, Rgb};
use calx::color::*;
use calx::timing;
use world::TerrainType;
use world::{Location, Chart};
use world::{FovStatus, EntityKind, MobType, MOB_SPECS};
use world::{Entity};
use viewutil::{chart_to_screen, cells_on_screen};
use viewutil::{FLOOR_Z, BLOCK_Z};
use drawable::{Drawable};
use tilecache;
use tilecache::tile::*;

pub fn draw_world<C: Chart>(chart: &C, ctx: &mut Context, damage_timers: &HashMap<Entity, uint>) {
    for pt in cells_on_screen() {
        let screen_pos = chart_to_screen(pt);
        let loc = *chart + pt;
        let cell_drawable = CellDrawable::new(loc, loc.fov_status(), damage_timers);
        cell_drawable.draw(ctx, screen_pos);
    }
}

/// Drawable representation of a single map location.
pub struct CellDrawable<'a> {
    loc: Location,
    fov: Option<FovStatus>,
    damage_timers: &'a HashMap<Entity, uint>
}

impl<'a> Drawable for CellDrawable<'a> {
    fn draw(&self, ctx: &mut Context, offset: V2<int>) {
        match self.fov {
            Some(_) => {
                self.draw_cell(ctx, offset)
            }
            None => {
                let (front_of_wall, is_door) = classify(self);
                if front_of_wall && !is_door {
                    self.draw_tile(ctx, CUBE, offset, BLOCK_Z, &BLACK);
                } else if !front_of_wall {
                    self.draw_tile(ctx, BLOCK_DARK, offset, BLOCK_Z, &BLACK);
                }
            }
        }

        fn classify(c: &CellDrawable) -> (bool, bool) {
            let mut front_of_wall = false;
            let mut is_door = false;
            let nw = c.loc + V2(-1, 0);
            let ne = c.loc + V2(0, -1);

            for &p in vec![nw, ne].iter() {
                let t = p.terrain();
                if t.is_wall() {
                    front_of_wall = true;
                    if !t.blocks_walk() { is_door = true; }
                }
            }
            (front_of_wall, is_door)
        }
    }
}

impl<'a> CellDrawable<'a> {
    pub fn new(
        loc: Location,
        fov: Option<FovStatus>,
        damage_timers: &'a HashMap<Entity, uint>) -> CellDrawable<'a> {
        CellDrawable {
            loc: loc,
            fov: fov,
            damage_timers: damage_timers,
        }
    }

    fn draw_tile(&'a self, ctx: &mut Context, idx: uint, offset: V2<int>, z: f32, color: &Rgb) {
        let color = match self.fov {
            Some(FovStatus::Remembered) => Rgb::new(0x22u8, 0x22u8, 0x11u8),
            _ => *color,
        };
        ctx.draw_image(offset, z, tilecache::get(idx), &color);
    }

    fn draw_cell(&'a self, ctx: &mut Context, offset: V2<int>) {
        self.draw_terrain(ctx, offset);

        if self.fov == Some(FovStatus::Seen) {
            for e in self.loc.entities().iter() {
                self.draw_entity(ctx, offset, e);
            }
        }
    }

    fn draw_terrain(&'a self, ctx: &mut Context, offset: V2<int>) {
        let k = Kernel::new(|loc| loc.terrain(), self.loc);
        match k.center {
            TerrainType::Void => {
                self.draw_tile(ctx, BLANK_FLOOR, offset, FLOOR_Z, &BLACK);
            },
            TerrainType::Water => {
                self.draw_tile(ctx, WATER, offset, FLOOR_Z, &ROYALBLUE);
            },
            TerrainType::Shallows => {
                self.draw_tile(ctx, SHALLOWS, offset, FLOOR_Z, &CORNFLOWERBLUE);
            },
            TerrainType::Magma => {
                self.draw_tile(ctx, MAGMA, offset, FLOOR_Z, &DARKRED);
            },
            TerrainType::Tree => {
                // A two-toner, with floor, using two z-layers
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                self.draw_tile(ctx, TREE_TRUNK, offset, BLOCK_Z, &SADDLEBROWN);
                self.draw_tile(ctx, TREE_FOLIAGE, offset, BLOCK_Z, &GREEN);
            },
            TerrainType::Floor => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
            },
            TerrainType::Chasm => {
                self.draw_tile(ctx, CHASM, offset, FLOOR_Z, &DARKSLATEGRAY);
            },
            TerrainType::Grass => {
                self.draw_tile(ctx, GRASS, offset, FLOOR_Z, &DARKGREEN);
            },
            TerrainType::Downstairs => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                self.draw_tile(ctx, DOWNSTAIRS, offset, BLOCK_Z, &SLATEGRAY);
            },
            TerrainType::Portal => {
                let glow = (127.0 *(1.0 + (time::precise_time_s()).sin())) as u8;
                let portal_col = Rgb::new(glow, glow, 255);
                self.draw_tile(ctx, PORTAL, offset, BLOCK_Z, &portal_col);
            },
            TerrainType::Rock => {
                blockform(self, ctx, &k, offset, BLOCK, &DARKGOLDENROD);
            }
            TerrainType::Wall => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                wallform(self, ctx, &k, offset, WALL, &LIGHTSLATEGRAY, true);
            },
            TerrainType::RockWall => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                wallform(self, ctx, &k, offset, ROCKWALL, &LIGHTSLATEGRAY, true);
            },
            TerrainType::Fence => {
                // The floor type beneath the fence tile is visible, make it grass
                // if there's grass behind the fence. Otherwise make it regular
                // floor.
                if k.n == TerrainType::Grass || k.ne == TerrainType::Grass || k.nw == TerrainType::Grass {
                    self.draw_tile(ctx, GRASS, offset, FLOOR_Z, &DARKGREEN);
                } else {
                    self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                }
                wallform(self, ctx, &k, offset, FENCE, &DARKGOLDENROD, false);
            },
            TerrainType::Bars => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                wallform(self, ctx, &k, offset, BARS, &GAINSBORO, false);
            },
            TerrainType::Stalagmite => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                self.draw_tile(ctx, STALAGMITE, offset, BLOCK_Z, &DARKGOLDENROD);
            },
            TerrainType::Window => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                wallform(self, ctx, &k, offset, WINDOW, &LIGHTSLATEGRAY, false);
            },
            TerrainType::Door => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                wallform(self, ctx, &k, offset, DOOR, &LIGHTSLATEGRAY, true);
                wallform(self, ctx, &k, offset, DOOR + 4, &SADDLEBROWN, false);
            },
            TerrainType::OpenDoor => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                wallform(self, ctx, &k, offset, DOOR, &LIGHTSLATEGRAY, true);
            },
            TerrainType::Table => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                self.draw_tile(ctx, TABLE, offset, BLOCK_Z, &DARKGOLDENROD);
            },
            TerrainType::Fountain => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                self.draw_tile(ctx, FOUNTAIN, offset, BLOCK_Z, &GAINSBORO);
            },
            TerrainType::Altar => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                self.draw_tile(ctx, ALTAR, offset, BLOCK_Z, &GAINSBORO);
            },
            TerrainType::Barrel => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                self.draw_tile(ctx, BARREL, offset, BLOCK_Z, &DARKGOLDENROD);
            },
            TerrainType::Grave => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                self.draw_tile(ctx, GRAVE, offset, BLOCK_Z, &SLATEGRAY);
            },
            TerrainType::Stone => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                self.draw_tile(ctx, STONE, offset, BLOCK_Z, &SLATEGRAY);
            },
            TerrainType::Menhir => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                self.draw_tile(ctx, MENHIR, offset, BLOCK_Z, &SLATEGRAY);
            },
            TerrainType::DeadTree => {
                self.draw_tile(ctx, FLOOR, offset, FLOOR_Z, &SLATEGRAY);
                self.draw_tile(ctx, TREE_TRUNK, offset, BLOCK_Z, &SADDLEBROWN);
            },
            TerrainType::TallGrass => {
                self.draw_tile(ctx, TALLGRASS, offset, BLOCK_Z, &GOLD);
            },
        }

        fn blockform(c: &CellDrawable, ctx: &mut Context, k: &Kernel<TerrainType>, offset: V2<int>, idx: uint, color: &Rgb) {
            c.draw_tile(ctx, idx, offset, BLOCK_Z, color);
            // Back lines for blocks with open floor behind them.
            if !k.nw.is_wall() {
                c.draw_tile(ctx, BLOCK_NW, offset, BLOCK_Z, color);
            }
            if !k.n.is_wall() {
                c.draw_tile(ctx, BLOCK_N, offset, BLOCK_Z, color);
            }
            if !k.ne.is_wall() {
                c.draw_tile(ctx, BLOCK_NE, offset, BLOCK_Z, color);
            }
        }

        fn wallform(c: &CellDrawable, ctx: &mut Context, k: &Kernel<TerrainType>, offset: V2<int>, idx: uint, color: &Rgb, opaque: bool) {
            let (left_wall, right_wall, block) = wall_flags_lrb(k);
            if block {
                if opaque {
                    c.draw_tile(ctx, CUBE, offset, BLOCK_Z, color);
                } else {
                    c.draw_tile(ctx, idx + 2, offset, BLOCK_Z, color);
                    return;
                }
            }
            if left_wall && right_wall {
                c.draw_tile(ctx, idx + 2, offset, BLOCK_Z, color);
            } else if left_wall {
                c.draw_tile(ctx, idx, offset, BLOCK_Z, color);
            } else if right_wall {
                c.draw_tile(ctx, idx + 1, offset, BLOCK_Z, color);
            } else if !block || !k.s.is_wall() {
                // NB: This branch has some actual local kernel logic not
                // handled by wall_flags_lrb.
                let idx = if k.n.is_wall() && (!k.nw.is_wall() || !k.ne.is_wall()) {
                    // TODO: Walltile-specific XY-walls
                    XYWALL
                } else {
                    idx + 3
                };
                c.draw_tile(ctx, idx, offset, BLOCK_Z, color);
            }
        }

        // Return code:
        // (there is a wall piece to the left front of the tile,
        //  there is a wall piece to the right front of the tile,
        //  there is a solid block in the tile)
        fn wall_flags_lrb(k: &Kernel<TerrainType>) -> (bool, bool, bool) {
            if k.nw.is_wall() && k.n.is_wall() && k.ne.is_wall() {
                // If there is open space to east or west, even if this block
                // has adjacent walls to the southeast or the southwest, those
                // will be using thin wall sprites, so this block needs to have
                // the corresponding wall bit to make the wall line not have
                // gaps.
                (!k.w.is_wall() || !k.sw.is_wall(), !k.e.is_wall() || !k.se.is_wall(), true)
            } else {
                (k.nw.is_wall(), k.ne.is_wall(), false)
            }
        }
    }

    fn draw_entity(&'a self, ctx: &mut Context, offset: V2<int>, entity: &Entity) {
        match entity.kind() {
            EntityKind::Mob(m) => {
                let body_pos =
                    if entity.is_bobbing() {
                        offset + *(timing::cycle_anim(
                                0.3f64,
                                &[V2(0, 0), V2(0, -1)]))
                    } else { offset };

                let (icon, mut color) = (
                    MOB_SPECS[m as uint].sprite,
                    MOB_SPECS[m as uint].color);

                if let Some(&t) = self.damage_timers.get(entity) {
                    color = if t % 2 == 0 { &WHITE } else { &BLACK };
                }

                if m == MobType::Serpent {
                    // Special case, Serpent sprite is made of two parts.
                    // Body
                    self.draw_tile(ctx, icon, body_pos, BLOCK_Z, color);
                    // Ground mound, doesn't bob.
                    self.draw_tile(ctx, icon + 1, offset, BLOCK_Z, color);
                } else {
                    self.draw_tile(ctx, icon, body_pos, BLOCK_Z, color);
                }
            }
            todo => { println!("TODO: Draw {} entity", todo) }
        }
    }
}

/// 3x3 grid of terrain cells. Use this as the input for terrain tile
/// computation, which will need to consider the immediate vicinity of cells.
struct Kernel<C> {
    n: C,
    ne: C,
    e: C,
    nw: C,
    center: C,
    se: C,
    w: C,
    sw: C,
    s: C,
}

impl<C: Clone> Kernel<C> {
    pub fn new(get: |Location| -> C, loc: Location) -> Kernel<C> {
        Kernel {
            n: get(loc + V2(-1, -1)),
            ne: get(loc + V2(0, -1)),
            e: get(loc + V2(1, -1)),
            nw: get(loc + V2(-1, 0)),
            center: get(loc),
            se: get(loc + V2(1, 0)),
            w: get(loc + V2(-1, 1)),
            sw: get(loc + V2(0, 1)),
            s: get(loc + V2(1, 1)),
        }
    }
}
<|endoftext|>


<commit_before>//! Binding shim for libz80e-core
extern crate libc;
use self::libc::{ c_int, c_void, pthread_mutex_t };

#[allow(dead_code)]
#[repr(C)]
pub struct z80e_registers {
    af: u16,
    bc: u16,
    de: u16,
    hl: u16,
    _af: u16,
    _bc: u16,
    _de: u16,
    _hl: u16,
    pc: u16,
    sp: u16,
    ix: u16,
    iy: u16,
    i: u8,
    r: u8,
    wz: u16,
}

#[allow(dead_code)]
#[repr(C)]
pub struct z80e_io_device {
    pub device: *mut c_void,
    pub read_in: extern fn(*mut c_void) -> u8,
    pub write_out: extern fn(*mut c_void, u8),
}

#[allow(dead_code)]
#[repr(C)]
pub struct z80e_cpu {
    pub devices: [z80e_io_device; 100],
    registers: z80e_registers,
    iff1: bool,
    iff2: bool,
    int_mode: u8,
    iff_wait: bool,
    halted: bool,
    prefix: u16,
    pub memory: *mut c_void,
    pub read_byte: extern fn(*mut c_void, u16) -> u8,
    pub write_byte: extern fn(*mut c_void, u16, u8),
    bus_lock: pthread_mutex_t,
    interrupt: bool,
    bus: u8,
}

#[allow(dead_code)]
#[link(name = "z80e-core")]
extern {
    pub fn cpu_init() -> *mut z80e_cpu;
    pub fn cpu_free(cpu: *mut z80e_cpu);
    pub fn cpu_interrupt(cpu: *mut z80e_cpu, bus: u8) -> c_int;
    pub fn cpu_try_interrupt(cpu: *mut z80e_cpu, bus: u8) -> c_int;
//    pub fn cpu_clear_interrupt(cpu: *mut z80e_cpu) -> c_int;
//    pub fn cpu_try_clear_interrupt(cpu: *mut z80e_cpu) -> c_int;
    pub fn cpu_execute(cpu: *mut z80e_cpu, cycles: c_int) -> c_int;
}
<commit_msg>Fix length of I/O device array<commit_after>//! Binding shim for libz80e-core
extern crate libc;
use self::libc::{ c_int, c_void, pthread_mutex_t };

#[allow(dead_code)]
#[repr(C)]
pub struct z80e_registers {
    af: u16,
    bc: u16,
    de: u16,
    hl: u16,
    _af: u16,
    _bc: u16,
    _de: u16,
    _hl: u16,
    pc: u16,
    sp: u16,
    ix: u16,
    iy: u16,
    i: u8,
    r: u8,
    wz: u16,
}

#[allow(dead_code)]
#[repr(C)]
pub struct z80e_io_device {
    pub device: *mut c_void,
    pub read_in: extern fn(*mut c_void) -> u8,
    pub write_out: extern fn(*mut c_void, u8),
}

#[allow(dead_code)]
#[repr(C)]
pub struct z80e_cpu {
    pub devices: [z80e_io_device; 0x100],
    registers: z80e_registers,
    iff1: bool,
    iff2: bool,
    int_mode: u8,
    iff_wait: bool,
    halted: bool,
    prefix: u16,
    pub memory: *mut c_void,
    pub read_byte: extern fn(*mut c_void, u16) -> u8,
    pub write_byte: extern fn(*mut c_void, u16, u8),
    bus_lock: pthread_mutex_t,
    interrupt: bool,
    bus: u8,
}

#[allow(dead_code)]
#[link(name = "z80e-core")]
extern {
    pub fn cpu_init() -> *mut z80e_cpu;
    pub fn cpu_free(cpu: *mut z80e_cpu);
    pub fn cpu_interrupt(cpu: *mut z80e_cpu, bus: u8) -> c_int;
    pub fn cpu_try_interrupt(cpu: *mut z80e_cpu, bus: u8) -> c_int;
//    pub fn cpu_clear_interrupt(cpu: *mut z80e_cpu) -> c_int;
//    pub fn cpu_try_clear_interrupt(cpu: *mut z80e_cpu) -> c_int;
    pub fn cpu_execute(cpu: *mut z80e_cpu, cycles: c_int) -> c_int;
}
<|endoftext|>


<commit_before>import util::common::ty_mach;
import util::common::ty_mach_to_str;
import util::common::new_str_hash;
import util::data::interner;
import std::int;
import std::uint;
import std::str;

type str_num = uint;

tag binop {
    PLUS;
    MINUS;
    STAR;
    SLASH;
    PERCENT;
    CARET;
    AND;
    OR;
    LSL;
    LSR;
    ASR;
}

tag token {
    /* Expression-operator symbols. */
    EQ;
    LT;
    LE;
    EQEQ;
    NE;
    GE;
    GT;
    ANDAND;
    OROR;
    NOT;
    TILDE;

    BINOP(binop);
    BINOPEQ(binop);

    /* Structural symbols */
    AT;
    DOT;
    COMMA;
    SEMI;
    COLON;
    MOD_SEP;
    QUES;
    RARROW;
    SEND;
    RECV;
    LARROW;
    LPAREN;
    RPAREN;
    LBRACKET;
    RBRACKET;
    LBRACE;
    RBRACE;

    POUND;

    /* Literals */
    LIT_INT(int);
    LIT_UINT(uint);
    LIT_MACH_INT(ty_mach, int);
    LIT_FLOAT(str_num);
    LIT_MACH_FLOAT(ty_mach, str_num);
    LIT_STR(str_num);
    LIT_CHAR(char);
    LIT_BOOL(bool);

    /* Name components */
    IDENT(str_num, bool);
    IDX(int);
    UNDERSCORE;

    BRACEQUOTE(str_num);
    EOF;
}

fn binop_to_str(binop o) -> str {
    alt (o) {
        case (PLUS) { ret "+"; }
        case (MINUS) { ret "-"; }
        case (STAR) { ret "*"; }
        case (SLASH) { ret "/"; }
        case (PERCENT) { ret "%"; }
        case (CARET) { ret "^"; }
        case (AND) { ret "&"; }
        case (OR) { ret "|"; }
        case (LSL) { ret "<<"; }
        case (LSR) { ret ">>"; }
        case (ASR) { ret ">>>"; }
    }
}

fn to_str(lexer::reader r, token t) -> str {
    alt (t) {

        case (EQ) { ret "="; }
        case (LT) { ret "<"; }
        case (LE) { ret "<="; }
        case (EQEQ) { ret "=="; }
        case (NE) { ret "!="; }
        case (GE) { ret ">="; }
        case (GT) { ret ">"; }
        case (NOT) { ret "!"; }
        case (TILDE) { ret "~"; }
        case (OROR) { ret "||"; }
        case (ANDAND) { ret "&&"; }

        case (BINOP(?op)) { ret binop_to_str(op); }
        case (BINOPEQ(?op)) { ret binop_to_str(op) + "="; }

        /* Structural symbols */
        case (AT) { ret "@"; }
        case (DOT) { ret "."; }
        case (COMMA) { ret ","; }
        case (SEMI) { ret ";"; }
        case (COLON) { ret ":"; }
        case (MOD_SEP) { ret "::"; }
        case (QUES) { ret "?"; }
        case (RARROW) { ret "->"; }
        case (SEND) { ret "<|"; }
        case (LARROW) { ret "<-"; }
        case (LPAREN) { ret "("; }
        case (RPAREN) { ret ")"; }
        case (LBRACKET) { ret "["; }
        case (RBRACKET) { ret "]"; }
        case (LBRACE) { ret "{"; }
        case (RBRACE) { ret "}"; }

        case (POUND) { ret "#"; }

        /* Literals */
        case (LIT_INT(?i)) { ret int::to_str(i, 10u); }
        case (LIT_UINT(?u)) { ret uint::to_str(u, 10u); }
        case (LIT_MACH_INT(?tm, ?i)) {
            ret  int::to_str(i, 10u)
                + "_" + ty_mach_to_str(tm);
        }
        case (LIT_MACH_FLOAT(?tm, ?s)) {
            ret interner::get[str](*r.get_interner(), s) + "_" +
                ty_mach_to_str(tm);
        }

        case (LIT_FLOAT(?s)) { ret interner::get[str](*r.get_interner(), s); }
        case (LIT_STR(?s)) {
            // FIXME: escape.
            ret "\"" + interner::get[str](*r.get_interner(), s) + "\"";
        }
        case (LIT_CHAR(?c)) {
            // FIXME: escape.
            auto tmp = "'";
            str::push_char(tmp, c);
            str::push_byte(tmp, '\'' as u8);
            ret tmp;
        }

        case (LIT_BOOL(?b)) {
            if (b) { ret "true"; } else { ret "false"; }
        }

        /* Name components */
        case (IDENT(?s, _)) { ret interner::get[str](*r.get_interner(), s); }
        case (IDX(?i)) { ret "_" + int::to_str(i, 10u); }
        case (UNDERSCORE) { ret "_"; }

        case (BRACEQUOTE(_)) { ret "<bracequote>"; }
        case (EOF) { ret "<eof>"; }
    }
}

// Local Variables:
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Pretty print the new RECV token...<commit_after>import util::common::ty_mach;
import util::common::ty_mach_to_str;
import util::common::new_str_hash;
import util::data::interner;
import std::int;
import std::uint;
import std::str;

type str_num = uint;

tag binop {
    PLUS;
    MINUS;
    STAR;
    SLASH;
    PERCENT;
    CARET;
    AND;
    OR;
    LSL;
    LSR;
    ASR;
}

tag token {
    /* Expression-operator symbols. */
    EQ;
    LT;
    LE;
    EQEQ;
    NE;
    GE;
    GT;
    ANDAND;
    OROR;
    NOT;
    TILDE;

    BINOP(binop);
    BINOPEQ(binop);

    /* Structural symbols */
    AT;
    DOT;
    COMMA;
    SEMI;
    COLON;
    MOD_SEP;
    QUES;
    RARROW;
    SEND;
    RECV;
    LARROW;
    LPAREN;
    RPAREN;
    LBRACKET;
    RBRACKET;
    LBRACE;
    RBRACE;

    POUND;

    /* Literals */
    LIT_INT(int);
    LIT_UINT(uint);
    LIT_MACH_INT(ty_mach, int);
    LIT_FLOAT(str_num);
    LIT_MACH_FLOAT(ty_mach, str_num);
    LIT_STR(str_num);
    LIT_CHAR(char);
    LIT_BOOL(bool);

    /* Name components */
    IDENT(str_num, bool);
    IDX(int);
    UNDERSCORE;

    BRACEQUOTE(str_num);
    EOF;
}

fn binop_to_str(binop o) -> str {
    alt (o) {
        case (PLUS) { ret "+"; }
        case (MINUS) { ret "-"; }
        case (STAR) { ret "*"; }
        case (SLASH) { ret "/"; }
        case (PERCENT) { ret "%"; }
        case (CARET) { ret "^"; }
        case (AND) { ret "&"; }
        case (OR) { ret "|"; }
        case (LSL) { ret "<<"; }
        case (LSR) { ret ">>"; }
        case (ASR) { ret ">>>"; }
    }
}

fn to_str(lexer::reader r, token t) -> str {
    alt (t) {

        case (EQ) { ret "="; }
        case (LT) { ret "<"; }
        case (LE) { ret "<="; }
        case (EQEQ) { ret "=="; }
        case (NE) { ret "!="; }
        case (GE) { ret ">="; }
        case (GT) { ret ">"; }
        case (NOT) { ret "!"; }
        case (TILDE) { ret "~"; }
        case (OROR) { ret "||"; }
        case (ANDAND) { ret "&&"; }

        case (BINOP(?op)) { ret binop_to_str(op); }
        case (BINOPEQ(?op)) { ret binop_to_str(op) + "="; }

        /* Structural symbols */
        case (AT) { ret "@"; }
        case (DOT) { ret "."; }
        case (COMMA) { ret ","; }
        case (SEMI) { ret ";"; }
        case (COLON) { ret ":"; }
        case (MOD_SEP) { ret "::"; }
        case (QUES) { ret "?"; }
        case (RARROW) { ret "->"; }
        case (SEND) { ret "<|"; }
        case (RECV) { ret "<|"; }
        case (LARROW) { ret "<-"; }
        case (LPAREN) { ret "("; }
        case (RPAREN) { ret ")"; }
        case (LBRACKET) { ret "["; }
        case (RBRACKET) { ret "]"; }
        case (LBRACE) { ret "{"; }
        case (RBRACE) { ret "}"; }

        case (POUND) { ret "#"; }

        /* Literals */
        case (LIT_INT(?i)) { ret int::to_str(i, 10u); }
        case (LIT_UINT(?u)) { ret uint::to_str(u, 10u); }
        case (LIT_MACH_INT(?tm, ?i)) {
            ret  int::to_str(i, 10u)
                + "_" + ty_mach_to_str(tm);
        }
        case (LIT_MACH_FLOAT(?tm, ?s)) {
            ret interner::get[str](*r.get_interner(), s) + "_" +
                ty_mach_to_str(tm);
        }

        case (LIT_FLOAT(?s)) { ret interner::get[str](*r.get_interner(), s); }
        case (LIT_STR(?s)) {
            // FIXME: escape.
            ret "\"" + interner::get[str](*r.get_interner(), s) + "\"";
        }
        case (LIT_CHAR(?c)) {
            // FIXME: escape.
            auto tmp = "'";
            str::push_char(tmp, c);
            str::push_byte(tmp, '\'' as u8);
            ret tmp;
        }

        case (LIT_BOOL(?b)) {
            if (b) { ret "true"; } else { ret "false"; }
        }

        /* Name components */
        case (IDENT(?s, _)) { ret interner::get[str](*r.get_interner(), s); }
        case (IDX(?i)) { ret "_" + int::to_str(i, 10u); }
        case (UNDERSCORE) { ret "_"; }

        case (BRACEQUOTE(_)) { ret "<bracequote>"; }
        case (EOF) { ret "<eof>"; }
    }
}

// Local Variables:
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>use std::collections::hash_set::HashSet;
use std::iter::FromIterator;

use api::server_data::ServerData;
use api::result::*;
use web::data::APIGeneSummary;

use types::GeneUniquename;

#[derive(Serialize, Deserialize, Eq, PartialEq, Clone)]
pub enum IntRangeType {
#[serde(rename = "genome_range_contains")]
    GenomeRangeContains,
#[serde(rename = "protein_length")]
    ProteinLength,
}

#[derive(Serialize, Deserialize, Eq, PartialEq, Clone)]
pub enum FloatRangeType {
#[serde(rename = "protein_mol_weight")]
    ProteinMolWeight,
}

#[derive(Serialize, Deserialize, Clone)]
pub enum QueryNode {
#[serde(rename = "or")]
    Or(Vec<QueryNode>),
#[serde(rename = "and")]
    And(Vec<QueryNode>),
#[serde(rename = "not")]
    Not(Box<QueryNode>, Box<QueryNode>),
#[serde(rename = "termid")]
    TermId(String),
#[serde(rename = "subset")]
    Subset(String),
#[serde(rename = "gene_list")]
    GeneList(Vec<GeneUniquename>),
#[serde(rename = "int_range")]
    IntRange(IntRangeType, u64, u64),
#[serde(rename = "float_range")]
    FloatRange(FloatRangeType, f64, f64),
}

fn exec_or(server_data: &ServerData, nodes: &Vec<QueryNode>) -> Result {
    if nodes.len() == 0 {
        return Result {
            status: ResultStatus::Error("illegal query: OR operator has no nodes".into()),
            rows: vec![],
        }
    }

    let mut seen_genes = HashSet::new();
    let mut or_rows = vec![];

    for node in nodes {
        let node_result = node.exec(server_data);
        if node_result.status != ResultStatus::Ok {
            return Result {
                status: node_result.status,
                rows: vec![],
            }
        }
        for node_row in &node_result.rows {
            if !seen_genes.contains(&node_row.gene_uniquename) {
                or_rows.push(ResultRow {
                    gene_uniquename: node_row.gene_uniquename.clone(),
                });
                seen_genes.insert(node_row.gene_uniquename.clone());
            }
        }
    }
    Result {
        status: ResultStatus::Ok,
        rows: or_rows
    }
}

fn exec_and(server_data: &ServerData, nodes: &Vec<QueryNode>) -> Result {
    if nodes.len() == 0 {
        return Result {
            status: ResultStatus::Error("illegal query: AND operator has no nodes".into()),
            rows: vec![],
        };
    }

    let first_node_result = nodes[0].exec(server_data);

    if first_node_result.status != ResultStatus::Ok {
        return Result {
            status: first_node_result.status,
            rows: vec![],
        };
    }

    let current_genes =
        first_node_result.rows.into_iter().map(|row| row.gene_uniquename);

    let mut current_gene_set =
        HashSet::from_iter(current_genes);

    for node in nodes[1..].iter() {
        let node_result = node.exec(server_data);
        if node_result.status != ResultStatus::Ok {
            return Result {
                status: node_result.status,
                rows: vec![],
            }
        }

        let node_genes =
            node_result.rows.into_iter().map(|row| row.gene_uniquename)
            .collect::<HashSet<_>>();

        current_gene_set = current_gene_set.intersection(&node_genes).cloned().collect();
    }
    Result {
        status: ResultStatus::Ok,
        rows: current_gene_set.iter().map(|gene_uniquename| ResultRow {
            gene_uniquename: gene_uniquename.clone()
        }).collect(),
    }
}

fn exec_not(server_data: &ServerData, node_a: &QueryNode, node_b: &QueryNode) -> Result {
    let node_b_result = node_b.exec(server_data);
    if node_b_result.status != ResultStatus::Ok {
        return Result {
            status: node_b_result.status,
            rows: vec![],
        }
    }

    let node_b_gene_set: HashSet<GeneUniquename> =
        HashSet::from_iter(node_b_result.rows.into_iter().map(|row| row.gene_uniquename));

    let node_a_result = node_a.exec(server_data);
    if node_a_result.status != ResultStatus::Ok {
        return Result {
            status: node_a_result.status,
            rows: vec![],
        }
    }

    let mut not_rows = vec![];

    for row in &node_a_result.rows {
        if !node_b_gene_set.contains(&row.gene_uniquename) {
            not_rows.push(ResultRow {
                gene_uniquename: row.gene_uniquename.clone(),
            });
        }
    }
    Result {
        status: ResultStatus::Ok,
        rows: not_rows,
    }
}

fn results_from_gene_vec(genes: Vec<GeneUniquename>) -> Result {
    Result {
        status: ResultStatus::Ok,
        rows: genes.into_iter()
            .map(|gene_uniquename| ResultRow {
                gene_uniquename: gene_uniquename,
            }).collect::<Vec<_>>()
    }
}

fn exec_termid(server_data: &ServerData, term_id: &str) -> Result {
    results_from_gene_vec(server_data.genes_of_termid(term_id))
}

fn exec_subset(server_data: &ServerData, subset_name: &str) -> Result {
    results_from_gene_vec(server_data.genes_of_subset(subset_name))
}

fn exec_gene_list(gene_uniquenames: &Vec<GeneUniquename>) -> Result {
    results_from_gene_vec(gene_uniquenames.clone())
}

fn exec_genome_range_overlaps(server_data: &ServerData, range_start: u64, range_end: u64)
                              -> Result
{
    let gene_uniquenames =
        server_data.filter_genes(&|gene: &APIGeneSummary| {
            if let Some(ref location) = gene.location {
                location.start_pos as u64 <= range_end &&
                    location.end_pos as u64 >= range_start
            } else {
                false
            }
        });
    results_from_gene_vec(gene_uniquenames)
}

fn exec_protein_length_range(server_data: &ServerData, range_start: u64, range_end: u64)
                             -> Result
{
    let gene_uniquenames =
        server_data.filter_genes(&|gene: &APIGeneSummary| {
            if gene.transcripts.len() > 0 {
                if let Some(ref protein) = gene.transcripts[0].protein {
                    protein.sequence.len() as u64 >= range_start &&
                        protein.sequence.len() as u64 <= range_end
                } else {
                    false
                }
            } else {
                false
            }
        });
    results_from_gene_vec(gene_uniquenames)
}

fn exec_int_range(server_data: &ServerData, range_type: &IntRangeType,
                  start: u64, end: u64) -> Result {
    match *range_type {
        IntRangeType::GenomeRangeContains => exec_genome_range_overlaps(server_data, start, end),
        IntRangeType::ProteinLength => exec_protein_length_range(server_data, start, end),
    }
}

fn exec_mol_weight_range(server_data: &ServerData, range_start: f64, range_end: f64) -> Result {
    let gene_uniquenames =
        server_data.filter_genes(&|gene: &APIGeneSummary| {
            if gene.transcripts.len() > 0 {
                if let Some(ref protein) = gene.transcripts[0].protein {
                    protein.molecular_weight as f64 >= range_start &&
                        protein.molecular_weight as f64 <= range_end
                } else {
                    false
                }
            } else {
                false
            }
        });
    results_from_gene_vec(gene_uniquenames)
}

fn exec_float_range(server_data: &ServerData, range_type: &FloatRangeType,
                    start: f64, end: f64) -> Result {
    match *range_type {
        FloatRangeType::ProteinMolWeight => exec_mol_weight_range(server_data, start, end)
    }
}

impl QueryNode {
    pub fn exec(&self, server_data: &ServerData) -> Result {
        use self::QueryNode::*;
        match *self {
            Or(ref nodes) => exec_or(server_data, nodes),
            And(ref nodes) => exec_and(server_data, nodes),
            Not(ref node_a, ref node_b) => exec_not(server_data, node_a, node_b),
            TermId(ref term_id) => exec_termid(server_data, term_id),
            Subset(ref subset_name) => exec_subset(server_data, subset_name),
            GeneList(ref gene_list) => exec_gene_list(gene_list),
            IntRange(ref range_type, start, end) =>
                exec_int_range(server_data, range_type, start, end),
            FloatRange(ref range_type, start, end) =>
                exec_float_range(server_data, range_type, start, end),
        }
    }
}

#[derive(Serialize, Deserialize)]
pub struct Query {
    constraints: QueryNode,
}

impl Query {
    pub fn from_node(node: QueryNode) -> Query {
        Query {
            constraints: node
        }
    }

    pub fn exec(&self, server_data: &ServerData) -> Result {
        self.constraints.exec(server_data)
    }
}
<commit_msg>Allow single ended query ranges<commit_after>use std::collections::hash_set::HashSet;
use std::iter::FromIterator;

use api::server_data::ServerData;
use api::result::*;
use web::data::APIGeneSummary;

use types::GeneUniquename;

#[derive(Serialize, Deserialize, Eq, PartialEq, Clone)]
pub enum IntRangeType {
#[serde(rename = "genome_range_contains")]
    GenomeRangeContains,
#[serde(rename = "protein_length")]
    ProteinLength,
}

#[derive(Serialize, Deserialize, Eq, PartialEq, Clone)]
pub enum FloatRangeType {
#[serde(rename = "protein_mol_weight")]
    ProteinMolWeight,
}

#[derive(Serialize, Deserialize, Clone)]
pub enum QueryNode {
#[serde(rename = "or")]
    Or(Vec<QueryNode>),
#[serde(rename = "and")]
    And(Vec<QueryNode>),
#[serde(rename = "not")]
    Not(Box<QueryNode>, Box<QueryNode>),
#[serde(rename = "termid")]
    TermId(String),
#[serde(rename = "subset")]
    Subset(String),
#[serde(rename = "gene_list")]
    GeneList(Vec<GeneUniquename>),
#[serde(rename = "int_range")]
    IntRange(IntRangeType, Option<u64>, Option<u64>),
#[serde(rename = "float_range")]
    FloatRange(FloatRangeType, Option<f64>, Option<f64>),
}

fn exec_or(server_data: &ServerData, nodes: &Vec<QueryNode>) -> Result {
    if nodes.len() == 0 {
        return Result {
            status: ResultStatus::Error("illegal query: OR operator has no nodes".into()),
            rows: vec![],
        }
    }

    let mut seen_genes = HashSet::new();
    let mut or_rows = vec![];

    for node in nodes {
        let node_result = node.exec(server_data);
        if node_result.status != ResultStatus::Ok {
            return Result {
                status: node_result.status,
                rows: vec![],
            }
        }
        for node_row in &node_result.rows {
            if !seen_genes.contains(&node_row.gene_uniquename) {
                or_rows.push(ResultRow {
                    gene_uniquename: node_row.gene_uniquename.clone(),
                });
                seen_genes.insert(node_row.gene_uniquename.clone());
            }
        }
    }
    Result {
        status: ResultStatus::Ok,
        rows: or_rows
    }
}

fn exec_and(server_data: &ServerData, nodes: &Vec<QueryNode>) -> Result {
    if nodes.len() == 0 {
        return Result {
            status: ResultStatus::Error("illegal query: AND operator has no nodes".into()),
            rows: vec![],
        };
    }

    let first_node_result = nodes[0].exec(server_data);

    if first_node_result.status != ResultStatus::Ok {
        return Result {
            status: first_node_result.status,
            rows: vec![],
        };
    }

    let current_genes =
        first_node_result.rows.into_iter().map(|row| row.gene_uniquename);

    let mut current_gene_set =
        HashSet::from_iter(current_genes);

    for node in nodes[1..].iter() {
        let node_result = node.exec(server_data);
        if node_result.status != ResultStatus::Ok {
            return Result {
                status: node_result.status,
                rows: vec![],
            }
        }

        let node_genes =
            node_result.rows.into_iter().map(|row| row.gene_uniquename)
            .collect::<HashSet<_>>();

        current_gene_set = current_gene_set.intersection(&node_genes).cloned().collect();
    }
    Result {
        status: ResultStatus::Ok,
        rows: current_gene_set.iter().map(|gene_uniquename| ResultRow {
            gene_uniquename: gene_uniquename.clone()
        }).collect(),
    }
}

fn exec_not(server_data: &ServerData, node_a: &QueryNode, node_b: &QueryNode) -> Result {
    let node_b_result = node_b.exec(server_data);
    if node_b_result.status != ResultStatus::Ok {
        return Result {
            status: node_b_result.status,
            rows: vec![],
        }
    }

    let node_b_gene_set: HashSet<GeneUniquename> =
        HashSet::from_iter(node_b_result.rows.into_iter().map(|row| row.gene_uniquename));

    let node_a_result = node_a.exec(server_data);
    if node_a_result.status != ResultStatus::Ok {
        return Result {
            status: node_a_result.status,
            rows: vec![],
        }
    }

    let mut not_rows = vec![];

    for row in &node_a_result.rows {
        if !node_b_gene_set.contains(&row.gene_uniquename) {
            not_rows.push(ResultRow {
                gene_uniquename: row.gene_uniquename.clone(),
            });
        }
    }
    Result {
        status: ResultStatus::Ok,
        rows: not_rows,
    }
}

fn results_from_gene_vec(genes: Vec<GeneUniquename>) -> Result {
    Result {
        status: ResultStatus::Ok,
        rows: genes.into_iter()
            .map(|gene_uniquename| ResultRow {
                gene_uniquename: gene_uniquename,
            }).collect::<Vec<_>>()
    }
}

fn exec_termid(server_data: &ServerData, term_id: &str) -> Result {
    results_from_gene_vec(server_data.genes_of_termid(term_id))
}

fn exec_subset(server_data: &ServerData, subset_name: &str) -> Result {
    results_from_gene_vec(server_data.genes_of_subset(subset_name))
}

fn exec_gene_list(gene_uniquenames: &Vec<GeneUniquename>) -> Result {
    results_from_gene_vec(gene_uniquenames.clone())
}

fn exec_genome_range_overlaps(server_data: &ServerData,
                              range_start: Option<u64>, range_end: Option<u64>)
                              -> Result
{
    let gene_uniquenames =
        server_data.filter_genes(&|gene: &APIGeneSummary| {
            if let Some(ref location) = gene.location {
                (range_end.is_none() || location.start_pos as u64 <= range_end.unwrap()) &&
                (range_start.is_none() || location.end_pos as u64 >= range_start.unwrap())
            } else {
                false
            }
        });
    results_from_gene_vec(gene_uniquenames)
}

fn exec_protein_length_range(server_data: &ServerData,
                             range_start: Option<u64>, range_end: Option<u64>)
                             -> Result
{
    let gene_uniquenames =
        server_data.filter_genes(&|gene: &APIGeneSummary| {
            if gene.transcripts.len() > 0 {
                if let Some(ref protein) = gene.transcripts[0].protein {
                    (range_start.is_none() || protein.sequence.len() as u64 >= range_start.unwrap()) &&
                    (range_end.is_none() || protein.sequence.len() as u64 <= range_end.unwrap())
                } else {
                    false
                }
            } else {
                false
            }
        });
    results_from_gene_vec(gene_uniquenames)
}

fn exec_int_range(server_data: &ServerData, range_type: &IntRangeType,
                  start: Option<u64>, end: Option<u64>) -> Result {
    match *range_type {
        IntRangeType::GenomeRangeContains => exec_genome_range_overlaps(server_data, start, end),
        IntRangeType::ProteinLength => exec_protein_length_range(server_data, start, end),
    }
}

fn exec_mol_weight_range(server_data: &ServerData, range_start: Option<f64>, range_end: Option<f64>)
                         -> Result
{
    let gene_uniquenames =
        server_data.filter_genes(&|gene: &APIGeneSummary| {
            if gene.transcripts.len() > 0 {
                if let Some(ref protein) = gene.transcripts[0].protein {
                    (range_start.is_none() ||
                        protein.molecular_weight as f64 >= range_start.unwrap()) &&
                    (range_end.is_none() ||
                        protein.molecular_weight as f64 <= range_end.unwrap())
                } else {
                    false
                }
            } else {
                false
            }
        });
    results_from_gene_vec(gene_uniquenames)
}

fn exec_float_range(server_data: &ServerData, range_type: &FloatRangeType,
                    start: Option<f64>, end: Option<f64>) -> Result {
    match *range_type {
        FloatRangeType::ProteinMolWeight => exec_mol_weight_range(server_data, start, end)
    }
}

impl QueryNode {
    pub fn exec(&self, server_data: &ServerData) -> Result {
        use self::QueryNode::*;
        match *self {
            Or(ref nodes) => exec_or(server_data, nodes),
            And(ref nodes) => exec_and(server_data, nodes),
            Not(ref node_a, ref node_b) => exec_not(server_data, node_a, node_b),
            TermId(ref term_id) => exec_termid(server_data, term_id),
            Subset(ref subset_name) => exec_subset(server_data, subset_name),
            GeneList(ref gene_list) => exec_gene_list(gene_list),
            IntRange(ref range_type, start, end) =>
                exec_int_range(server_data, range_type, start, end),
            FloatRange(ref range_type, start, end) =>
                exec_float_range(server_data, range_type, start, end),
        }
    }
}

#[derive(Serialize, Deserialize)]
pub struct Query {
    constraints: QueryNode,
}

impl Query {
    pub fn from_node(node: QueryNode) -> Query {
        Query {
            constraints: node
        }
    }

    pub fn exec(&self, server_data: &ServerData) -> Result {
        self.constraints.exec(server_data)
    }
}
<|endoftext|>