<commit_before>//! An example that uses CPUID to determine the system topology.
//!
//! Intel Topology is a pretty complicated subject (unfortunately):
//! https://software.intel.com/en-us/articles/intel-64-architecture-processor-topology-enumeration/
extern crate core_affinity;
extern crate raw_cpuid;

use raw_cpuid::{CpuId, ExtendedTopologyLevel, TopologyType};
use std::thread;
use std::convert::TryInto;

/// Runs CPU ID on every core in the system (to gather all APIC IDs).
///
/// # Note
/// This won't work on macOS, apparently there is no guarantee after setting the affinity
/// that a thread will really execute on the pinned core.
fn gather_all_xapic_ids() -> Vec<u8> {
    let core_ids = core_affinity::get_core_ids().unwrap();

    // Create a thread for each active CPU core.
    core_ids
        .into_iter()
        .map(|id| {
            thread::spawn(move || {
                // Pin this thread to a single CPU core.
                core_affinity::set_for_current(id);
                // Do more work after this.
                let cpuid = CpuId::new();
                cpuid
                    .get_feature_info()
                    .map_or_else(|| 0, |finfo| finfo.initial_local_apic_id())
            })
            .join()
            .unwrap_or(0)
        })
        .collect::<Vec<_>>()
}

/// Runs CPU ID on every core in the system (to gather all x2APIC IDs).
///
/// # Note
/// This won't work on macOS, apparently there is no guarantee after setting the affinity
/// that a thread will really execute on the pinned core.
fn gather_all_x2apic_ids() -> Vec<u32> {
    let core_ids = core_affinity::get_core_ids().unwrap();

    // Create a thread for each active CPU core.
    core_ids
        .into_iter()
        .map(|id| {
            thread::spawn(move || {
                // Pin this thread to a single CPU core.
                core_affinity::set_for_current(id);
                // Do more work after this.
                let cpuid = CpuId::new();
                cpuid.get_extended_topology_info().map_or_else(
                    || 0,
                    |mut topiter| topiter.next().as_ref().unwrap().x2apic_id(),
                )
            })
            .join()
            .unwrap_or(0)
        })
        .collect::<Vec<_>>()
}

fn enumerate_with_x2apic_ids() {
    let cpuid = CpuId::new();
    let mut smt_x2apic_shift: u32 = 0;
    let mut core_x2apic_shift: u32 = 0;

    cpuid.get_extended_topology_info().map_or_else(
        || println!("No topology information available."),
        |topoiter| {
            let topology: Vec<ExtendedTopologyLevel> = topoiter.collect();
            for topolevel in topology.iter() {
                match topolevel.level_type() {
                    TopologyType::SMT => {
                        smt_x2apic_shift = topolevel.shift_right_for_next_apic_id();
                    }
                    TopologyType::Core => {
                        core_x2apic_shift = topolevel.shift_right_for_next_apic_id();
                    }
                    _ => panic!("Topology category not supported."),
                };
            }
        },
    );

    println!("Enumeration of all cores in the system (with x2APIC IDs):");
    let mut all_x2apic_ids: Vec<u32> = gather_all_x2apic_ids();
    all_x2apic_ids.sort_unstable();
    for x2apic_id in all_x2apic_ids {
        let smt_select_mask = !(u32::max_value() << smt_x2apic_shift);
        let core_select_mask = (!((u32::max_value()) << core_x2apic_shift)) ^ smt_select_mask;
        let pkg_select_mask = u32::max_value() << core_x2apic_shift;

        let smt_id = x2apic_id & smt_select_mask;
        let core_id = (x2apic_id & core_select_mask) >> smt_x2apic_shift;
        let pkg_id = (x2apic_id & pkg_select_mask) >> core_x2apic_shift;

        println!(
            "x2APIC#{} (pkg: {}, core: {}, smt: {})",
            x2apic_id, pkg_id, core_id, smt_id
        );
    }
}

fn cpuid_bits_needed(count: u8) -> u8 {
    let mut mask: u8 = 0x80;
    let mut cnt: u8 = 8;

    while (cnt > 0) && ((mask & count) != mask) {
        mask >>= 1;
        cnt -= 1;
    }

    cnt
}

fn get_processor_limits() -> (u8, u8) {
    let cpuid = CpuId::new();

    // This is for AMD processors:
    if let Some(info) = cpuid.get_processor_capacity_feature_info() {
        let max_logical_processor_ids = info.num_phys_threads();
        let smt_max_cores_for_package = info.apic_id_size();

        return (max_logical_processor_ids.try_into().unwrap(), smt_max_cores_for_package.try_into().unwrap());
    }
    // This is for Intel processors:
    else if let Some(cparams) = cpuid.get_cache_parameters() {
        let max_logical_processor_ids = cpuid
            .get_feature_info()
            .map_or_else(|| 1, |finfo| finfo.max_logical_processor_ids());

        let mut smt_max_cores_for_package: u8 = 1;
        for (ecx, cache) in cparams.enumerate() {
            if ecx == 0 {
                smt_max_cores_for_package = cache.max_cores_for_package() as u8;
            }
        }

        return (max_logical_processor_ids as u8, smt_max_cores_for_package as u8);
    }

    unreachable!("Example doesn't support this CPU")
}

fn enumerate_with_xapic_ids() {
    let (max_logical_processor_ids, smt_max_cores_for_package) = get_processor_limits();

    let smt_mask_width: u8 = cpuid_bits_needed(
        (max_logical_processor_ids.next_power_of_two() / smt_max_cores_for_package) - 1,
    );
    let smt_select_mask: u8 = !(u8::max_value() << smt_mask_width);
    let core_mask_width: u8 = cpuid_bits_needed(smt_max_cores_for_package - 1);
    let core_only_select_mask =
        (!(u8::max_value() << (core_mask_width + smt_mask_width))) ^ smt_select_mask;
    let pkg_select_mask = u8::max_value() << (core_mask_width + smt_mask_width);

    println!("Enumeration of all cores in the system (with APIC IDs):");
    let mut all_xapic_ids: Vec<u8> = gather_all_xapic_ids();
    all_xapic_ids.sort_unstable();

    for xapic_id in all_xapic_ids {
        let smt_id = xapic_id & smt_select_mask;
        let core_id = (xapic_id & core_only_select_mask) >> smt_mask_width;
        let pkg_id = (xapic_id & pkg_select_mask) >> (core_mask_width + smt_mask_width);

        println!(
            "APIC#{} (pkg: {}, core: {}, smt: {})",
            xapic_id, pkg_id, core_id, smt_id
        );
    }
}

fn main() {
    let cpuid = CpuId::new();

    cpuid.get_processor_brand_string().map_or_else(
        || println!("CPU model identifier not available."),
        |pbs| println!("CPU Model is: {}", pbs.as_str()),
    );
    cpuid.get_extended_topology_info().map_or_else(
        || println!("No topology information available."),
        |topoiter| {
            let mut topology: Vec<ExtendedTopologyLevel> = topoiter.collect();
            topology.reverse();

            for topolevel in topology.iter() {
                let typ = match topolevel.level_type() {
                    TopologyType::SMT => "SMT-threads",
                    TopologyType::Core => "cores",
                    _ => panic!("Topology category not supported."),
                };

                println!(
                    "At level {} the CPU has: {} {}",
                    topolevel.level_number(),
                    topolevel.processors(),
                    typ,
                );
            }
        },
    );

    println!();
    enumerate_with_xapic_ids();

    println!();
    enumerate_with_x2apic_ids();
}
<commit_msg>Formatting.<commit_after>//! An example that uses CPUID to determine the system topology.
//!
//! Intel Topology is a pretty complicated subject (unfortunately):
//! https://software.intel.com/en-us/articles/intel-64-architecture-processor-topology-enumeration/
extern crate core_affinity;
extern crate raw_cpuid;

use raw_cpuid::{CpuId, ExtendedTopologyLevel, TopologyType};
use std::convert::TryInto;
use std::thread;

/// Runs CPU ID on every core in the system (to gather all APIC IDs).
///
/// # Note
/// This won't work on macOS, apparently there is no guarantee after setting the affinity
/// that a thread will really execute on the pinned core.
fn gather_all_xapic_ids() -> Vec<u8> {
    let core_ids = core_affinity::get_core_ids().unwrap();

    // Create a thread for each active CPU core.
    core_ids
        .into_iter()
        .map(|id| {
            thread::spawn(move || {
                // Pin this thread to a single CPU core.
                core_affinity::set_for_current(id);
                // Do more work after this.
                let cpuid = CpuId::new();
                cpuid
                    .get_feature_info()
                    .map_or_else(|| 0, |finfo| finfo.initial_local_apic_id())
            })
            .join()
            .unwrap_or(0)
        })
        .collect::<Vec<_>>()
}

/// Runs CPU ID on every core in the system (to gather all x2APIC IDs).
///
/// # Note
/// This won't work on macOS, apparently there is no guarantee after setting the affinity
/// that a thread will really execute on the pinned core.
fn gather_all_x2apic_ids() -> Vec<u32> {
    let core_ids = core_affinity::get_core_ids().unwrap();

    // Create a thread for each active CPU core.
    core_ids
        .into_iter()
        .map(|id| {
            thread::spawn(move || {
                // Pin this thread to a single CPU core.
                core_affinity::set_for_current(id);
                // Do more work after this.
                let cpuid = CpuId::new();
                cpuid.get_extended_topology_info().map_or_else(
                    || 0,
                    |mut topiter| topiter.next().as_ref().unwrap().x2apic_id(),
                )
            })
            .join()
            .unwrap_or(0)
        })
        .collect::<Vec<_>>()
}

fn enumerate_with_x2apic_ids() {
    let cpuid = CpuId::new();
    let mut smt_x2apic_shift: u32 = 0;
    let mut core_x2apic_shift: u32 = 0;

    cpuid.get_extended_topology_info().map_or_else(
        || println!("No topology information available."),
        |topoiter| {
            let topology: Vec<ExtendedTopologyLevel> = topoiter.collect();
            for topolevel in topology.iter() {
                match topolevel.level_type() {
                    TopologyType::SMT => {
                        smt_x2apic_shift = topolevel.shift_right_for_next_apic_id();
                    }
                    TopologyType::Core => {
                        core_x2apic_shift = topolevel.shift_right_for_next_apic_id();
                    }
                    _ => panic!("Topology category not supported."),
                };
            }
        },
    );

    println!("Enumeration of all cores in the system (with x2APIC IDs):");
    let mut all_x2apic_ids: Vec<u32> = gather_all_x2apic_ids();
    all_x2apic_ids.sort_unstable();
    for x2apic_id in all_x2apic_ids {
        let smt_select_mask = !(u32::max_value() << smt_x2apic_shift);
        let core_select_mask = (!((u32::max_value()) << core_x2apic_shift)) ^ smt_select_mask;
        let pkg_select_mask = u32::max_value() << core_x2apic_shift;

        let smt_id = x2apic_id & smt_select_mask;
        let core_id = (x2apic_id & core_select_mask) >> smt_x2apic_shift;
        let pkg_id = (x2apic_id & pkg_select_mask) >> core_x2apic_shift;

        println!(
            "x2APIC#{} (pkg: {}, core: {}, smt: {})",
            x2apic_id, pkg_id, core_id, smt_id
        );
    }
}

fn cpuid_bits_needed(count: u8) -> u8 {
    let mut mask: u8 = 0x80;
    let mut cnt: u8 = 8;

    while (cnt > 0) && ((mask & count) != mask) {
        mask >>= 1;
        cnt -= 1;
    }

    cnt
}

fn get_processor_limits() -> (u8, u8) {
    let cpuid = CpuId::new();

    // This is for AMD processors:
    if let Some(info) = cpuid.get_processor_capacity_feature_info() {
        let max_logical_processor_ids = info.num_phys_threads();
        let smt_max_cores_for_package = info.apic_id_size();

        return (
            max_logical_processor_ids.try_into().unwrap(),
            smt_max_cores_for_package.try_into().unwrap(),
        );
    }
    // This is for Intel processors:
    else if let Some(cparams) = cpuid.get_cache_parameters() {
        let max_logical_processor_ids = cpuid
            .get_feature_info()
            .map_or_else(|| 1, |finfo| finfo.max_logical_processor_ids());

        let mut smt_max_cores_for_package: u8 = 1;
        for (ecx, cache) in cparams.enumerate() {
            if ecx == 0 {
                smt_max_cores_for_package = cache.max_cores_for_package() as u8;
            }
        }

        return (
            max_logical_processor_ids as u8,
            smt_max_cores_for_package as u8,
        );
    }

    unreachable!("Example doesn't support this CPU")
}

fn enumerate_with_xapic_ids() {
    let (max_logical_processor_ids, smt_max_cores_for_package) = get_processor_limits();

    let smt_mask_width: u8 = cpuid_bits_needed(
        (max_logical_processor_ids.next_power_of_two() / smt_max_cores_for_package) - 1,
    );
    let smt_select_mask: u8 = !(u8::max_value() << smt_mask_width);
    let core_mask_width: u8 = cpuid_bits_needed(smt_max_cores_for_package - 1);
    let core_only_select_mask =
        (!(u8::max_value() << (core_mask_width + smt_mask_width))) ^ smt_select_mask;
    let pkg_select_mask = u8::max_value() << (core_mask_width + smt_mask_width);

    println!("Enumeration of all cores in the system (with APIC IDs):");
    let mut all_xapic_ids: Vec<u8> = gather_all_xapic_ids();
    all_xapic_ids.sort_unstable();

    for xapic_id in all_xapic_ids {
        let smt_id = xapic_id & smt_select_mask;
        let core_id = (xapic_id & core_only_select_mask) >> smt_mask_width;
        let pkg_id = (xapic_id & pkg_select_mask) >> (core_mask_width + smt_mask_width);

        println!(
            "APIC#{} (pkg: {}, core: {}, smt: {})",
            xapic_id, pkg_id, core_id, smt_id
        );
    }
}

fn main() {
    let cpuid = CpuId::new();

    cpuid.get_processor_brand_string().map_or_else(
        || println!("CPU model identifier not available."),
        |pbs| println!("CPU Model is: {}", pbs.as_str()),
    );
    cpuid.get_extended_topology_info().map_or_else(
        || println!("No topology information available."),
        |topoiter| {
            let mut topology: Vec<ExtendedTopologyLevel> = topoiter.collect();
            topology.reverse();

            for topolevel in topology.iter() {
                let typ = match topolevel.level_type() {
                    TopologyType::SMT => "SMT-threads",
                    TopologyType::Core => "cores",
                    _ => panic!("Topology category not supported."),
                };

                println!(
                    "At level {} the CPU has: {} {}",
                    topolevel.level_number(),
                    topolevel.processors(),
                    typ,
                );
            }
        },
    );

    println!();
    enumerate_with_xapic_ids();

    println!();
    enumerate_with_x2apic_ids();
}
<|endoftext|>


<commit_before>extern crate wayland_scanner;

use std::env::var;
use std::path::Path;
use wayland_scanner::*;

static STABLE_PROTOCOLS: &[(&str, &[(&str, &str)])] = &[
    ("presentation-time", &[]),
    ("viewporter", &[]),
    ("xdg-shell", &[]),
];

static UNSTABLE_PROTOCOLS: &[(&str, &[(&str, &[(&str, &str)])])] = &[
    ("fullscreen-shell", &[("v1", &[])]),
    ("idle-inhibit", &[("v1", &[])]),
    ("input-method", &[("v1", &[])]),
    ("input-timestamps", &[("v1", &[])]),
    ("keyboard-shortcuts-inhibit", &[("v1", &[])]),
    ("linux-dmabuf", &[("v1", &[])]),
    (
        "linux-explicit-synchronization",
        &[(
            "v1",
            &[
                ("zwp_linux_buffer_release_v1", "fenced_release"),
                ("zwp_linux_buffer_release_v1", "immediate_release"),
            ],
        )],
    ),
    ("pointer-constraints", &[("v1", &[])]),
    ("pointer-gestures", &[("v1", &[])]),
    ("primary-selection", &[("v1", &[])]),
    ("relative-pointer", &[("v1", &[])]),
    ("tablet", &[("v1", &[]), ("v2", &[])]),
    ("text-input", &[("v1", &[]), ("v3", &[])]),
    ("xdg-decoration", &[("v1", &[])]),
    ("xdg-foreign", &[("v1", &[]), ("v2", &[])]),
    ("xdg-output", &[("v1", &[])]),
    ("xdg-shell", &[("v5", &[]), ("v6", &[])]),
    ("xwayland-keyboard-grab", &[("v1", &[])]),
];

static WLR_UNSTABLE_PROTOCOLS: &[(&str, &[(&str, &[(&str, &str)])])] = &[
    ("wlr-data-control", &[("v1", &[])]),
    ("wlr-export-dmabuf", &[("v1", &[])]),
    ("wlr-foreign-toplevel-management", &[("v1", &[])]),
    ("wlr-gamma-control", &[("v1", &[])]),
    ("wlr-input-inhibitor", &[("v1", &[])]),
    ("wlr-layer-shell", &[("v1", &[])]),
    ("wlr-screencopy", &[("v1", &[])]),
];

static MISC_PROTOCOLS: &[(&str, &[(&str, &str)])] = &[("gtk-primary-selection", &[])];

fn generate_protocol(
    name: &str,
    protocol_file: &Path,
    out_dir: &Path,
    client: bool,
    server: bool,
    dest_events: &[(&str, &str)],
) {
    println!("cargo:rerun-if-changed={}", protocol_file.display());

    if client {
        generate_code_with_destructor_events(
            &protocol_file,
            out_dir.join(&format!("{}_client_api.rs", name)),
            Side::Client,
            dest_events,
        );
    }
    if server {
        generate_code_with_destructor_events(
            &protocol_file,
            out_dir.join(&format!("{}_server_api.rs", name)),
            Side::Server,
            dest_events,
        );
    }
}

fn main() {
    println!("cargo:rerun-if-changed-env=CARGO_FEATURE_CLIENT");
    println!("cargo:rerun-if-changed-env=CARGO_FEATURE_SERVER");
    println!("cargo:rerun-if-changed-env=CARGO_FEATURE_UNSTABLE_PROTOCOLS");

    let out_dir_str = var("OUT_DIR").unwrap();
    let out_dir = Path::new(&out_dir_str);

    let client = var("CARGO_FEATURE_CLIENT").ok().is_some();
    let server = var("CARGO_FEATURE_SERVER").ok().is_some();

    for &(name, dest_events) in STABLE_PROTOCOLS {
        let file = format!("{name}/{name}.xml", name = name);
        generate_protocol(
            name,
            &Path::new("./protocols/stable").join(&file),
            out_dir,
            client,
            server,
            dest_events,
        );
    }

    for &(name, dest_events) in MISC_PROTOCOLS {
        let file = format!("{name}.xml", name = name);
        generate_protocol(
            name,
            &Path::new("./misc").join(&file),
            out_dir,
            client,
            server,
            dest_events,
        );
    }

    if var("CARGO_FEATURE_UNSTABLE_PROTOCOLS").ok().is_some() {
        for &(name, versions) in UNSTABLE_PROTOCOLS {
            for &(version, dest_events) in versions {
                let file = format!(
                    "{name}/{name}-unstable-{version}.xml",
                    name = name,
                    version = version
                );
                generate_protocol(
                    &format!("{name}-{version}", name = name, version = version),
                    &Path::new("./protocols/unstable").join(file),
                    out_dir,
                    client,
                    server,
                    dest_events,
                );
            }
        }
        for &(name, versions) in WLR_UNSTABLE_PROTOCOLS {
            for &(version, dest_events) in versions {
                let file = format!("{name}-unstable-{version}.xml", name = name, version = version);
                generate_protocol(
                    &format!("{name}-{version}", name = name, version = version),
                    &Path::new("./wlr-protocols/unstable").join(file),
                    out_dir,
                    client,
                    server,
                    dest_events,
                );
            }
        }
    }
}
<commit_msg>fix clippy warning<commit_after>extern crate wayland_scanner;

use std::env::var;
use std::path::Path;
use wayland_scanner::*;

type StableProtocol<'a> = (&'a str, &'a [(&'a str, &'a str)]);
type UnstableProtocol<'a> = (&'a str, &'a [(&'a str, &'a [(&'a str, &'a str)])]);

static STABLE_PROTOCOLS: &[StableProtocol] = &[
    ("presentation-time", &[]),
    ("viewporter", &[]),
    ("xdg-shell", &[]),
];

static UNSTABLE_PROTOCOLS: &[UnstableProtocol] = &[
    ("fullscreen-shell", &[("v1", &[])]),
    ("idle-inhibit", &[("v1", &[])]),
    ("input-method", &[("v1", &[])]),
    ("input-timestamps", &[("v1", &[])]),
    ("keyboard-shortcuts-inhibit", &[("v1", &[])]),
    ("linux-dmabuf", &[("v1", &[])]),
    (
        "linux-explicit-synchronization",
        &[(
            "v1",
            &[
                ("zwp_linux_buffer_release_v1", "fenced_release"),
                ("zwp_linux_buffer_release_v1", "immediate_release"),
            ],
        )],
    ),
    ("pointer-constraints", &[("v1", &[])]),
    ("pointer-gestures", &[("v1", &[])]),
    ("primary-selection", &[("v1", &[])]),
    ("relative-pointer", &[("v1", &[])]),
    ("tablet", &[("v1", &[]), ("v2", &[])]),
    ("text-input", &[("v1", &[]), ("v3", &[])]),
    ("xdg-decoration", &[("v1", &[])]),
    ("xdg-foreign", &[("v1", &[]), ("v2", &[])]),
    ("xdg-output", &[("v1", &[])]),
    ("xdg-shell", &[("v5", &[]), ("v6", &[])]),
    ("xwayland-keyboard-grab", &[("v1", &[])]),
];

static WLR_UNSTABLE_PROTOCOLS: &[UnstableProtocol] = &[
    ("wlr-data-control", &[("v1", &[])]),
    ("wlr-export-dmabuf", &[("v1", &[])]),
    ("wlr-foreign-toplevel-management", &[("v1", &[])]),
    ("wlr-gamma-control", &[("v1", &[])]),
    ("wlr-input-inhibitor", &[("v1", &[])]),
    ("wlr-layer-shell", &[("v1", &[])]),
    ("wlr-screencopy", &[("v1", &[])]),
];

static MISC_PROTOCOLS: &[StableProtocol] = &[("gtk-primary-selection", &[])];

fn generate_protocol(
    name: &str,
    protocol_file: &Path,
    out_dir: &Path,
    client: bool,
    server: bool,
    dest_events: &[(&str, &str)],
) {
    println!("cargo:rerun-if-changed={}", protocol_file.display());

    if client {
        generate_code_with_destructor_events(
            &protocol_file,
            out_dir.join(&format!("{}_client_api.rs", name)),
            Side::Client,
            dest_events,
        );
    }
    if server {
        generate_code_with_destructor_events(
            &protocol_file,
            out_dir.join(&format!("{}_server_api.rs", name)),
            Side::Server,
            dest_events,
        );
    }
}

fn main() {
    println!("cargo:rerun-if-changed-env=CARGO_FEATURE_CLIENT");
    println!("cargo:rerun-if-changed-env=CARGO_FEATURE_SERVER");
    println!("cargo:rerun-if-changed-env=CARGO_FEATURE_UNSTABLE_PROTOCOLS");

    let out_dir_str = var("OUT_DIR").unwrap();
    let out_dir = Path::new(&out_dir_str);

    let client = var("CARGO_FEATURE_CLIENT").ok().is_some();
    let server = var("CARGO_FEATURE_SERVER").ok().is_some();

    for &(name, dest_events) in STABLE_PROTOCOLS {
        let file = format!("{name}/{name}.xml", name = name);
        generate_protocol(
            name,
            &Path::new("./protocols/stable").join(&file),
            out_dir,
            client,
            server,
            dest_events,
        );
    }

    for &(name, dest_events) in MISC_PROTOCOLS {
        let file = format!("{name}.xml", name = name);
        generate_protocol(
            name,
            &Path::new("./misc").join(&file),
            out_dir,
            client,
            server,
            dest_events,
        );
    }

    if var("CARGO_FEATURE_UNSTABLE_PROTOCOLS").ok().is_some() {
        for &(name, versions) in UNSTABLE_PROTOCOLS {
            for &(version, dest_events) in versions {
                let file = format!(
                    "{name}/{name}-unstable-{version}.xml",
                    name = name,
                    version = version
                );
                generate_protocol(
                    &format!("{name}-{version}", name = name, version = version),
                    &Path::new("./protocols/unstable").join(file),
                    out_dir,
                    client,
                    server,
                    dest_events,
                );
            }
        }
        for &(name, versions) in WLR_UNSTABLE_PROTOCOLS {
            for &(version, dest_events) in versions {
                let file = format!("{name}-unstable-{version}.xml", name = name, version = version);
                generate_protocol(
                    &format!("{name}-{version}", name = name, version = version),
                    &Path::new("./wlr-protocols/unstable").join(file),
                    out_dir,
                    client,
                    server,
                    dest_events,
                );
            }
        }
    }
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Linear_congruential_generator

trait LinearCongruentialGenerator {
    fn new(seed: u32) -> Self;
    fn seed(&mut self, seed: u32);
    fn next(&mut self) -> u32;
}

struct BSDLinearCongruentialGenerator {
    state: u32
}

impl LinearCongruentialGenerator for BSDLinearCongruentialGenerator {
    fn new(seed: u32) -> BSDLinearCongruentialGenerator {
        BSDLinearCongruentialGenerator { state: seed }
    }

    fn seed(&mut self, seed: u32) {
        self.state = seed;
    }

    fn next(&mut self) -> u32 {
        self.state = (1103515245 * self.state + 12345) % (1 << 31);
        self.state
    }
}

struct MSLinearCongruentialGenerator {
    state: u32
}

impl LinearCongruentialGenerator for MSLinearCongruentialGenerator {
    fn new(seed: u32) -> MSLinearCongruentialGenerator {
        MSLinearCongruentialGenerator { state: seed }
    }

    fn seed(&mut self, seed: u32) {
        self.state = seed;
    }

    fn next(&mut self) -> u32 {
        self.state = (214013 * self.state + 2531011) % (1 << 31);
        self.state >> 16
    }
}

#[cfg(not(test))]
fn main() {
    let mut bsd: BSDLinearCongruentialGenerator = LinearCongruentialGenerator::new(0);
    let mut ms: MSLinearCongruentialGenerator = LinearCongruentialGenerator::new(0);
    let names = ["BSD", "Microsoft"];
    let mut lcgs: [&mut LinearCongruentialGenerator, ..2] = [&mut bsd, &mut ms];
    for (name, lcg) in names.iter().zip(lcgs.iter_mut()) {
        println!("{}", name)
        for _ in range(0i, 10) {
            let next: u32 = lcg.next();
            println!("{}", next);
        }
        println!("");
    }
}

#[cfg(test)]
mod test {
    use super::{LinearCongruentialGenerator, BSDLinearCongruentialGenerator, MSLinearCongruentialGenerator};

    #[test]
    fn bsd() {
        let values = [12345u32, 1406932606, 654583775, 1449466924, 229283573, 1109335178, 1051550459, 1293799192, 794471793, 551188310];
        let mut lcg: BSDLinearCongruentialGenerator = LinearCongruentialGenerator::new(0);
        for val in values.iter() {
            assert_eq!(lcg.next(), *val);
        }
    }

    #[test]
    fn ms() {
        let values = [38u32, 7719, 21238, 2437, 8855, 11797, 8365, 32285, 10450, 30612];
        let mut lcg: MSLinearCongruentialGenerator = LinearCongruentialGenerator::new(0);
        for val in values.iter() {
            assert_eq!(lcg.next(), *val);
        }

    }
}
<commit_msg>Fixed object safety error in LinearCongruentialGenerator trait<commit_after>// Implements http://rosettacode.org/wiki/Linear_congruential_generator

trait LinearCongruentialGenerator {
    fn seed(&mut self, seed: u32);
    fn next(&mut self) -> u32;
}

struct BSDLinearCongruentialGenerator {
    state: u32
}

impl BSDLinearCongruentialGenerator {
    fn new(seed: u32) -> BSDLinearCongruentialGenerator {
        BSDLinearCongruentialGenerator { state: seed }
    }
}

impl LinearCongruentialGenerator for BSDLinearCongruentialGenerator {
    fn seed(&mut self, seed: u32) {
        self.state = seed;
    }

    fn next(&mut self) -> u32 {
        self.state = (1103515245 * self.state + 12345) % (1 << 31);
        self.state
    }
}

struct MSLinearCongruentialGenerator {
    state: u32
}

impl MSLinearCongruentialGenerator {
    fn new(seed: u32) -> MSLinearCongruentialGenerator {
        MSLinearCongruentialGenerator { state: seed }
    }
}

impl LinearCongruentialGenerator for MSLinearCongruentialGenerator {
    fn seed(&mut self, seed: u32) {
        self.state = seed;
    }

    fn next(&mut self) -> u32 {
        self.state = (214013 * self.state + 2531011) % (1 << 31);
        self.state >> 16
    }
}

#[cfg(not(test))]
fn main() {
    let mut bsd = BSDLinearCongruentialGenerator::new(0);
    let mut ms = MSLinearCongruentialGenerator::new(0);
    let names = ["BSD", "Microsoft"];
    let mut lcgs: [&mut LinearCongruentialGenerator, ..2] = [&mut bsd, &mut ms];
    for (name, lcg) in names.iter().zip(lcgs.iter_mut()) {
        println!("{}", name)
        for _ in range(0i, 10) {
            let next: u32 = lcg.next();
            println!("{}", next);
        }
        println!("");
    }
}

#[cfg(test)]
mod test {
    use super::{LinearCongruentialGenerator, BSDLinearCongruentialGenerator, MSLinearCongruentialGenerator};

    #[test]
    fn bsd() {
        let values = [12345u32, 1406932606, 654583775, 1449466924, 229283573, 1109335178, 1051550459, 1293799192, 794471793, 551188310];
        let mut lcg = BSDLinearCongruentialGenerator::new(0);
        for val in values.iter() {
            assert_eq!(lcg.next(), *val);
        }
    }

    #[test]
    fn ms() {
        let values = [38u32, 7719, 21238, 2437, 8855, 11797, 8365, 32285, 10450, 30612];
        let mut lcg = MSLinearCongruentialGenerator::new(0);
        for val in values.iter() {
            assert_eq!(lcg.next(), *val);
        }

    }
}
<|endoftext|>


<commit_before>use std::{Vec, String, ToString};
use std::collections::{BTreeMap, VecDeque};

use super::dvaddr::DVAddr;
use super::zio;

/// MRU - Most Recently Used cache
struct Mru {
    map: BTreeMap<DVAddr, Vec<u8>>,
    queue: VecDeque<DVAddr>, // Oldest DVAddrs are at the end
    size: usize, // Max mru cache size in blocks
    used: usize, // Number of used blocks in mru cache
}

impl Mru {
    pub fn new() -> Self {
        Mru {
            map: BTreeMap::new(),
            queue: VecDeque::new(),
            size: 1000,
            used: 0,
        }
    }

    pub fn cache_block(&mut self, dva: &DVAddr, block: Vec<u8>) -> Result<Vec<u8>, String> {
        // If necessary, make room for the block in the cache
        while self.used + (dva.asize() as usize) > self.size {
            let last_dva = match self.queue.pop_back() {
                Some(dva) => dva,
                None => return Err("No more ARC MRU items to free".to_string()),
            };
            self.map.remove(&last_dva);
            self.used -= last_dva.asize() as usize;
        }

        // Add the block to the cache
        self.used += dva.asize() as usize;
        self.map.insert(*dva, block);
        self.queue.push_front(*dva);
        Ok(self.map.get(dva).unwrap().clone())
    }
}

/// MFU - Most Frequently Used cache
struct Mfu {
    // TODO: Keep track of use counts. So mfu_map becomes (use_count: u64, Vec<u8>). Reset the use
    // count every once in a while. For instance, every 1000 reads. This will probably end up being
    // a knob for the user.
    // TODO: Keep track of minimum frequency and corresponding DVA
    map: BTreeMap<DVAddr, (u64, Vec<u8>)>,
    size: usize, // Max mfu cache size in blocks
    used: usize, // Number of used bytes in mfu cache
}

impl Mfu {
    pub fn new() -> Self {
        Mfu {
            map: BTreeMap::new(),
            size: 1000,
            used: 0,
        }
    }

    pub fn cache_block(&mut self, dva: &DVAddr, block: Vec<u8>) -> Result<Vec<u8>, String> {
        {
            let mut lowest_freq = 0;
            let mut lowest_dva: Result<DVAddr, String> = Err("No valid DVA found.".to_string());

            for (&dva_key, &(freq, _)) in self.map.iter() {
                if freq < lowest_freq {
                    lowest_freq = freq;
                    lowest_dva = Ok(dva_key);
                }
            }

            self.map.remove(&try!(lowest_dva));
        }

        // Add the block to the cache
        self.used += dva.asize() as usize;
        self.map.insert(*dva, (1, block));
        Ok(self.map.get(dva).unwrap().1.clone())
    }
}

// Our implementation of the Adaptive Replacement Cache (ARC) is set up to allocate
// its buffer on the heap rather than in a private pool thing. This makes it much
// simpler to implement, but defers the fragmentation problem to the heap allocator.
// We named the type `ArCache` to avoid confusion with Rust's `Arc` reference type.
pub struct ArCache {
    mru: Mru,
    mfu: Mfu,
}

impl ArCache {
    pub fn new() -> Self {
        ArCache {
            mru: Mru::new(),
            mfu: Mfu::new(),
        }
    }

    pub fn read(&mut self, reader: &mut zio::Reader, dva: &DVAddr) -> Result<Vec<u8>, String> {
        if let Some(block) = self.mru.map.remove(dva) {
            self.mfu.map.insert(*dva, (0, block.clone()));

            // Block is cached
            return Ok(block);
        }
        if let Some(block) = self.mfu.map.get_mut(dva) {
            // Block is cached
            if block.0 > 1000 {
                block.0 = 0;
            } else {
                block.0 += 1;
            }

            return Ok(block.1.clone());
        }

        // Block isn't cached, have to read it from disk
        let block = reader.read(dva.sector() as usize, dva.asize() as usize);

        // Blocks start in MRU cache
        self.mru.cache_block(dva, block)
    }
}
<commit_msg>Have the lowest frequency binding start at the highest possible value<commit_after>use std::{Vec, String, ToString};
use std::collections::{BTreeMap, VecDeque};

use super::dvaddr::DVAddr;
use super::zio;

/// MRU - Most Recently Used cache
struct Mru {
    map: BTreeMap<DVAddr, Vec<u8>>,
    queue: VecDeque<DVAddr>, // Oldest DVAddrs are at the end
    size: usize, // Max mru cache size in blocks
    used: usize, // Number of used blocks in mru cache
}

impl Mru {
    pub fn new() -> Self {
        Mru {
            map: BTreeMap::new(),
            queue: VecDeque::new(),
            size: 1000,
            used: 0,
        }
    }

    pub fn cache_block(&mut self, dva: &DVAddr, block: Vec<u8>) -> Result<Vec<u8>, String> {
        // If necessary, make room for the block in the cache
        while self.used + (dva.asize() as usize) > self.size {
            let last_dva = match self.queue.pop_back() {
                Some(dva) => dva,
                None => return Err("No more ARC MRU items to free".to_string()),
            };
            self.map.remove(&last_dva);
            self.used -= last_dva.asize() as usize;
        }

        // Add the block to the cache
        self.used += dva.asize() as usize;
        self.map.insert(*dva, block);
        self.queue.push_front(*dva);
        Ok(self.map.get(dva).unwrap().clone())
    }
}

/// MFU - Most Frequently Used cache
struct Mfu {
    // TODO: Keep track of use counts. So mfu_map becomes (use_count: u64, Vec<u8>). Reset the use
    // count every once in a while. For instance, every 1000 reads. This will probably end up being
    // a knob for the user.
    // TODO: Keep track of minimum frequency and corresponding DVA
    map: BTreeMap<DVAddr, (u64, Vec<u8>)>,
    size: usize, // Max mfu cache size in blocks
    used: usize, // Number of used bytes in mfu cache
}

impl Mfu {
    pub fn new() -> Self {
        Mfu {
            map: BTreeMap::new(),
            size: 1000,
            used: 0,
        }
    }

    pub fn cache_block(&mut self, dva: &DVAddr, block: Vec<u8>) -> Result<Vec<u8>, String> {
        {
            let mut lowest_freq = ::std::u64::MAX;
            let mut lowest_dva: Result<DVAddr, String> = Err("No valid DVA found.".to_string());

            for (&dva_key, &(freq, _)) in self.map.iter() {
                if freq < lowest_freq {
                    lowest_freq = freq;
                    lowest_dva = Ok(dva_key);
                }
            }

            self.map.remove(&try!(lowest_dva));
        }

        // Add the block to the cache
        self.used += dva.asize() as usize;
        self.map.insert(*dva, (1, block));
        Ok(self.map.get(dva).unwrap().1.clone())
    }
}

// Our implementation of the Adaptive Replacement Cache (ARC) is set up to allocate
// its buffer on the heap rather than in a private pool thing. This makes it much
// simpler to implement, but defers the fragmentation problem to the heap allocator.
// We named the type `ArCache` to avoid confusion with Rust's `Arc` reference type.
pub struct ArCache {
    mru: Mru,
    mfu: Mfu,
}

impl ArCache {
    pub fn new() -> Self {
        ArCache {
            mru: Mru::new(),
            mfu: Mfu::new(),
        }
    }

    pub fn read(&mut self, reader: &mut zio::Reader, dva: &DVAddr) -> Result<Vec<u8>, String> {
        if let Some(block) = self.mru.map.remove(dva) {
            self.mfu.map.insert(*dva, (0, block.clone()));

            // Block is cached
            return Ok(block);
        }
        if let Some(block) = self.mfu.map.get_mut(dva) {
            // Block is cached
            if block.0 > 1000 {
                block.0 = 0;
            } else {
                block.0 += 1;
            }

            return Ok(block.1.clone());
        }

        // Block isn't cached, have to read it from disk
        let block = reader.read(dva.sector() as usize, dva.asize() as usize);

        // Blocks start in MRU cache
        self.mru.cache_block(dva, block)
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

use std::cell::RefCell;
use std::ops::Deref;
use std::rc::Rc;

use gtk::{
    CellRendererText,
    IsA,
    ListStore,
    TreeIter,
    TreeModel,
    TreeModelExt,
    TreeSelection,
    TreeView,
    TreeViewColumn,
    Type,
    WidgetExt,
};

use super::Completer;

/// A widget to show completions for the command entry.
pub struct CompletionView {
    unselect_callback: RefCell<Option<Box<Fn()>>>,
    view: TreeView,
}

impl CompletionView {
    /// Create a new completion view.
    pub fn new() -> Rc<Self> {
        let tree_view = TreeView::new();

        let column1 = TreeViewColumn::new();
        let cell1 = CellRendererText::new();
        column1.pack_start(&cell1, true);
        column1.add_attribute(&cell1, "text", 0);
        tree_view.append_column(&column1);

        let column2 = TreeViewColumn::new();
        let cell2 = CellRendererText::new();
        column2.pack_start(&cell2, true);
        column2.add_attribute(&cell2, "text", 1);
        tree_view.append_column(&column2);

        tree_view.get_selection().unselect_all();
        tree_view.set_enable_search(false);
        tree_view.set_headers_visible(false);
        tree_view.set_hexpand(true);

        Rc::new(CompletionView {
            unselect_callback: RefCell::new(None),
            view: tree_view,
        })
    }

    /// Add a callback to the selection changed event.
    pub fn connect_selection_changed<F: Fn(&TreeSelection) + 'static>(&self, callback: F) {
        self.view.get_selection().connect_changed(callback);
    }

    /// Add a callback to the unselect event.
    pub fn connect_unselect<F: Fn() + 'static>(&self, callback: F) {
        *self.unselect_callback.borrow_mut() = Some(Box::new(callback));
    }

    /// Filter the rows from the input.
    pub fn filter(&self, input: &str, completer: &Completer) {
        let model = ListStore::new(&[Type::String, Type::String]);

        let key =
            if let Some(index) = input.find(' ') {
                input[index + 1 ..].trim_left()
            }
            else {
                input
            };
        let key = key.to_lowercase();
        for &(ref col1, ref col2) in &completer.completions(&key) {
            model.insert_with_values(None, &[0, 1], &[&col1, &col2]);
        }
        self.view.set_model(Some(&model));
    }

    /// Scroll to the selected row.
    fn scroll(&self, model: &TreeModel, iter: &TreeIter) {
        if let Some(path) = model.get_path(iter) {
            self.view.scroll_to_cell(Some(&path), None, false, 0.0, 0.0);
        }
    }

    /// Scroll to the first row.
    pub fn scroll_to_first(&self) {
        if let Some(model) = self.view.get_model() {
            if let Some(iter) = model.get_iter_first() {
                if let Some(path) = model.get_path(&iter) {
                    self.view.scroll_to_cell(Some(&path), None, false, 0.0, 0.0);
                }
            }
        }
    }

    /// Select the next item.
    /// This loops with the value that started the completion.
    pub fn select_next(&self) {
        if let Some(model) = self.view.get_model() {
            let selection = self.view.get_selection();
            if let Some((model, selected_iter)) = selection.get_selected() {
                if model.iter_next(&selected_iter) {
                    selection.select_iter(&selected_iter);
                    self.scroll(&model, &selected_iter);
                }
                else {
                    self.unselect();
                    self.show_original_input();
                }
            }
            else if let Some(iter) = model.get_iter_first() {
                self.scroll(&model, &iter);
                selection.select_iter(&iter);
            }
        }
    }

    /// Select the previous item.
    /// This loops with the value that started the completion.
    pub fn select_previous(&self) {
        if let Some(model) = self.view.get_model() {
            let selection = self.view.get_selection();
            if let Some((model, selected_iter)) = selection.get_selected() {
                if model.iter_previous(&selected_iter) {
                    selection.select_iter(&selected_iter);
                    self.scroll(&model, &selected_iter);
                }
                else {
                    self.unselect();
                    self.show_original_input();
                }
            }
            else if let Some(iter) = model.iter_nth_child(None, model.iter_n_children(None) - 1) {
                self.scroll(&model, &iter);
                selection.select_iter(&iter);
            }
        }
    }

    /// Set the model.
    pub fn set_model<T: IsA<TreeModel>>(&self, model: Option<&T>) {
        self.view.set_model(model);
    }

    /// Emit the event to show the original input.
    /// This is emitted when the user unselect from the completion view.
    fn show_original_input(&self) {
        if let Some(ref callback) = *self.unselect_callback.borrow() {
            callback();
        }
    }

    /// Unselect the item.
    pub fn unselect(&self) {
        let selection = self.view.get_selection();
        selection.unselect_all();
    }
}

impl Deref for CompletionView {
    type Target = TreeView;

    fn deref(&self) -> &Self::Target {
        &self.view
    }
}

is_widget!(CompletionView, view);
<commit_msg>Fixed error in select_previous when there are no completions.<commit_after>/*
 * Copyright (c) 2016 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

use std::cell::RefCell;
use std::cmp::max;
use std::ops::Deref;
use std::rc::Rc;

use gtk::{
    CellRendererText,
    IsA,
    ListStore,
    TreeIter,
    TreeModel,
    TreeModelExt,
    TreeSelection,
    TreeView,
    TreeViewColumn,
    Type,
    WidgetExt,
};

use super::Completer;

/// A widget to show completions for the command entry.
pub struct CompletionView {
    unselect_callback: RefCell<Option<Box<Fn()>>>,
    view: TreeView,
}

impl CompletionView {
    /// Create a new completion view.
    pub fn new() -> Rc<Self> {
        let tree_view = TreeView::new();

        let column1 = TreeViewColumn::new();
        let cell1 = CellRendererText::new();
        column1.pack_start(&cell1, true);
        column1.add_attribute(&cell1, "text", 0);
        tree_view.append_column(&column1);

        let column2 = TreeViewColumn::new();
        let cell2 = CellRendererText::new();
        column2.pack_start(&cell2, true);
        column2.add_attribute(&cell2, "text", 1);
        tree_view.append_column(&column2);

        tree_view.get_selection().unselect_all();
        tree_view.set_enable_search(false);
        tree_view.set_headers_visible(false);
        tree_view.set_hexpand(true);

        Rc::new(CompletionView {
            unselect_callback: RefCell::new(None),
            view: tree_view,
        })
    }

    /// Add a callback to the selection changed event.
    pub fn connect_selection_changed<F: Fn(&TreeSelection) + 'static>(&self, callback: F) {
        self.view.get_selection().connect_changed(callback);
    }

    /// Add a callback to the unselect event.
    pub fn connect_unselect<F: Fn() + 'static>(&self, callback: F) {
        *self.unselect_callback.borrow_mut() = Some(Box::new(callback));
    }

    /// Filter the rows from the input.
    pub fn filter(&self, input: &str, completer: &Completer) {
        let model = ListStore::new(&[Type::String, Type::String]);

        let key =
            if let Some(index) = input.find(' ') {
                input[index + 1 ..].trim_left()
            }
            else {
                input
            };
        let key = key.to_lowercase();
        for &(ref col1, ref col2) in &completer.completions(&key) {
            model.insert_with_values(None, &[0, 1], &[&col1, &col2]);
        }
        self.view.set_model(Some(&model));
    }

    /// Scroll to the selected row.
    fn scroll(&self, model: &TreeModel, iter: &TreeIter) {
        if let Some(path) = model.get_path(iter) {
            self.view.scroll_to_cell(Some(&path), None, false, 0.0, 0.0);
        }
    }

    /// Scroll to the first row.
    pub fn scroll_to_first(&self) {
        if let Some(model) = self.view.get_model() {
            if let Some(iter) = model.get_iter_first() {
                if let Some(path) = model.get_path(&iter) {
                    self.view.scroll_to_cell(Some(&path), None, false, 0.0, 0.0);
                }
            }
        }
    }

    /// Select the next item.
    /// This loops with the value that started the completion.
    pub fn select_next(&self) {
        if let Some(model) = self.view.get_model() {
            let selection = self.view.get_selection();
            if let Some((model, selected_iter)) = selection.get_selected() {
                if model.iter_next(&selected_iter) {
                    selection.select_iter(&selected_iter);
                    self.scroll(&model, &selected_iter);
                }
                else {
                    self.unselect();
                    self.show_original_input();
                }
            }
            else if let Some(iter) = model.get_iter_first() {
                self.scroll(&model, &iter);
                selection.select_iter(&iter);
            }
        }
    }

    /// Select the previous item.
    /// This loops with the value that started the completion.
    pub fn select_previous(&self) {
        if let Some(model) = self.view.get_model() {
            let selection = self.view.get_selection();
            if let Some((model, selected_iter)) = selection.get_selected() {
                if model.iter_previous(&selected_iter) {
                    selection.select_iter(&selected_iter);
                    self.scroll(&model, &selected_iter);
                }
                else {
                    self.unselect();
                    self.show_original_input();
                }
            }
            else if let Some(iter) = model.iter_nth_child(None, max(0, model.iter_n_children(None) - 1)) {
                self.scroll(&model, &iter);
                selection.select_iter(&iter);
            }
        }
    }

    /// Set the model.
    pub fn set_model<T: IsA<TreeModel>>(&self, model: Option<&T>) {
        self.view.set_model(model);
    }

    /// Emit the event to show the original input.
    /// This is emitted when the user unselect from the completion view.
    fn show_original_input(&self) {
        if let Some(ref callback) = *self.unselect_callback.borrow() {
            callback();
        }
    }

    /// Unselect the item.
    pub fn unselect(&self) {
        let selection = self.view.get_selection();
        selection.unselect_all();
    }
}

impl Deref for CompletionView {
    type Target = TreeView;

    fn deref(&self) -> &Self::Target {
        &self.view
    }
}

is_widget!(CompletionView, view);
<|endoftext|>


<commit_before>// Copyright (c) 2015-2016 William (B.J.) Snow Orvis
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Lindenmayer systems are a methodology for representing various kinds of iterated curves or
//! other constructions. A given system has an alphabet of symbols, an initial string, and one or
//! more rules for transforming that string into the next iteration/generation.
//!
//! The resulting string at a given iteration or generation can represent a sequence of commands
//! that some representation process, such as a turtle drawing program, can then use to draw a
//! curve/fractal/plant (which is what this implementation provides).

use crate::geometry::Point;
use crate::turtle::*;
use std::cell::RefCell;
use std::marker::PhantomData;

/// Represents a particular Lindenmayer system. It requires an alphabet (represented as an enum),
/// an initial sequence ("string"), and one or more rules that transform the sequence with each
/// iteration/generation.
///
/// Under many circumstances, these methods will not actually use &self. However, having a &self
/// allows for more flexibility, such as creating caching objects or creating L-systems that can be
/// defined at runtime instead of at compile time.
pub trait LindenmayerSystem<Alphabet: Clone> {
    /// Should return the initial Lindenmayer system string (iteration 0).
    fn initial(&self) -> Vec<Alphabet>;

    /// Apply Lindenmayer system rules to a given character.
    ///
    /// A common implementation approach would be to use `match` with the Alphabet. For example:
    ///
    /// ```
    /// use fractal_lib::lindenmayer::LindenmayerSystem;
    ///
    /// /// Our Alphbet
    /// #[derive(Clone)]
    /// enum SomeAlphabet { A, B, C, Foo }
    ///
    /// struct SomeLSystem;
    ///
    /// impl LindenmayerSystem<SomeAlphabet> for SomeLSystem {
    ///      fn initial(&self) -> Vec<SomeAlphabet> {
    ///          vec![SomeAlphabet::A, SomeAlphabet::B, SomeAlphabet::C]
    ///      }
    ///
    ///     fn apply_rule(&self, l: SomeAlphabet) -> Vec<SomeAlphabet> {
    ///         match l {
    ///             SomeAlphabet::A => vec![SomeAlphabet::A, SomeAlphabet::Foo,
    ///             SomeAlphabet::B, SomeAlphabet::C],
    ///             SomeAlphabet::B => vec![SomeAlphabet::Foo],
    ///             SomeAlphabet::C => vec![SomeAlphabet::Foo, SomeAlphabet::B],
    ///             SomeAlphabet::Foo => vec![SomeAlphabet::Foo],
    ///         }
    ///     }
    /// }
    /// ```
    fn apply_rule(&self, curr_symbol: Alphabet) -> Vec<Alphabet>;

    fn generate_next_iteration(&self, last_iteration: &[Alphabet]) -> Vec<Alphabet> {
        let mut newlstr: Vec<Alphabet> = vec![];

        for l in last_iteration.iter().cloned() {
            for other in self.apply_rule(l).iter().cloned() {
                newlstr.push(other);
            }
        }
        newlstr
    }

    /// Generates a Lindenmayer system string for `iteration`.
    ///
    /// This is done by starting with the initial sequence, and repeatedly applying the rules to
    /// the sequence `iteration` times. The result is a new vector that contains the sequence
    /// for the specified iteration.
    fn generate(&self, iteration: u64) -> Vec<Alphabet> {
        let mut last: Vec<Alphabet> = self.initial();
        let mut i = 0;
        while i < iteration {
            i += 1;
            last = self.generate_next_iteration(&last);
        }
        last
    }
}

/// In order to draw a fractal using a Lindenmayer System, we need to translate the output from the
/// L-System into turtle commands. To do this, we need to initial the turtle, and we need a way to
/// convert the L-System's symbols into actions. This trait provides the methods needed to
/// configure the `LindenmayerSystemTurtleProgram`, which is the glue that issues arbitrary Turtle
/// commands.
pub trait LindenmayerSystemDrawingParameters<Alphabet> {
    /// Returns the iteration that should be drawn.
    fn iteration(&self) -> u64;

    /// Specifies the turtle's initial position. Defaults to (0.0, 0.0).
    fn initial_pos(&self) -> Point {
        Point { x: 0.0, y: 0.0 }
    }

    /// Specifies the turtle's initial direction. Defaults to 0.0.
    fn initial_rad(&self) -> f64 {
        0.0
    }

    /// Convert symbol into a turtle command.
    ///
    /// Usually, when moving the turtle forwards, there is some formula that will ensure that
    /// the turtle always ends at a given point, such as at (1.0, 0.0).
    fn interpret_symbol(&self, symbol: Alphabet) -> TurtleStep;
}

/// In order to improve the performance of using a Lindenmayer System under some circumstances, it
/// is beneficial to cache each iteration. This allows O(1) lookups for every iteration less than
/// or equal to the largest iteration already looked up at the cost of storing every iteration
/// below the largest iteration computed (the amount of memory used changes depending on
/// characteristics of the L-System, such as how rapidly the strings grow between each iteration).
#[derive(Clone)]
pub struct LindenmayerSystemCachingDecorator<L, A>
where
    L: LindenmayerSystem<A>,
    A: Clone + 'static,
{
    alphabet: PhantomData<A>,
    pub system: L,
    iteration_cache: RefCell<Vec<Vec<A>>>,
}

impl<'a, L, A> LindenmayerSystemCachingDecorator<L, A>
where
    L: LindenmayerSystem<A>,
    A: Clone + 'static,
{
    /// Return a new LindenmayerSystemCachingDecorator that wraps the input
    /// `system` and caches its iterations.
    pub fn new(system: L) -> LindenmayerSystemCachingDecorator<L, A> {
        LindenmayerSystemCachingDecorator {
            alphabet: PhantomData,
            system,
            iteration_cache: RefCell::new(vec![]),
        }
    }
}

impl<L, A> LindenmayerSystem<A> for LindenmayerSystemCachingDecorator<L, A>
where
    L: LindenmayerSystem<A>,
    A: Clone + 'static,
{
    /// Delegate to system
    fn initial(&self) -> Vec<A> {
        self.system.initial()
    }

    /// Delegate to system
    fn apply_rule(&self, curr_symbol: A) -> Vec<A> {
        self.system.apply_rule(curr_symbol)
    }

    /// Reimplement to to use caching. Currently using recursion.
    fn generate(&self, iteration: u64) -> Vec<A> {
        {
            let cache = self.iteration_cache.borrow_mut();
            let val = cache.get(iteration as usize);
            if val.is_some() {
                println!("found {}", iteration);
                return val.unwrap().clone();
            }
        } // end borrow of the cache
        {
            println!("generating {}", iteration);
            let curr = match iteration {
                0 => self.system.initial(), // terminating case
                _ => {
                    let last = self.generate(iteration - 1);
                    self.system.generate_next_iteration(&last)
                }
            };
            let mut cache = self.iteration_cache.borrow_mut();
            cache.push(curr);
        } // end borrow of the cache
          // Now that we have cached, try again (which should use the cache)
        self.generate(iteration)
    }
}

#[derive(Clone)]
pub struct LindenmayerSystemTurtleProgram<L, A>
where
    L: LindenmayerSystem<A> + LindenmayerSystemDrawingParameters<A>,
    A: Clone + 'static,
{
    alphabet: PhantomData<A>,
    cacheable_system: LindenmayerSystemCachingDecorator<L, A>, // system: L,
}

impl<L, A> LindenmayerSystemTurtleProgram<L, A>
where
    L: LindenmayerSystem<A> + LindenmayerSystemDrawingParameters<A>,
    A: Clone,
{
    pub fn new(system: L) -> LindenmayerSystemTurtleProgram<L, A> {
        LindenmayerSystemTurtleProgram {
            alphabet: PhantomData,
            cacheable_system: LindenmayerSystemCachingDecorator::new(system), // system: system,
        }
    }
}

impl<L, A> TurtleProgram for LindenmayerSystemTurtleProgram<L, A>
where
    LindenmayerSystemTurtleProgram<L, A>: Clone,
    L: LindenmayerSystem<A> + LindenmayerSystemDrawingParameters<A> + 'static,
    A: Clone + 'static,
{
    fn init_turtle(&self) -> Vec<TurtleStep> {
        vec![
            TurtleStep::SetPos(self.cacheable_system.system.initial_pos()),
            TurtleStep::SetRad(self.cacheable_system.system.initial_rad()),
            TurtleStep::Down,
        ]
    }

    // The lifetimes are needed here to satisfy TurtleProgramIterator's type signature.
    fn turtle_program_iter(&self) -> TurtleProgramIterator {
        let sequence = self
            .cacheable_system
            .generate(self.cacheable_system.system.iteration());
        println!("Done");

        TurtleProgramIterator::new(Box::new(LindenmayerSystemTurtleProgramIterator {
            alphabet: PhantomData,
            program: (*self).clone(),
            sequence,
            curr_step: 0,
        }))
    }
}

pub struct LindenmayerSystemTurtleProgramIterator<L, A>
where
    L: LindenmayerSystem<A> + LindenmayerSystemDrawingParameters<A> + 'static,
    A: Clone + 'static,
{
    alphabet: PhantomData<A>,
    program: LindenmayerSystemTurtleProgram<L, A>,
    sequence: Vec<A>,
    curr_step: usize,
}

impl<'a, L, A> Iterator for LindenmayerSystemTurtleProgramIterator<L, A>
where
    L: LindenmayerSystem<A> + LindenmayerSystemDrawingParameters<A> + 'static,
    A: Clone + 'static,
{
    type Item = TurtleStep;

    fn next(&mut self) -> Option<TurtleStep> {
        if self.curr_step >= self.sequence.len() {
            return None;
        }

        let symbol = self.sequence[self.curr_step].clone();
        self.curr_step += 1;

        Some(
            self.program
                .cacheable_system
                .system
                .interpret_symbol(symbol),
        )
    }
}

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

    #[derive(Clone, PartialEq, Eq, Debug)]
    enum TestABC {
        A,
        B,
        C,
        Foo,
    }

    struct TestLS;

    impl LindenmayerSystem<TestABC> for TestLS {
        fn initial(&self) -> Vec<TestABC> {
            vec![TestABC::A, TestABC::B, TestABC::C]
        }

        fn apply_rule(&self, l: TestABC) -> Vec<TestABC> {
            match l {
                TestABC::A => vec![TestABC::A, TestABC::Foo, TestABC::B, TestABC::C],
                TestABC::B => vec![TestABC::Foo],
                TestABC::C => vec![TestABC::Foo, TestABC::B],
                TestABC::Foo => vec![TestABC::Foo],
            }
        }
    }

    /// Test a sample TestLS system
    #[test]
    fn test_lsystem() {
        assert_eq!(TestLS.generate(0), [TestABC::A, TestABC::B, TestABC::C]);
        assert_eq!(
            TestLS.generate(1),
            [
                TestABC::A,
                TestABC::Foo,
                TestABC::B,
                TestABC::C,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::B
            ]
        );
        assert_eq!(
            TestLS.generate(2),
            [
                TestABC::A,
                TestABC::Foo,
                TestABC::B,
                TestABC::C,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::B,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo
            ]
        );
        assert_eq!(
            TestLS.generate(3),
            [
                TestABC::A,
                TestABC::Foo,
                TestABC::B,
                TestABC::C,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::B,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo
            ]
        );
    }

    /// Test the caching decorator
    #[test]
    fn test_caching() {
        // All this can really test is verify that multiple calls for the same
        // generation come out the same.
        let orig_system = TestLS;
        let system = LindenmayerSystemCachingDecorator::new(orig_system);
        // baseline
        assert_eq!(system.generate(0), [TestABC::A, TestABC::B, TestABC::C]);
        // again
        assert_eq!(system.generate(0), [TestABC::A, TestABC::B, TestABC::C]);
        // something that will require caching 1 and 2 and use 0's cache
        assert_eq!(
            system.generate(3),
            [
                TestABC::A,
                TestABC::Foo,
                TestABC::B,
                TestABC::C,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::B,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo
            ]
        );
        // use cache
        assert_eq!(
            system.generate(3),
            [
                TestABC::A,
                TestABC::Foo,
                TestABC::B,
                TestABC::C,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::B,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo
            ]
        );
        // use cache
        assert_eq!(
            system.generate(1),
            [
                TestABC::A,
                TestABC::Foo,
                TestABC::B,
                TestABC::C,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::B
            ]
        );
    }
}
<commit_msg>Fix a spacing issue in a docstring in lindenmayer.rs<commit_after>// Copyright (c) 2015-2016 William (B.J.) Snow Orvis
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Lindenmayer systems are a methodology for representing various kinds of iterated curves or
//! other constructions. A given system has an alphabet of symbols, an initial string, and one or
//! more rules for transforming that string into the next iteration/generation.
//!
//! The resulting string at a given iteration or generation can represent a sequence of commands
//! that some representation process, such as a turtle drawing program, can then use to draw a
//! curve/fractal/plant (which is what this implementation provides).

use crate::geometry::Point;
use crate::turtle::*;
use std::cell::RefCell;
use std::marker::PhantomData;

/// Represents a particular Lindenmayer system. It requires an alphabet (represented as an enum),
/// an initial sequence ("string"), and one or more rules that transform the sequence with each
/// iteration/generation.
///
/// Under many circumstances, these methods will not actually use &self. However, having a &self
/// allows for more flexibility, such as creating caching objects or creating L-systems that can be
/// defined at runtime instead of at compile time.
pub trait LindenmayerSystem<Alphabet: Clone> {
    /// Should return the initial Lindenmayer system string (iteration 0).
    fn initial(&self) -> Vec<Alphabet>;

    /// Apply Lindenmayer system rules to a given character.
    ///
    /// A common implementation approach would be to use `match` with the Alphabet. For example:
    ///
    /// ```
    /// use fractal_lib::lindenmayer::LindenmayerSystem;
    ///
    /// /// Our Alphbet
    /// #[derive(Clone)]
    /// enum SomeAlphabet { A, B, C, Foo }
    ///
    /// struct SomeLSystem;
    ///
    /// impl LindenmayerSystem<SomeAlphabet> for SomeLSystem {
    ///     fn initial(&self) -> Vec<SomeAlphabet> {
    ///         vec![SomeAlphabet::A, SomeAlphabet::B, SomeAlphabet::C]
    ///     }
    ///
    ///     fn apply_rule(&self, l: SomeAlphabet) -> Vec<SomeAlphabet> {
    ///         match l {
    ///             SomeAlphabet::A => vec![SomeAlphabet::A, SomeAlphabet::Foo,
    ///             SomeAlphabet::B, SomeAlphabet::C],
    ///             SomeAlphabet::B => vec![SomeAlphabet::Foo],
    ///             SomeAlphabet::C => vec![SomeAlphabet::Foo, SomeAlphabet::B],
    ///             SomeAlphabet::Foo => vec![SomeAlphabet::Foo],
    ///         }
    ///     }
    /// }
    /// ```
    fn apply_rule(&self, curr_symbol: Alphabet) -> Vec<Alphabet>;

    fn generate_next_iteration(&self, last_iteration: &[Alphabet]) -> Vec<Alphabet> {
        let mut newlstr: Vec<Alphabet> = vec![];

        for l in last_iteration.iter().cloned() {
            for other in self.apply_rule(l).iter().cloned() {
                newlstr.push(other);
            }
        }
        newlstr
    }

    /// Generates a Lindenmayer system string for `iteration`.
    ///
    /// This is done by starting with the initial sequence, and repeatedly applying the rules to
    /// the sequence `iteration` times. The result is a new vector that contains the sequence
    /// for the specified iteration.
    fn generate(&self, iteration: u64) -> Vec<Alphabet> {
        let mut last: Vec<Alphabet> = self.initial();
        let mut i = 0;
        while i < iteration {
            i += 1;
            last = self.generate_next_iteration(&last);
        }
        last
    }
}

/// In order to draw a fractal using a Lindenmayer System, we need to translate the output from the
/// L-System into turtle commands. To do this, we need to initial the turtle, and we need a way to
/// convert the L-System's symbols into actions. This trait provides the methods needed to
/// configure the `LindenmayerSystemTurtleProgram`, which is the glue that issues arbitrary Turtle
/// commands.
pub trait LindenmayerSystemDrawingParameters<Alphabet> {
    /// Returns the iteration that should be drawn.
    fn iteration(&self) -> u64;

    /// Specifies the turtle's initial position. Defaults to (0.0, 0.0).
    fn initial_pos(&self) -> Point {
        Point { x: 0.0, y: 0.0 }
    }

    /// Specifies the turtle's initial direction. Defaults to 0.0.
    fn initial_rad(&self) -> f64 {
        0.0
    }

    /// Convert symbol into a turtle command.
    ///
    /// Usually, when moving the turtle forwards, there is some formula that will ensure that
    /// the turtle always ends at a given point, such as at (1.0, 0.0).
    fn interpret_symbol(&self, symbol: Alphabet) -> TurtleStep;
}

/// In order to improve the performance of using a Lindenmayer System under some circumstances, it
/// is beneficial to cache each iteration. This allows O(1) lookups for every iteration less than
/// or equal to the largest iteration already looked up at the cost of storing every iteration
/// below the largest iteration computed (the amount of memory used changes depending on
/// characteristics of the L-System, such as how rapidly the strings grow between each iteration).
#[derive(Clone)]
pub struct LindenmayerSystemCachingDecorator<L, A>
where
    L: LindenmayerSystem<A>,
    A: Clone + 'static,
{
    alphabet: PhantomData<A>,
    pub system: L,
    iteration_cache: RefCell<Vec<Vec<A>>>,
}

impl<'a, L, A> LindenmayerSystemCachingDecorator<L, A>
where
    L: LindenmayerSystem<A>,
    A: Clone + 'static,
{
    /// Return a new LindenmayerSystemCachingDecorator that wraps the input
    /// `system` and caches its iterations.
    pub fn new(system: L) -> LindenmayerSystemCachingDecorator<L, A> {
        LindenmayerSystemCachingDecorator {
            alphabet: PhantomData,
            system,
            iteration_cache: RefCell::new(vec![]),
        }
    }
}

impl<L, A> LindenmayerSystem<A> for LindenmayerSystemCachingDecorator<L, A>
where
    L: LindenmayerSystem<A>,
    A: Clone + 'static,
{
    /// Delegate to system
    fn initial(&self) -> Vec<A> {
        self.system.initial()
    }

    /// Delegate to system
    fn apply_rule(&self, curr_symbol: A) -> Vec<A> {
        self.system.apply_rule(curr_symbol)
    }

    /// Reimplement to to use caching. Currently using recursion.
    fn generate(&self, iteration: u64) -> Vec<A> {
        {
            let cache = self.iteration_cache.borrow_mut();
            let val = cache.get(iteration as usize);
            if val.is_some() {
                println!("found {}", iteration);
                return val.unwrap().clone();
            }
        } // end borrow of the cache
        {
            println!("generating {}", iteration);
            let curr = match iteration {
                0 => self.system.initial(), // terminating case
                _ => {
                    let last = self.generate(iteration - 1);
                    self.system.generate_next_iteration(&last)
                }
            };
            let mut cache = self.iteration_cache.borrow_mut();
            cache.push(curr);
        } // end borrow of the cache
          // Now that we have cached, try again (which should use the cache)
        self.generate(iteration)
    }
}

#[derive(Clone)]
pub struct LindenmayerSystemTurtleProgram<L, A>
where
    L: LindenmayerSystem<A> + LindenmayerSystemDrawingParameters<A>,
    A: Clone + 'static,
{
    alphabet: PhantomData<A>,
    cacheable_system: LindenmayerSystemCachingDecorator<L, A>, // system: L,
}

impl<L, A> LindenmayerSystemTurtleProgram<L, A>
where
    L: LindenmayerSystem<A> + LindenmayerSystemDrawingParameters<A>,
    A: Clone,
{
    pub fn new(system: L) -> LindenmayerSystemTurtleProgram<L, A> {
        LindenmayerSystemTurtleProgram {
            alphabet: PhantomData,
            cacheable_system: LindenmayerSystemCachingDecorator::new(system), // system: system,
        }
    }
}

impl<L, A> TurtleProgram for LindenmayerSystemTurtleProgram<L, A>
where
    LindenmayerSystemTurtleProgram<L, A>: Clone,
    L: LindenmayerSystem<A> + LindenmayerSystemDrawingParameters<A> + 'static,
    A: Clone + 'static,
{
    fn init_turtle(&self) -> Vec<TurtleStep> {
        vec![
            TurtleStep::SetPos(self.cacheable_system.system.initial_pos()),
            TurtleStep::SetRad(self.cacheable_system.system.initial_rad()),
            TurtleStep::Down,
        ]
    }

    // The lifetimes are needed here to satisfy TurtleProgramIterator's type signature.
    fn turtle_program_iter(&self) -> TurtleProgramIterator {
        let sequence = self
            .cacheable_system
            .generate(self.cacheable_system.system.iteration());
        println!("Done");

        TurtleProgramIterator::new(Box::new(LindenmayerSystemTurtleProgramIterator {
            alphabet: PhantomData,
            program: (*self).clone(),
            sequence,
            curr_step: 0,
        }))
    }
}

pub struct LindenmayerSystemTurtleProgramIterator<L, A>
where
    L: LindenmayerSystem<A> + LindenmayerSystemDrawingParameters<A> + 'static,
    A: Clone + 'static,
{
    alphabet: PhantomData<A>,
    program: LindenmayerSystemTurtleProgram<L, A>,
    sequence: Vec<A>,
    curr_step: usize,
}

impl<'a, L, A> Iterator for LindenmayerSystemTurtleProgramIterator<L, A>
where
    L: LindenmayerSystem<A> + LindenmayerSystemDrawingParameters<A> + 'static,
    A: Clone + 'static,
{
    type Item = TurtleStep;

    fn next(&mut self) -> Option<TurtleStep> {
        if self.curr_step >= self.sequence.len() {
            return None;
        }

        let symbol = self.sequence[self.curr_step].clone();
        self.curr_step += 1;

        Some(
            self.program
                .cacheable_system
                .system
                .interpret_symbol(symbol),
        )
    }
}

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

    #[derive(Clone, PartialEq, Eq, Debug)]
    enum TestABC {
        A,
        B,
        C,
        Foo,
    }

    struct TestLS;

    impl LindenmayerSystem<TestABC> for TestLS {
        fn initial(&self) -> Vec<TestABC> {
            vec![TestABC::A, TestABC::B, TestABC::C]
        }

        fn apply_rule(&self, l: TestABC) -> Vec<TestABC> {
            match l {
                TestABC::A => vec![TestABC::A, TestABC::Foo, TestABC::B, TestABC::C],
                TestABC::B => vec![TestABC::Foo],
                TestABC::C => vec![TestABC::Foo, TestABC::B],
                TestABC::Foo => vec![TestABC::Foo],
            }
        }
    }

    /// Test a sample TestLS system
    #[test]
    fn test_lsystem() {
        assert_eq!(TestLS.generate(0), [TestABC::A, TestABC::B, TestABC::C]);
        assert_eq!(
            TestLS.generate(1),
            [
                TestABC::A,
                TestABC::Foo,
                TestABC::B,
                TestABC::C,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::B
            ]
        );
        assert_eq!(
            TestLS.generate(2),
            [
                TestABC::A,
                TestABC::Foo,
                TestABC::B,
                TestABC::C,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::B,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo
            ]
        );
        assert_eq!(
            TestLS.generate(3),
            [
                TestABC::A,
                TestABC::Foo,
                TestABC::B,
                TestABC::C,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::B,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo
            ]
        );
    }

    /// Test the caching decorator
    #[test]
    fn test_caching() {
        // All this can really test is verify that multiple calls for the same
        // generation come out the same.
        let orig_system = TestLS;
        let system = LindenmayerSystemCachingDecorator::new(orig_system);
        // baseline
        assert_eq!(system.generate(0), [TestABC::A, TestABC::B, TestABC::C]);
        // again
        assert_eq!(system.generate(0), [TestABC::A, TestABC::B, TestABC::C]);
        // something that will require caching 1 and 2 and use 0's cache
        assert_eq!(
            system.generate(3),
            [
                TestABC::A,
                TestABC::Foo,
                TestABC::B,
                TestABC::C,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::B,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo
            ]
        );
        // use cache
        assert_eq!(
            system.generate(3),
            [
                TestABC::A,
                TestABC::Foo,
                TestABC::B,
                TestABC::C,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::B,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::Foo
            ]
        );
        // use cache
        assert_eq!(
            system.generate(1),
            [
                TestABC::A,
                TestABC::Foo,
                TestABC::B,
                TestABC::C,
                TestABC::Foo,
                TestABC::Foo,
                TestABC::B
            ]
        );
    }
}
<|endoftext|>


<commit_before>use std::iter::Map;
use calx::{V2, Rect, RectIter};

pub static SCREEN_W: int = 640;
pub static SCREEN_H: int = 360;

/// Useful general constant for cell dimension ops.
static PIXEL_UNIT: int = 16;

/// Draw layer for floor tiles.
pub static FLOOR_Z: f32 = 0.500f32;
/// Draw layer for wall and object tiles.
pub static BLOCK_Z: f32 = 0.400f32;
/// Draw layer for visual effects
pub static FX_Z: f32 = 0.300f32;

/// Transform from chart space (unit is one map cell) to view space (unit is
/// one pixel).
pub fn chart_to_view(chart_pos: V2<int>) -> V2<int> {
    V2(chart_pos.0 * PIXEL_UNIT - chart_pos.1 * PIXEL_UNIT,
       chart_pos.0 * PIXEL_UNIT / 2 + chart_pos.1 * PIXEL_UNIT / 2)
}

/// Transform from chart space into the default on-screen space centered on
/// window center.
pub fn chart_to_screen(chart_pos: V2<int>) -> V2<int> {
    chart_to_view(chart_pos) + V2(SCREEN_W / 2, SCREEN_H / 2)
}

/// Transform from view space (unit is one pixel) to chart space (unit is one
/// map cell).
pub fn view_to_chart(view_pos: V2<int>) -> V2<int> {
    let c = PIXEL_UNIT as f32 / 2.0;
    let column = ((view_pos.0 as f32 + c) / (c * 2.0)).floor();
    let row = ((view_pos.1 as f32 - column * c) / (c * 2.0)).floor();
    V2((column + row) as int, row as int)
}

/// Return the chart positions for which chart_to_view is inside view_rect.
pub fn cells_in_view_rect<'a>(view_rect: Rect<int>) -> Map<'a, V2<int>, V2<int>, RectIter<int>> {
    let p1 = pixel_to_min_column(view_rect.mn());
    let p2 = pixel_to_max_column(view_rect.mx());
    Rect(p1, p2 - p1)
        .iter().map(|rc| column_to_chart(rc))
}

pub fn cells_on_screen<'a>() -> Map<'a, V2<int>, V2<int>, RectIter<int>> {
    cells_in_view_rect(Rect(V2(-SCREEN_W / 2, -SCREEN_H / 2), V2(SCREEN_W, SCREEN_H)))
}

/// Transform to the column space point that contains the pixel space point
/// when looking for minimum column space point. (The column space rows
/// overlap, so minimum and maximum points differ.)
fn pixel_to_min_column(pixel_pos: V2<int>) -> V2<int> {
    V2((pixel_pos.0 - PIXEL_UNIT) / PIXEL_UNIT,
       (pixel_pos.1 - PIXEL_UNIT * 2) / PIXEL_UNIT)
}

/// Transform to the column space point that contains the pixel space point
/// when looking for maximum column space point. (The column space rows
/// overlap, so minimum and maximum points differ.)
fn pixel_to_max_column(pixel_pos: V2<int>) -> V2<int> {
    V2((pixel_pos.0 + PIXEL_UNIT) / PIXEL_UNIT,
       (pixel_pos.1 + PIXEL_UNIT) / PIXEL_UNIT)
}

/// Transform a column space point to a chart space point.
fn column_to_chart(cr: V2<int>) -> V2<int> {
    V2(((1 + cr.0 + 2 * cr.1) as f32 / 2f32).floor() as int,
       (-(cr.0 - 1) as f32 / 2f32).floor() as int + cr.1)
}

#[cfg(test)]
mod test {
    use calx::V2;
    use super::column_to_chart;

    #[test]
    fn c2c() {
        assert_eq!(V2(-1,  0), column_to_chart(V2(-1, -1)));
        assert_eq!(V2(-1, -1), column_to_chart(V2( 0, -1)));
        assert_eq!(V2( 0, -1), column_to_chart(V2( 1, -1)));

        assert_eq!(V2( 0,  1), column_to_chart(V2(-1,  0)));
        assert_eq!(V2( 0,  0), column_to_chart(V2( 0,  0)));
        assert_eq!(V2( 1,  0), column_to_chart(V2( 1,  0)));

        assert_eq!(V2( 1,  2), column_to_chart(V2(-1,  1)));
        assert_eq!(V2( 1,  1), column_to_chart(V2( 0,  1)));
        assert_eq!(V2( 2,  1), column_to_chart(V2( 1,  1)));

        assert_eq!(V2(-3, -1), column_to_chart(V2(-2, -2)));
        assert_eq!(V2( 1,  3), column_to_chart(V2(-2,  2)));
        assert_eq!(V2( 3,  1), column_to_chart(V2( 2,  2)));
        assert_eq!(V2(-1, -3), column_to_chart(V2( 2, -2)));
    }
}
<commit_msg>Special column chart iteration for correct tile depth order<commit_after>use std::iter::Map;
use calx::{V2, Rect, RectIter};

pub static SCREEN_W: int = 640;
pub static SCREEN_H: int = 360;

/// Useful general constant for cell dimension ops.
static PIXEL_UNIT: int = 16;

/// Draw layer for floor tiles.
pub static FLOOR_Z: f32 = 0.500f32;
/// Draw layer for wall and object tiles.
pub static BLOCK_Z: f32 = 0.400f32;
/// Draw layer for visual effects
pub static FX_Z: f32 = 0.300f32;

/// Transform from chart space (unit is one map cell) to view space (unit is
/// one pixel).
pub fn chart_to_view(chart_pos: V2<int>) -> V2<int> {
    V2(chart_pos.0 * PIXEL_UNIT - chart_pos.1 * PIXEL_UNIT,
       chart_pos.0 * PIXEL_UNIT / 2 + chart_pos.1 * PIXEL_UNIT / 2)
}

/// Transform from chart space into the default on-screen space centered on
/// window center.
pub fn chart_to_screen(chart_pos: V2<int>) -> V2<int> {
    chart_to_view(chart_pos) + V2(SCREEN_W / 2, SCREEN_H / 2)
}

/// Transform from view space (unit is one pixel) to chart space (unit is one
/// map cell).
pub fn view_to_chart(view_pos: V2<int>) -> V2<int> {
    let c = PIXEL_UNIT as f32 / 2.0;
    let column = ((view_pos.0 as f32 + c) / (c * 2.0)).floor();
    let row = ((view_pos.1 as f32 - column * c) / (c * 2.0)).floor();
    V2((column + row) as int, row as int)
}

/// Return the chart positions for which chart_to_view is inside view_rect.
pub fn cells_in_view_rect<'a>(view_rect: Rect<int>) -> Map<'a, V2<int>, V2<int>, ColumnRectIter> {
    let V2(x0, y0) = pixel_to_min_column(view_rect.mn());
    let V2(x1, y1) = pixel_to_max_column(view_rect.mx());
    ColumnRectIter {
        x: x0,
        y: y0,
        upper_row: x0 % 2 == 0,
        x0: x0,
        x1: x1,
        y1: y1,
    }.map(|rc| column_to_chart(rc))
}

pub fn cells_on_screen<'a>() -> Map<'a, V2<int>, V2<int>, ColumnRectIter> {
    cells_in_view_rect(Rect(V2(-SCREEN_W / 2, -SCREEN_H / 2), V2(SCREEN_W, SCREEN_H)))
}

/// Transform to the column space point that contains the pixel space point
/// when looking for minimum column space point. (The column space rows
/// overlap, so minimum and maximum points differ.)
fn pixel_to_min_column(pixel_pos: V2<int>) -> V2<int> {
    V2((pixel_pos.0 - PIXEL_UNIT) / PIXEL_UNIT,
       (pixel_pos.1 - PIXEL_UNIT * 2) / PIXEL_UNIT)
}

/// Transform to the column space point that contains the pixel space point
/// when looking for maximum column space point. (The column space rows
/// overlap, so minimum and maximum points differ.)
fn pixel_to_max_column(pixel_pos: V2<int>) -> V2<int> {
    V2((pixel_pos.0 + PIXEL_UNIT) / PIXEL_UNIT,
       (pixel_pos.1 + PIXEL_UNIT) / PIXEL_UNIT)
}

/// Transform a column space point to a chart space point.
fn column_to_chart(cr: V2<int>) -> V2<int> {
    V2(((1 + cr.0 + 2 * cr.1) as f32 / 2f32).floor() as int,
       (-(cr.0 - 1) as f32 / 2f32).floor() as int + cr.1)
}

pub struct ColumnRectIter {
    x: int,
    y: int,
    // To prevent ordering artifacts, a hex column layout iterator needs to
    // return each row in two parts, first the upper row of hexes offsetted
    // up, then the lower row.
    upper_row: bool,
    x0: int,
    x1: int,
    y1: int,
}

impl Iterator<V2<int>> for ColumnRectIter {
    fn next(&mut self) -> Option<V2<int>> {
        if self.y >= self.y1 { return None; }
        let ret = Some(V2(self.x, self.y));
        self.x = self.x + 2;

        if self.x >= self.x1 {
            self.x = self.x0 +
                if ((self.x0 % 2) == 1) ^ !self.upper_row {
                    1
                } else {
                    0
                };
            if self.upper_row {
                self.upper_row = false;
            } else {
                self.y = self.y + 1;
                self.upper_row = true;
            }
        }
        ret
    }
}

#[cfg(test)]
mod test {
    use calx::V2;
    use super::column_to_chart;

    #[test]
    fn c2c() {
        assert_eq!(V2(-1,  0), column_to_chart(V2(-1, -1)));
        assert_eq!(V2(-1, -1), column_to_chart(V2( 0, -1)));
        assert_eq!(V2( 0, -1), column_to_chart(V2( 1, -1)));

        assert_eq!(V2( 0,  1), column_to_chart(V2(-1,  0)));
        assert_eq!(V2( 0,  0), column_to_chart(V2( 0,  0)));
        assert_eq!(V2( 1,  0), column_to_chart(V2( 1,  0)));

        assert_eq!(V2( 1,  2), column_to_chart(V2(-1,  1)));
        assert_eq!(V2( 1,  1), column_to_chart(V2( 0,  1)));
        assert_eq!(V2( 2,  1), column_to_chart(V2( 1,  1)));

        assert_eq!(V2(-3, -1), column_to_chart(V2(-2, -2)));
        assert_eq!(V2( 1,  3), column_to_chart(V2(-2,  2)));
        assert_eq!(V2( 3,  1), column_to_chart(V2( 2,  2)));
        assert_eq!(V2(-1, -3), column_to_chart(V2( 2, -2)));
    }
}
<|endoftext|>