<commit_before>//! Simple daemon
//!
//! This daemon will start web server, track new packages and build them

use std::{env, thread};
use std::panic::{catch_unwind, AssertUnwindSafe};
use std::process::exit;
use std::fs::File;
use std::io::Write;
use std::time::Duration;
use std::path::PathBuf;
use libc::fork;
use time;
use DocBuilderOptions;
use DocBuilder;
use utils::{update_sources, update_release_activity, github_updater, pubsubhubbub};
use db::{connect_db, update_search_index};

pub fn start_daemon() {
    // first check required environment variables
    for v in ["CRATESFYI_PREFIX",
              "CRATESFYI_PREFIX",
              "CRATESFYI_GITHUB_USERNAME",
              "CRATESFYI_GITHUB_ACCESSTOKEN"]
        .iter() {
        env::var(v).expect("Environment variable not found");
    }

    let dbopts = opts();

    // check paths once
    dbopts.check_paths().unwrap();

    // fork the process
    let pid = unsafe { fork() };
    if pid > 0 {
        let mut file = File::create(dbopts.prefix.join("cratesfyi.pid"))
            .expect("Failed to create pid file");
        writeln!(&mut file, "{}", pid).expect("Failed to write pid");

        info!("cratesfyi {} daemon started on: {}", ::BUILD_VERSION, pid);
        exit(0);
    }

    // check new crates every minute
    thread::spawn(move || {
        // space this out to prevent it from clashing against the queue-builder thread on launch
        thread::sleep(Duration::from_secs(30));
        loop {
            let opts = opts();
            let mut doc_builder = DocBuilder::new(opts);

            debug!("Checking new crates");
            match doc_builder.get_new_crates() {
                Ok(n) => debug!("{} crates added to queue", n),
                Err(e) => error!("Failed to get new crates: {}", e),
            }

            thread::sleep(Duration::from_secs(60));
        }
    });

    // build new crates every minute
    thread::spawn(move || {
        let opts = opts();
        let mut doc_builder = DocBuilder::new(opts);

        /// Represents the current state of the builder thread.
        enum BuilderState {
            /// The builder thread has just started, and hasn't built any crates yet.
            Fresh,
            /// The builder has just seen an empty build queue.
            EmptyQueue,
            /// The builder has just seen the lock file.
            Locked,
            /// The builder has just finished building a crate. The enclosed count is the number of
            /// crates built since the caches have been refreshed.
            QueueInProgress(usize),
        }

        let mut status = BuilderState::Fresh;

        loop {
            if !status.is_in_progress() {
                thread::sleep(Duration::from_secs(60));
            }

            // check lock file
            if doc_builder.is_locked() {
                warn!("Lock file exits, skipping building new crates");
                status = BuilderState::Locked;
                continue;
            }

            if status.count() > 10 {
                // periodically, we need to flush our caches and ping the hubs
                debug!("10 builds in a row; flushing caches");
                status = BuilderState::QueueInProgress(0);

                match pubsubhubbub::ping_hubs() {
                    Err(e) => error!("Failed to ping hub: {}", e),
                    Ok(n) => debug!("Succesfully pinged {} hubs", n)
                }

                if let Err(e) = doc_builder.load_cache() {
                    error!("Failed to load cache: {}", e);
                }

                if let Err(e) = doc_builder.save_cache() {
                    error!("Failed to save cache: {}", e);
                }

                if let Err(e) = update_sources() {
                    error!("Failed to update sources: {}", e);
                    continue;
                }
            }

            // Only build crates if there are any to build
            debug!("Checking build queue");
            match doc_builder.get_queue_count() {
                Err(e) => {
                    error!("Failed to read the number of crates in the queue: {}", e);
                    continue;
                }
                Ok(0) => {
                    if status.is_in_progress() {
                        // ping the hubs before continuing
                        match pubsubhubbub::ping_hubs() {
                            Err(e) => error!("Failed to ping hub: {}", e),
                            Ok(n) => debug!("Succesfully pinged {} hubs", n)
                        }

                        if let Err(e) = doc_builder.save_cache() {
                            error!("Failed to save cache: {}", e);
                        }
                    }
                    debug!("Queue is empty, going back to sleep");
                    status = BuilderState::EmptyQueue;
                    continue;
                }
                Ok(queue_count) => {
                    info!("Starting build with {} crates in queue (currently on a {} crate streak)",
                          queue_count, status.count());
                }
            }

            // if we're starting a new batch, reload our caches and sources
            if !status.is_in_progress() {
                if let Err(e) = doc_builder.load_cache() {
                    error!("Failed to load cache: {}", e);
                    continue;
                }

                if let Err(e) = update_sources() {
                    error!("Failed to update sources: {}", e);
                    continue;
                }
            }

            // Run build_packages_queue under `catch_unwind` to catch panics
            // This only panicked twice in the last 6 months but its just a better
            // idea to do this.
            let res = catch_unwind(AssertUnwindSafe(|| {
                match doc_builder.build_next_queue_package() {
                    Err(e) => error!("Failed to build crate from queue: {}", e),
                    Ok(crate_built) => if crate_built {
                        status.increment();
                    }

                }
            }));

            if let Err(e) = res {
                error!("GRAVE ERROR Building new crates panicked: {:?}", e);
            }
        }

        impl BuilderState {
            fn count(&self) -> usize {
                match *self {
                    BuilderState::QueueInProgress(n) => n,
                    _ => 0,
                }
            }

            fn is_in_progress(&self) -> bool {
                match *self {
                    BuilderState::QueueInProgress(_) => true,
                    _ => false,
                }
            }

            fn increment(&mut self) {
                *self = BuilderState::QueueInProgress(self.count() + 1);
            }
        }
    });

    // update release activity everyday at 23:55
    thread::spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60));
            let now = time::now();
            if now.tm_hour == 23 && now.tm_min == 55 {
                info!("Updating release activity");
                if let Err(e) = update_release_activity() {
                    error!("Failed to update release activity: {}", e);
                }
            }
        }
    });

    // update search index every 3 hours
    thread::spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60 * 60 * 3));
            let conn = connect_db().expect("Failed to connect database");
            if let Err(e) = update_search_index(&conn) {
                error!("Failed to update search index: {}", e);
            }
        }
    });

    // update github stats every 6 hours
    thread::spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60 * 60 * 6));
            if let Err(e) = github_updater() {
                error!("Failed to update github fields: {}", e);
            }
        }
    });

    // TODO: update ssl certificate every 3 months

    // at least start web server
    info!("Starting web server");
    ::start_web_server(None);
}

fn opts() -> DocBuilderOptions {
    let prefix = PathBuf::from(env::var("CRATESFYI_PREFIX")
        .expect("CRATESFYI_PREFIX environment variable not found"));
    DocBuilderOptions::from_prefix(prefix)
}
<commit_msg>cycle caches at 10 builds, not 11<commit_after>//! Simple daemon
//!
//! This daemon will start web server, track new packages and build them

use std::{env, thread};
use std::panic::{catch_unwind, AssertUnwindSafe};
use std::process::exit;
use std::fs::File;
use std::io::Write;
use std::time::Duration;
use std::path::PathBuf;
use libc::fork;
use time;
use DocBuilderOptions;
use DocBuilder;
use utils::{update_sources, update_release_activity, github_updater, pubsubhubbub};
use db::{connect_db, update_search_index};

pub fn start_daemon() {
    // first check required environment variables
    for v in ["CRATESFYI_PREFIX",
              "CRATESFYI_PREFIX",
              "CRATESFYI_GITHUB_USERNAME",
              "CRATESFYI_GITHUB_ACCESSTOKEN"]
        .iter() {
        env::var(v).expect("Environment variable not found");
    }

    let dbopts = opts();

    // check paths once
    dbopts.check_paths().unwrap();

    // fork the process
    let pid = unsafe { fork() };
    if pid > 0 {
        let mut file = File::create(dbopts.prefix.join("cratesfyi.pid"))
            .expect("Failed to create pid file");
        writeln!(&mut file, "{}", pid).expect("Failed to write pid");

        info!("cratesfyi {} daemon started on: {}", ::BUILD_VERSION, pid);
        exit(0);
    }

    // check new crates every minute
    thread::spawn(move || {
        // space this out to prevent it from clashing against the queue-builder thread on launch
        thread::sleep(Duration::from_secs(30));
        loop {
            let opts = opts();
            let mut doc_builder = DocBuilder::new(opts);

            debug!("Checking new crates");
            match doc_builder.get_new_crates() {
                Ok(n) => debug!("{} crates added to queue", n),
                Err(e) => error!("Failed to get new crates: {}", e),
            }

            thread::sleep(Duration::from_secs(60));
        }
    });

    // build new crates every minute
    thread::spawn(move || {
        let opts = opts();
        let mut doc_builder = DocBuilder::new(opts);

        /// Represents the current state of the builder thread.
        enum BuilderState {
            /// The builder thread has just started, and hasn't built any crates yet.
            Fresh,
            /// The builder has just seen an empty build queue.
            EmptyQueue,
            /// The builder has just seen the lock file.
            Locked,
            /// The builder has just finished building a crate. The enclosed count is the number of
            /// crates built since the caches have been refreshed.
            QueueInProgress(usize),
        }

        let mut status = BuilderState::Fresh;

        loop {
            if !status.is_in_progress() {
                thread::sleep(Duration::from_secs(60));
            }

            // check lock file
            if doc_builder.is_locked() {
                warn!("Lock file exits, skipping building new crates");
                status = BuilderState::Locked;
                continue;
            }

            if status.count() >= 10 {
                // periodically, we need to flush our caches and ping the hubs
                debug!("10 builds in a row; flushing caches");
                status = BuilderState::QueueInProgress(0);

                match pubsubhubbub::ping_hubs() {
                    Err(e) => error!("Failed to ping hub: {}", e),
                    Ok(n) => debug!("Succesfully pinged {} hubs", n)
                }

                if let Err(e) = doc_builder.load_cache() {
                    error!("Failed to load cache: {}", e);
                }

                if let Err(e) = doc_builder.save_cache() {
                    error!("Failed to save cache: {}", e);
                }

                if let Err(e) = update_sources() {
                    error!("Failed to update sources: {}", e);
                    continue;
                }
            }

            // Only build crates if there are any to build
            debug!("Checking build queue");
            match doc_builder.get_queue_count() {
                Err(e) => {
                    error!("Failed to read the number of crates in the queue: {}", e);
                    continue;
                }
                Ok(0) => {
                    if status.is_in_progress() {
                        // ping the hubs before continuing
                        match pubsubhubbub::ping_hubs() {
                            Err(e) => error!("Failed to ping hub: {}", e),
                            Ok(n) => debug!("Succesfully pinged {} hubs", n)
                        }

                        if let Err(e) = doc_builder.save_cache() {
                            error!("Failed to save cache: {}", e);
                        }
                    }
                    debug!("Queue is empty, going back to sleep");
                    status = BuilderState::EmptyQueue;
                    continue;
                }
                Ok(queue_count) => {
                    info!("Starting build with {} crates in queue (currently on a {} crate streak)",
                          queue_count, status.count());
                }
            }

            // if we're starting a new batch, reload our caches and sources
            if !status.is_in_progress() {
                if let Err(e) = doc_builder.load_cache() {
                    error!("Failed to load cache: {}", e);
                    continue;
                }

                if let Err(e) = update_sources() {
                    error!("Failed to update sources: {}", e);
                    continue;
                }
            }

            // Run build_packages_queue under `catch_unwind` to catch panics
            // This only panicked twice in the last 6 months but its just a better
            // idea to do this.
            let res = catch_unwind(AssertUnwindSafe(|| {
                match doc_builder.build_next_queue_package() {
                    Err(e) => error!("Failed to build crate from queue: {}", e),
                    Ok(crate_built) => if crate_built {
                        status.increment();
                    }

                }
            }));

            if let Err(e) = res {
                error!("GRAVE ERROR Building new crates panicked: {:?}", e);
            }
        }

        impl BuilderState {
            fn count(&self) -> usize {
                match *self {
                    BuilderState::QueueInProgress(n) => n,
                    _ => 0,
                }
            }

            fn is_in_progress(&self) -> bool {
                match *self {
                    BuilderState::QueueInProgress(_) => true,
                    _ => false,
                }
            }

            fn increment(&mut self) {
                *self = BuilderState::QueueInProgress(self.count() + 1);
            }
        }
    });

    // update release activity everyday at 23:55
    thread::spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60));
            let now = time::now();
            if now.tm_hour == 23 && now.tm_min == 55 {
                info!("Updating release activity");
                if let Err(e) = update_release_activity() {
                    error!("Failed to update release activity: {}", e);
                }
            }
        }
    });

    // update search index every 3 hours
    thread::spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60 * 60 * 3));
            let conn = connect_db().expect("Failed to connect database");
            if let Err(e) = update_search_index(&conn) {
                error!("Failed to update search index: {}", e);
            }
        }
    });

    // update github stats every 6 hours
    thread::spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60 * 60 * 6));
            if let Err(e) = github_updater() {
                error!("Failed to update github fields: {}", e);
            }
        }
    });

    // TODO: update ssl certificate every 3 months

    // at least start web server
    info!("Starting web server");
    ::start_web_server(None);
}

fn opts() -> DocBuilderOptions {
    let prefix = PathBuf::from(env::var("CRATESFYI_PREFIX")
        .expect("CRATESFYI_PREFIX environment variable not found"));
    DocBuilderOptions::from_prefix(prefix)
}
<|endoftext|>


<commit_before>use std::io::{stdout, stderr};
use std::path::Path;

use argparse::{ArgumentParser, Store, List};

use config::Config;
use super::config::find_config_or_exit;
use self::iptables::apply_graph;

mod graphs;
mod iptables;
mod run;

pub fn run(cmdline: Vec<String>) -> i32 {
    let mut kind = "".to_string();
    let mut args: Vec<String> = vec!();
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("
            Split the network into partitions.

            All kinds of network splits are idempotent and
            atomic. I.e. it operates on the whole network (in fact whole
            firewall table) and result is always the same regardless of
            previous operations. It also doesn't isolate containers from
            the bridge-namespaced nodes and from the internet.
            ");
        ap.refer(&mut kind)
            .add_argument("kind", Store, r#"
                Kind of partitioning to do:
                "disjoint" -- divide into few non-intersecting networks,
                "split" -- divide into graph of networks that may have some
                    'bridge' nodes,
                "isolate" -- isolate individual node(s) from anything and from
                    each other,
                "run" -- run arbitrary command in node's network namespaces
                    still being in same mount (filesystem) namespace.
                "#);
        ap.refer(&mut args)
            .add_argument("node", List, "
                A node(s) to operate on. See help of specific command
                for details
                ");
        ap.stop_on_first_argument(true);
        ap.silence_double_dash(false);
        match ap.parse(cmdline, &mut stdout(), &mut stderr()) {
            Ok(()) => {}
            Err(x) => return x,
        }
    }

    let (cfg, _) = find_config_or_exit(&Path::new("/work"), false);

    args.insert(0, format!("vagga_network {}", kind));
    match run_command(&cfg, kind, args) {
        Ok(()) => 0,
        Err(Ok(x)) => x,
        Err(Err(e)) => {
            error!("{}", e);
            1
        }
    }
}

pub fn run_command(cfg: &Config, kind: String, args: Vec<String>)
    -> Result<(), Result<i32, String>>
{
    let graph = match &kind[..] {
        "fullmesh" => graphs::full_mesh_cmd(&cfg, args)?,
        "disjoint" => graphs::disjoint_graph_cmd(&cfg, args)?,
        "split" => graphs::split_graph_cmd(&cfg, args)?,
        "isolate" => graphs::isolate_graph_cmd(&cfg, args)?,
        "run" => {
            run::run_command_cmd(&cfg, args)?;
            return Ok(());
        }
        _ => {
            return Err(Err(format!("Unknown command {}", kind)));
        }
    };
    apply_graph(graph).map_err(Err)?;
    Ok(())
}
<commit_msg>Add description of `vagga _network fullmesh` command<commit_after>use std::io::{stdout, stderr};
use std::path::Path;

use argparse::{ArgumentParser, Store, List};

use config::Config;
use super::config::find_config_or_exit;
use self::iptables::apply_graph;

mod graphs;
mod iptables;
mod run;

pub fn run(cmdline: Vec<String>) -> i32 {
    let mut kind = "".to_string();
    let mut args: Vec<String> = vec!();
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("
            Split the network into partitions.

            All kinds of network splits are idempotent and
            atomic. I.e. it operates on the whole network (in fact whole
            firewall table) and result is always the same regardless of
            previous operations. It also doesn't isolate containers from
            the bridge-namespaced nodes and from the internet.
            ");
        ap.refer(&mut kind)
            .add_argument("kind", Store, r#"
                Kind of partitioning to do:
                "disjoint" -- divide into few non-intersecting networks,
                "split" -- divide into graph of networks that may have some
                    'bridge' nodes,
                "isolate" -- isolate individual node(s) from anything and from
                    each other,
                "run" -- run arbitrary command in node's network namespaces
                    still being in same mount (filesystem) namespace,
                "fullmesh" -- restore network to full connectivity.
                "#);
        ap.refer(&mut args)
            .add_argument("node", List, "
                A node(s) to operate on. See help of specific command
                for details
                ");
        ap.stop_on_first_argument(true);
        ap.silence_double_dash(false);
        match ap.parse(cmdline, &mut stdout(), &mut stderr()) {
            Ok(()) => {}
            Err(x) => return x,
        }
    }

    let (cfg, _) = find_config_or_exit(&Path::new("/work"), false);

    args.insert(0, format!("vagga_network {}", kind));
    match run_command(&cfg, kind, args) {
        Ok(()) => 0,
        Err(Ok(x)) => x,
        Err(Err(e)) => {
            error!("{}", e);
            1
        }
    }
}

pub fn run_command(cfg: &Config, kind: String, args: Vec<String>)
    -> Result<(), Result<i32, String>>
{
    let graph = match &kind[..] {
        "fullmesh" => graphs::full_mesh_cmd(&cfg, args)?,
        "disjoint" => graphs::disjoint_graph_cmd(&cfg, args)?,
        "split" => graphs::split_graph_cmd(&cfg, args)?,
        "isolate" => graphs::isolate_graph_cmd(&cfg, args)?,
        "run" => {
            run::run_command_cmd(&cfg, args)?;
            return Ok(());
        }
        _ => {
            return Err(Err(format!("Unknown command {}", kind)));
        }
    };
    apply_graph(graph).map_err(Err)?;
    Ok(())
}
<|endoftext|>


<commit_before>use std::marker::ContravariantLifetime;
use std::mem;
use std::ptr;
use libc::c_ulong;

use objc::Id;
use objc::runtime::Object;

use INSObject;

pub struct NSEnumerator<'a, T> {
    id: Id<Object>,
    marker: ContravariantLifetime<'a>,
}

impl<'a, T> NSEnumerator<'a, T> where T: INSObject {
    pub unsafe fn from_ptr(ptr: *mut Object) -> NSEnumerator<'a, T> {
        NSEnumerator { id: Id::from_ptr(ptr), marker: ContravariantLifetime }
    }
}

impl<'a, T> Iterator for NSEnumerator<'a, T> where T: INSObject {
    type Item = &'a T;

    fn next(&mut self) -> Option<&'a T> {
        unsafe {
            let obj: *mut T = msg_send![self.id, nextObject];
            obj.as_ref()
        }
    }
}

pub trait INSFastEnumeration: INSObject {
    type Item: INSObject;

    fn enumerator(&self) -> NSFastEnumerator<Self> {
        NSFastEnumerator::new(self)
    }
}

#[repr(C)]
struct NSFastEnumerationState<T> {
    state: c_ulong,
    items_ptr: *const *const T,
    mutations_ptr: *mut c_ulong,
    extra: [c_ulong; 5],
}

const FAST_ENUM_BUF_SIZE: usize = 16;

pub struct NSFastEnumerator<'a, C: 'a + INSFastEnumeration> {
    object: &'a C,

    ptr: *const *const C::Item,
    end: *const *const C::Item,

    state: NSFastEnumerationState<C::Item>,
    buf: [*const C::Item; FAST_ENUM_BUF_SIZE],
}

impl<'a, C: INSFastEnumeration> NSFastEnumerator<'a, C> {
    fn new(object: &C) -> NSFastEnumerator<C> {
        NSFastEnumerator {
            object: object,

            ptr: ptr::null(),
            end: ptr::null(),

            state: unsafe { mem::zeroed() },
            buf: [ptr::null(); FAST_ENUM_BUF_SIZE],
        }
    }

    fn update_buf(&mut self) -> bool {
        // If this isn't our first time enumerating, record the previous value
        // from the mutations pointer.
        let mutations = if !self.ptr.is_null() {
            Some(unsafe { *self.state.mutations_ptr })
        } else {
            None
        };

        let count: usize = unsafe {
            msg_send![self.object, countByEnumeratingWithState:&mut self.state
                                                       objects:self.buf.as_mut_ptr()
                                                         count:self.buf.len()]
        };

        if count > 0 {
            // Check if the collection was mutated
            if let Some(mutations) = mutations {
                assert!(mutations == unsafe { *self.state.mutations_ptr },
                    "Mutation detected during enumeration of object {:?}",
                    self.object as *const C);
            }

            self.ptr = self.state.items_ptr;
            self.end = unsafe { self.ptr.offset(count as isize) };
            true
        } else {
            self.ptr = ptr::null();
            self.end = ptr::null();
            false
        }
    }
}

impl<'a, C: INSFastEnumeration> Iterator for NSFastEnumerator<'a, C> {
    type Item = &'a C::Item;

    fn next(&mut self) -> Option<&'a C::Item> {
        if self.ptr == self.end && !self.update_buf() {
            None
        } else {
            unsafe {
                let obj = *self.ptr;
                self.ptr = self.ptr.offset(1);
                Some(&*obj)
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use objc::Id;
    use {INSArray, INSValue, NSArray, NSValue};
    use super::INSFastEnumeration;

    #[test]
    fn test_enumerator() {
        let vec: Vec<Id<NSValue<u32>>> = (0..4).map(INSValue::from_value).collect();
        let array: Id<NSArray<_>> = INSArray::from_vec(vec);

        let enumerator = array.object_enumerator();
        assert!(enumerator.count() == 4);

        let enumerator = array.object_enumerator();
        assert!(enumerator.enumerate().all(|(i, obj)| obj.value() == i as u32));
    }

    #[test]
    fn test_fast_enumerator() {
        let vec: Vec<Id<NSValue<u32>>> = (0..4).map(INSValue::from_value).collect();
        let array: Id<NSArray<_>> = INSArray::from_vec(vec);

        let enumerator = array.enumerator();
        assert!(enumerator.count() == 4);

        let enumerator = array.enumerator();
        assert!(enumerator.enumerate().all(|(i, obj)| obj.value() == i as u32));
    }
}
<commit_msg>Extracted an enumerate function.<commit_after>use std::marker::ContravariantLifetime;
use std::mem;
use std::ptr;
use std::slice;
use libc::c_ulong;

use objc::Id;
use objc::runtime::Object;

use INSObject;

pub struct NSEnumerator<'a, T> {
    id: Id<Object>,
    marker: ContravariantLifetime<'a>,
}

impl<'a, T> NSEnumerator<'a, T> where T: INSObject {
    pub unsafe fn from_ptr(ptr: *mut Object) -> NSEnumerator<'a, T> {
        NSEnumerator { id: Id::from_ptr(ptr), marker: ContravariantLifetime }
    }
}

impl<'a, T> Iterator for NSEnumerator<'a, T> where T: INSObject {
    type Item = &'a T;

    fn next(&mut self) -> Option<&'a T> {
        unsafe {
            let obj: *mut T = msg_send![self.id, nextObject];
            obj.as_ref()
        }
    }
}

pub trait INSFastEnumeration: INSObject {
    type Item: INSObject;

    fn enumerator(&self) -> NSFastEnumerator<Self> {
        NSFastEnumerator::new(self)
    }
}

#[repr(C)]
struct NSFastEnumerationState<T> {
    state: c_ulong,
    items_ptr: *const *const T,
    mutations_ptr: *mut c_ulong,
    extra: [c_ulong; 5],
}

fn enumerate<'a, 'b: 'a, C: INSFastEnumeration>(object: &'b C,
        state: &mut NSFastEnumerationState<C::Item>,
        buf: &'a mut [*const C::Item]) -> Option<&'a [*const C::Item]> {
    let count: usize = unsafe {
        msg_send![object, countByEnumeratingWithState:state
                                              objects:buf.as_mut_ptr()
                                                count:buf.len()]
    };

    if count > 0 {
        unsafe { Some(slice::from_raw_parts(state.items_ptr, count)) }
    } else {
        None
    }
}

const FAST_ENUM_BUF_SIZE: usize = 16;

pub struct NSFastEnumerator<'a, C: 'a + INSFastEnumeration> {
    object: &'a C,

    ptr: *const *const C::Item,
    end: *const *const C::Item,

    state: NSFastEnumerationState<C::Item>,
    buf: [*const C::Item; FAST_ENUM_BUF_SIZE],
}

impl<'a, C: INSFastEnumeration> NSFastEnumerator<'a, C> {
    fn new(object: &C) -> NSFastEnumerator<C> {
        NSFastEnumerator {
            object: object,

            ptr: ptr::null(),
            end: ptr::null(),

            state: unsafe { mem::zeroed() },
            buf: [ptr::null(); FAST_ENUM_BUF_SIZE],
        }
    }

    fn update_buf(&mut self) -> bool {
        // If this isn't our first time enumerating, record the previous value
        // from the mutations pointer.
        let mutations = if !self.ptr.is_null() {
            Some(unsafe { *self.state.mutations_ptr })
        } else {
            None
        };

        let next_buf = enumerate(self.object, &mut self.state, &mut self.buf);
        if let Some(buf) = next_buf {
            // Check if the collection was mutated
            if let Some(mutations) = mutations {
                assert!(mutations == unsafe { *self.state.mutations_ptr },
                    "Mutation detected during enumeration of object {:?}",
                    self.object as *const C);
            }

            self.ptr = buf.as_ptr();
            self.end = unsafe { self.ptr.offset(buf.len() as isize) };
            true
        } else {
            self.ptr = ptr::null();
            self.end = ptr::null();
            false
        }
    }
}

impl<'a, C: INSFastEnumeration> Iterator for NSFastEnumerator<'a, C> {
    type Item = &'a C::Item;

    fn next(&mut self) -> Option<&'a C::Item> {
        if self.ptr == self.end && !self.update_buf() {
            None
        } else {
            unsafe {
                let obj = *self.ptr;
                self.ptr = self.ptr.offset(1);
                Some(&*obj)
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use objc::Id;
    use {INSArray, INSValue, NSArray, NSValue};
    use super::INSFastEnumeration;

    #[test]
    fn test_enumerator() {
        let vec: Vec<Id<NSValue<u32>>> = (0..4).map(INSValue::from_value).collect();
        let array: Id<NSArray<_>> = INSArray::from_vec(vec);

        let enumerator = array.object_enumerator();
        assert!(enumerator.count() == 4);

        let enumerator = array.object_enumerator();
        assert!(enumerator.enumerate().all(|(i, obj)| obj.value() == i as u32));
    }

    #[test]
    fn test_fast_enumerator() {
        let vec: Vec<Id<NSValue<u32>>> = (0..4).map(INSValue::from_value).collect();
        let array: Id<NSArray<_>> = INSArray::from_vec(vec);

        let enumerator = array.enumerator();
        assert!(enumerator.count() == 4);

        let enumerator = array.enumerator();
        assert!(enumerator.enumerate().all(|(i, obj)| obj.value() == i as u32));
    }
}
<|endoftext|>


<commit_before>use core::pin::Pin;
use futures_core::stream::TryStream;
use futures_core::task::{Context, Poll};
use futures_io::AsyncRead;
use std::cmp;
use std::io::{Error, Result};

/// An `AsyncRead` for the [`into_async_read`](super::TryStreamExt::into_async_read) combinator.
#[derive(Debug)]
#[must_use = "streams do nothing unless polled"]
pub struct IntoAsyncRead<St>
where
    St: TryStream<Error = Error> + Unpin,
    St::Ok: AsRef<[u8]>,
{
    stream: St,
    state: ReadState<St::Ok>,
}

impl<St> Unpin for IntoAsyncRead<St>
where
    St: TryStream<Error = Error> + Unpin,
    St::Ok: AsRef<[u8]>,
{
}

#[derive(Debug)]
enum ReadState<T: AsRef<[u8]>> {
    Ready { chunk: T, chunk_start: usize },
    PendingChunk,
    Eof,
}

impl<St> IntoAsyncRead<St>
where
    St: TryStream<Error = Error> + Unpin,
    St::Ok: AsRef<[u8]>,
{
    pub(super) fn new(stream: St) -> Self {
        IntoAsyncRead {
            stream,
            state: ReadState::PendingChunk,
        }
    }
}

impl<St> AsyncRead for IntoAsyncRead<St>
where
    St: TryStream<Error = Error> + Unpin,
    St::Ok: AsRef<[u8]>,
{
    fn poll_read(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut [u8],
    ) -> Poll<Result<usize>> {
        loop {
            match &mut self.state {
                ReadState::Ready { chunk, chunk_start } => {
                    let chunk = chunk.as_ref();
                    let len = cmp::min(buf.len(), chunk.len() - *chunk_start);

                    buf[..len].copy_from_slice(
                        &chunk[*chunk_start..*chunk_start + len],
                    );
                    *chunk_start += len;

                    if chunk.len() == *chunk_start {
                        self.state = ReadState::PendingChunk;
                    }

                    return Poll::Ready(Ok(len));
                }
                ReadState::PendingChunk => {
                    match ready!(Pin::new(&mut self.stream).try_poll_next(cx)) {
                        Some(Ok(chunk)) => {
                            self.state = ReadState::Ready {
                                chunk,
                                chunk_start: 0,
                            };
                            continue;
                        }
                        Some(Err(err)) => {
                            self.state = ReadState::Eof;
                            return Poll::Ready(Err(err));
                        }
                        None => {
                            self.state = ReadState::Eof;
                            return Poll::Ready(Ok(0));
                        }
                    }
                }
                ReadState::Eof => {
                    return Poll::Ready(Ok(0));
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use futures::stream::{self, StreamExt, TryStreamExt};
    use futures_io::AsyncRead;
    use futures_test::task::noop_context;

    macro_rules! assert_read {
        ($reader:expr, $buf:expr, $item:expr) => {
            let mut cx = noop_context();
            match Pin::new(&mut $reader).poll_read(&mut cx, $buf) {
                Poll::Ready(Ok(x)) => {
                    assert_eq!(x, $item);
                }
                Poll::Ready(Err(err)) => {
                    panic!("assertion failed: expected value but got {}", err);
                }
                Poll::Pending => {
                    panic!("assertion failed: reader was not ready");
                }
            }
        };
    }

    #[test]
    fn test_into_async_read() {
        let stream = stream::iter(1..=3).map(|_| Ok(vec![1, 2, 3, 4, 5]));
        let mut reader = stream.into_async_read();
        let mut buf = vec![0; 3];

        assert_read!(reader, &mut buf, 3);
        assert_eq!(&buf, &[1, 2, 3]);

        assert_read!(reader, &mut buf, 2);
        assert_eq!(&buf[..2], &[4, 5]);

        assert_read!(reader, &mut buf, 3);
        assert_eq!(&buf, &[1, 2, 3]);

        assert_read!(reader, &mut buf, 2);
        assert_eq!(&buf[..2], &[4, 5]);

        assert_read!(reader, &mut buf, 3);
        assert_eq!(&buf, &[1, 2, 3]);

        assert_read!(reader, &mut buf, 2);
        assert_eq!(&buf[..2], &[4, 5]);

        assert_read!(reader, &mut buf, 0);
    }
}
<commit_msg>Add AsyncBufRead implementation for IntoAsyncRead<commit_after>use core::pin::Pin;
use futures_core::stream::TryStream;
use futures_core::task::{Context, Poll};
use futures_io::{AsyncRead, AsyncBufRead};
use std::cmp;
use std::io::{Error, Result};

/// An `AsyncRead` for the [`into_async_read`](super::TryStreamExt::into_async_read) combinator.
#[derive(Debug)]
#[must_use = "streams do nothing unless polled"]
pub struct IntoAsyncRead<St>
where
    St: TryStream<Error = Error> + Unpin,
    St::Ok: AsRef<[u8]>,
{
    stream: St,
    state: ReadState<St::Ok>,
}

impl<St> Unpin for IntoAsyncRead<St>
where
    St: TryStream<Error = Error> + Unpin,
    St::Ok: AsRef<[u8]>,
{
}

#[derive(Debug)]
enum ReadState<T: AsRef<[u8]>> {
    Ready { chunk: T, chunk_start: usize },
    PendingChunk,
    Eof,
}

impl<St> IntoAsyncRead<St>
where
    St: TryStream<Error = Error> + Unpin,
    St::Ok: AsRef<[u8]>,
{
    pub(super) fn new(stream: St) -> Self {
        IntoAsyncRead {
            stream,
            state: ReadState::PendingChunk,
        }
    }
}

impl<St> AsyncRead for IntoAsyncRead<St>
where
    St: TryStream<Error = Error> + Unpin,
    St::Ok: AsRef<[u8]>,
{
    fn poll_read(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut [u8],
    ) -> Poll<Result<usize>> {
        loop {
            match &mut self.state {
                ReadState::Ready { chunk, chunk_start } => {
                    let chunk = chunk.as_ref();
                    let len = cmp::min(buf.len(), chunk.len() - *chunk_start);

                    buf[..len].copy_from_slice(
                        &chunk[*chunk_start..*chunk_start + len],
                    );
                    *chunk_start += len;

                    if chunk.len() == *chunk_start {
                        self.state = ReadState::PendingChunk;
                    }

                    return Poll::Ready(Ok(len));
                }
                ReadState::PendingChunk => {
                    match ready!(Pin::new(&mut self.stream).try_poll_next(cx)) {
                        Some(Ok(chunk)) => {
                            self.state = ReadState::Ready {
                                chunk,
                                chunk_start: 0,
                            };
                            continue;
                        }
                        Some(Err(err)) => {
                            self.state = ReadState::Eof;
                            return Poll::Ready(Err(err));
                        }
                        None => {
                            self.state = ReadState::Eof;
                            return Poll::Ready(Ok(0));
                        }
                    }
                }
                ReadState::Eof => {
                    return Poll::Ready(Ok(0));
                }
            }
        }
    }
}

impl<St> AsyncBufRead for IntoAsyncRead<St>
where
    St: TryStream<Error = Error> + Unpin,
    St::Ok: AsRef<[u8]>,
{
    fn poll_fill_buf<'a>(
        mut self: Pin<&'a mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Result<&'a [u8]>> {
        if let ReadState::PendingChunk = self.state {
            match ready!(Pin::new(&mut self.stream).try_poll_next(cx)) {
                Some(Ok(chunk)) => {
                    self.state = ReadState::Ready {
                        chunk,
                        chunk_start: 0,
                    };
                }
                Some(Err(err)) => {
                    self.state = ReadState::Eof;
                    return Poll::Ready(Err(err));
                }
                None => {
                    self.state = ReadState::Eof;
                    return Poll::Ready(Ok(&[]));
                }
            }
        }

        if let ReadState::Ready { ref chunk, chunk_start } = self.into_ref().get_ref().state {
            let chunk = chunk.as_ref();
            return Poll::Ready(Ok(&chunk[chunk_start..]));
        }

        // To get to this point we must be in ReadState::Eof
        Poll::Ready(Ok(&[]))
    }

    fn consume(
        mut self: Pin<&mut Self>,
        amount: usize,
    ) {
        if let ReadState::Ready { chunk, chunk_start } = &mut self.state {
            *chunk_start += amount;
            debug_assert!(*chunk_start <= chunk.as_ref().len());
            if *chunk_start >= chunk.as_ref().len() {
                self.state = ReadState::PendingChunk;
            }
        } else {
            debug_assert!(false, "Attempted to consume from IntoAsyncRead without chunk");
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use futures::stream::{self, StreamExt, TryStreamExt};
    use futures_io::AsyncRead;
    use futures_test::task::noop_context;

    macro_rules! assert_read {
        ($reader:expr, $buf:expr, $item:expr) => {
            let mut cx = noop_context();
            match Pin::new(&mut $reader).poll_read(&mut cx, $buf) {
                Poll::Ready(Ok(x)) => {
                    assert_eq!(x, $item);
                }
                Poll::Ready(Err(err)) => {
                    panic!("assertion failed: expected value but got {}", err);
                }
                Poll::Pending => {
                    panic!("assertion failed: reader was not ready");
                }
            }
        };
    }

    #[test]
    fn test_into_async_read() {
        let stream = stream::iter(1..=3).map(|_| Ok(vec![1, 2, 3, 4, 5]));
        let mut reader = stream.into_async_read();
        let mut buf = vec![0; 3];

        assert_read!(reader, &mut buf, 3);
        assert_eq!(&buf, &[1, 2, 3]);

        assert_read!(reader, &mut buf, 2);
        assert_eq!(&buf[..2], &[4, 5]);

        assert_read!(reader, &mut buf, 3);
        assert_eq!(&buf, &[1, 2, 3]);

        assert_read!(reader, &mut buf, 2);
        assert_eq!(&buf[..2], &[4, 5]);

        assert_read!(reader, &mut buf, 3);
        assert_eq!(&buf, &[1, 2, 3]);

        assert_read!(reader, &mut buf, 2);
        assert_eq!(&buf[..2], &[4, 5]);

        assert_read!(reader, &mut buf, 0);
    }

    #[test]
    fn test_into_async_bufread() -> std::io::Result<()> {
        let stream = stream::iter(1..=2).map(|_| Ok(vec![1, 2, 3, 4, 5]));
        let mut reader = stream.into_async_read();

        let mut cx = noop_context();
        let mut reader = Pin::new(&mut reader);

        assert_eq!(reader.as_mut().poll_fill_buf(&mut cx)?, Poll::Ready(&[1, 2, 3, 4, 5][..]));
        reader.as_mut().consume(3);

        assert_eq!(reader.as_mut().poll_fill_buf(&mut cx)?, Poll::Ready(&[4, 5][..]));
        reader.as_mut().consume(2);

        assert_eq!(reader.as_mut().poll_fill_buf(&mut cx)?, Poll::Ready(&[1, 2, 3, 4, 5][..]));
        reader.as_mut().consume(2);

        assert_eq!(reader.as_mut().poll_fill_buf(&mut cx)?, Poll::Ready(&[3, 4, 5][..]));
        reader.as_mut().consume(3);

        assert_eq!(reader.as_mut().poll_fill_buf(&mut cx)?, Poll::Ready(&[][..]));

        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::borrow::Borrow;
use std::cmp::min;
use std::io::Write;
use std::io;

use rustbox::{RustBox, Style, Color};

static LINEBREAK : char = '\\';

pub struct MsgArea {
    msgs   : Vec<Line>,

    width  : i32,
    height : i32,

    /// Vertical scroll
    scroll : i32,

    // TODO: logging
}

struct Line {
    /// A line. INVARIANT: Not longer than the width of the widget.
    msg : String,

    /// Is this continuation of previous line?
    continuation : bool,

    style : Style,
    fg : Color,
    bg : Color,
}

impl MsgArea {
    pub fn new(width : i32, height : i32) -> MsgArea {
        MsgArea {
            msgs: Vec::new(),
            width: width,
            height: height,
            scroll: 0,
        }
    }

    #[inline]
    pub fn add_msg_str(&mut self, msg_str : &str) {
        writeln!(&mut io::stderr(), "adding msg: {:?}", msg_str).unwrap();
        self.add_msg_str_(msg_str, Style::empty(), Color::Default, Color::Default);
    }

    #[inline]
    pub fn add_server_msg(&mut self, msg_str : &str) {
        writeln!(&mut io::stderr(), "adding msg: {:?}", msg_str).unwrap();
        self.add_msg_str_(msg_str, Style::empty(), Color::Yellow, Color::Default);
    }

    #[inline]
    pub fn add_err_msg_str(&mut self, msg_str : &str) {
        writeln!(&mut io::stderr(), "adding msg: {:?}", msg_str).unwrap();
        self.add_msg_str_(msg_str, Style::empty(), Color::White, Color::Red);
    }

    #[inline]
    pub fn add_msg(&mut self, msg : &Vec<char>) {
        self.add_msg_(msg, Style::empty(), Color::Default, Color::Default);
    }

    #[inline]
    pub fn add_err_msg(&mut self, msg : &Vec<char>) {
        self.add_msg_(msg, Style::empty(), Color::White, Color::Red);
    }

    pub fn draw(&self, rustbox : &RustBox, pos_x : i32, pos_y : i32) {
        let mut row = self.height - 1;
        let mut line_idx = min(self.scroll + self.height, self.msgs.len() as i32) - 1;
        while line_idx >= 0 && row >= 0 {
            let line = &self.msgs[line_idx as usize];

            if line.continuation {
                rustbox.print_char(pos_x as usize, (pos_y + row) as usize,
                                   line.style, line.fg, line.bg, LINEBREAK);
            }

            let pos_x = if line.continuation { pos_x + 1 } else { pos_x };

            rustbox.print(pos_x as usize, (pos_y + row) as usize,
                          line.style, line.fg, line.bg, &line.msg);

            row -= 1;
            line_idx -= 1;
        }
    }

    ////////////////////////////////////////////////////////////////////////////

    fn add_msg_str_(&mut self, msg : &str, style : Style, fg : Color, bg : Color) {
        // Take the fast path when number of bytes (which gives the max number
        // of characters possibly be in the string) is smaller than the width.
        if msg.len() <= self.width as usize {
            if self.need_to_scroll() {
                self.scroll += 1;
            }

            self.msgs.push(Line {
                msg: msg.to_owned(),
                continuation: false,
                style: style,
                fg: fg,
                bg: bg,
            });
        } else {
            // Need to split the lines, taking the slow path that uses an
            // intermediate vector.
            self.add_msg_(&msg.chars().collect(), style, fg, bg);
        }
    }

    fn add_msg_(&mut self, msg : &Vec<char>, style : Style, fg : Color, bg : Color) {
        let mut msg_slice : &[char] = msg.borrow();
        let mut lines : Vec<Line> = Vec::with_capacity(1);
        while msg_slice.len() != 0 {
            let first_line = lines.len() == 0;
            let split = if first_line { self.width } else { self.width - 1 };

            let (line, rest) = msg_slice.split_at(min(msg_slice.len(), split as usize));
            msg_slice = rest;

            lines.push(Line {
                msg: line.iter().cloned().collect(),
                continuation: !first_line,
                style: style,
                fg: fg,
                bg: bg,
            });
        }

        // We need to check the scroll before adding the messages, as the check
        // uses current scroll and number of messages.
        if self.need_to_scroll() {
            self.scroll += lines.len() as i32;
        }

        self.msgs.append(&mut lines);
    }

    ////////////////////////////////////////////////////////////////////////////

    pub fn scroll_up(&mut self) {
        if self.scroll > 0 {
            self.scroll -= 1;
        }
    }

    pub fn scroll_down(&mut self) {
        if (self.msgs.len() as i32) > self.scroll + self.height {
            self.scroll += 1;
        }
    }

    pub fn page_up(&mut self) {

    }

    pub fn page_down(&mut self) {

    }

    /// Do we need to scroll when adding a new message?
    #[inline]
    fn need_to_scroll(&self) -> bool {
        self.scroll + self.height == self.msgs.len() as i32
    }
}
<commit_msg>implement pgup/pgdn<commit_after>use std::borrow::Borrow;
use std::cmp::{max, min};
use std::io::Write;
use std::io;

use rustbox::{RustBox, Style, Color};

static LINEBREAK : char = '\\';

pub struct MsgArea {
    msgs   : Vec<Line>,

    width  : i32,
    height : i32,

    /// Vertical scroll
    scroll : i32,

    // TODO: logging
}

struct Line {
    /// A line. INVARIANT: Not longer than the width of the widget.
    msg : String,

    /// Is this continuation of previous line?
    continuation : bool,

    style : Style,
    fg : Color,
    bg : Color,
}

impl MsgArea {
    pub fn new(width : i32, height : i32) -> MsgArea {
        MsgArea {
            msgs: Vec::new(),
            width: width,
            height: height,
            scroll: 0,
        }
    }

    #[inline]
    pub fn add_msg_str(&mut self, msg_str : &str) {
        writeln!(&mut io::stderr(), "adding msg: {:?}", msg_str).unwrap();
        self.add_msg_str_(msg_str, Style::empty(), Color::Default, Color::Default);
    }

    #[inline]
    pub fn add_server_msg(&mut self, msg_str : &str) {
        writeln!(&mut io::stderr(), "adding msg: {:?}", msg_str).unwrap();
        self.add_msg_str_(msg_str, Style::empty(), Color::Yellow, Color::Default);
    }

    #[inline]
    pub fn add_err_msg_str(&mut self, msg_str : &str) {
        writeln!(&mut io::stderr(), "adding msg: {:?}", msg_str).unwrap();
        self.add_msg_str_(msg_str, Style::empty(), Color::White, Color::Red);
    }

    #[inline]
    pub fn add_msg(&mut self, msg : &Vec<char>) {
        self.add_msg_(msg, Style::empty(), Color::Default, Color::Default);
    }

    #[inline]
    pub fn add_err_msg(&mut self, msg : &Vec<char>) {
        self.add_msg_(msg, Style::empty(), Color::White, Color::Red);
    }

    pub fn draw(&self, rustbox : &RustBox, pos_x : i32, pos_y : i32) {
        let mut row = self.height - 1;
        let mut line_idx = min(self.scroll + self.height, self.msgs.len() as i32) - 1;
        while line_idx >= 0 && row >= 0 {
            let line = &self.msgs[line_idx as usize];

            if line.continuation {
                rustbox.print_char(pos_x as usize, (pos_y + row) as usize,
                                   line.style, line.fg, line.bg, LINEBREAK);
            }

            let pos_x = if line.continuation { pos_x + 1 } else { pos_x };

            rustbox.print(pos_x as usize, (pos_y + row) as usize,
                          line.style, line.fg, line.bg, &line.msg);

            row -= 1;
            line_idx -= 1;
        }
    }

    ////////////////////////////////////////////////////////////////////////////

    fn add_msg_str_(&mut self, msg : &str, style : Style, fg : Color, bg : Color) {
        // Take the fast path when number of bytes (which gives the max number
        // of characters possibly be in the string) is smaller than the width.
        if msg.len() <= self.width as usize {
            if self.need_to_scroll() {
                self.scroll += 1;
            }

            self.msgs.push(Line {
                msg: msg.to_owned(),
                continuation: false,
                style: style,
                fg: fg,
                bg: bg,
            });
        } else {
            // Need to split the lines, taking the slow path that uses an
            // intermediate vector.
            self.add_msg_(&msg.chars().collect(), style, fg, bg);
        }
    }

    fn add_msg_(&mut self, msg : &Vec<char>, style : Style, fg : Color, bg : Color) {
        let mut msg_slice : &[char] = msg.borrow();
        let mut lines : Vec<Line> = Vec::with_capacity(1);
        while msg_slice.len() != 0 {
            let first_line = lines.len() == 0;
            let split = if first_line { self.width } else { self.width - 1 };

            let (line, rest) = msg_slice.split_at(min(msg_slice.len(), split as usize));
            msg_slice = rest;

            lines.push(Line {
                msg: line.iter().cloned().collect(),
                continuation: !first_line,
                style: style,
                fg: fg,
                bg: bg,
            });
        }

        // We need to check the scroll before adding the messages, as the check
        // uses current scroll and number of messages.
        if self.need_to_scroll() {
            self.scroll += lines.len() as i32;
        }

        self.msgs.append(&mut lines);
    }

    ////////////////////////////////////////////////////////////////////////////

    pub fn scroll_up(&mut self) {
        if self.scroll > 0 {
            self.scroll -= 1;
        }
    }

    pub fn scroll_down(&mut self) {
        if (self.msgs.len() as i32) > self.scroll + self.height {
            self.scroll += 1;
        }
    }

    pub fn page_up(&mut self) {
        self.scroll = max(0, self.scroll - 10);
    }

    pub fn page_down(&mut self) {
        self.scroll = min(self.scroll + 10, (self.msgs.len() as i32) - self.height);
    }

    /// Do we need to scroll when adding a new message?
    #[inline]
    fn need_to_scroll(&self) -> bool {
        self.scroll + self.height == self.msgs.len() as i32
    }
}
<|endoftext|>


<commit_before>
use prelude::*;

use fixedbitset::FixedBitSet;
use std::collections::HashSet;
use std::marker::PhantomData;

use visit::{
    GraphBase,
    GraphProp,
    IntoEdgeReferences,
    IntoEdges,
    IntoEdgesDirected,
    IntoNeighbors,
    IntoNeighborsDirected,
    IntoNodeIdentifiers,
    IntoNodeReferences,
    NodeIndexable,
    NodeRef,
    VisitMap,
    Visitable,
};
use visit::{Data, NodeCompactIndexable, NodeCount};
use data::{DataMap};

/// A graph filter for nodes.
pub trait FilterNode<N>
{
    /// Return true to have the node be part of the graph
    fn include_node(&self, node: N) -> bool;
}

impl<F, N> FilterNode<N> for F
    where F: Fn(N) -> bool,
{
    fn include_node(&self, n: N) -> bool {
        (*self)(n)
    }
}

/// This filter includes the nodes that are contained in the set.
impl<N> FilterNode<N> for FixedBitSet
    where FixedBitSet: VisitMap<N>,
{
    fn include_node(&self, n: N) -> bool {
        self.is_visited(&n)
    }
}

/// This filter includes the nodes that are contained in the set.
impl<N, S> FilterNode<N> for HashSet<N, S>
    where HashSet<N, S>: VisitMap<N>,
{
    fn include_node(&self, n: N) -> bool {
        self.is_visited(&n)
    }
}

/// A node-filtering graph adaptor.
#[derive(Copy, Clone, Debug)]
pub struct NodeFiltered<G, F>(pub G, pub F);

impl<F, G> NodeFiltered<G, F>
    where G: GraphBase,
          F: Fn(G::NodeId) -> bool,
{
    /// Create an `NodeFiltered` adaptor from the closure `filter`.
    pub fn from_fn(graph: G, filter: F) -> Self {
        NodeFiltered(graph, filter)
    }
}

impl<G, F> GraphBase for NodeFiltered<G, F> where G: GraphBase {
    type NodeId = G::NodeId;
    type EdgeId = G::EdgeId;
}

impl<'a, G, F> IntoNeighbors for &'a NodeFiltered<G, F>
    where G: IntoNeighbors,
          F: FilterNode<G::NodeId>,
{
    type Neighbors = NodeFilteredNeighbors<'a, G::Neighbors, F>;
    fn neighbors(self, n: G::NodeId) -> Self::Neighbors {
        NodeFilteredNeighbors {
            include_source: self.1.include_node(n),
            iter: self.0.neighbors(n),
            f: &self.1,
        }
    }
}

/// A filtered neighbors iterator.
pub struct NodeFilteredNeighbors<'a, I, F: 'a>
{
    include_source: bool,
    iter: I,
    f: &'a F,
}

impl<'a, I, F> Iterator for NodeFilteredNeighbors<'a, I, F>
    where I: Iterator,
          I::Item: Copy,
          F: FilterNode<I::Item>,
{
    type Item = I::Item;
    fn next(&mut self) -> Option<Self::Item> {
        let f = self.f;
        if !self.include_source {
            None
        } else {
            self.iter.find(move |&target| f.include_node(target))
        }
    }
}

impl<'a, G, F> IntoNeighborsDirected for &'a NodeFiltered<G, F>
    where G: IntoNeighborsDirected,
          F: FilterNode<G::NodeId>,
{
    type NeighborsDirected = NodeFilteredNeighbors<'a, G::NeighborsDirected, F>;
    fn neighbors_directed(self, n: G::NodeId, dir: Direction)
        -> Self::NeighborsDirected {
        NodeFilteredNeighbors {
            include_source: self.1.include_node(n),
            iter: self.0.neighbors_directed(n, dir),
            f: &self.1,
        }
    }
}

impl<'a, G, F> IntoNodeIdentifiers for &'a NodeFiltered<G, F>
    where G: IntoNodeIdentifiers,
          F: FilterNode<G::NodeId>,
{
    type NodeIdentifiers = NodeFilteredNeighbors<'a, G::NodeIdentifiers, F>;
    fn node_identifiers(self) -> Self::NodeIdentifiers {
        NodeFilteredNeighbors {
            include_source: true,
            iter: self.0.node_identifiers(),
            f: &self.1,
        }
    }
}

impl<'a, G, F> IntoNodeReferences for &'a NodeFiltered<G, F>
    where G: IntoNodeReferences,
          F: FilterNode<G::NodeId>,
{
    type NodeRef = G::NodeRef;
    type NodeReferences = NodeFilteredNodes<'a, G::NodeReferences, F>;
    fn node_references(self) -> Self::NodeReferences {
        NodeFilteredNodes {
            include_source: true,
            iter: self.0.node_references(),
            f: &self.1,
        }
    }
}

/// A filtered node references iterator.
pub struct NodeFilteredNodes<'a, I, F: 'a>
{
    include_source: bool,
    iter: I,
    f: &'a F,
}

impl<'a, I, F> Iterator for NodeFilteredNodes<'a, I, F>
    where I: Iterator,
          I::Item: Copy + NodeRef,
          F: FilterNode<<I::Item as NodeRef>::NodeId>,
{
    type Item = I::Item;
    fn next(&mut self) -> Option<Self::Item> {
        let f = self.f;
        if !self.include_source {
            None
        } else {
            self.iter.find(move |&target| f.include_node(target.id()))
        }
    }
}

impl<'a, G, F> IntoEdgeReferences for &'a NodeFiltered<G, F>
    where G: IntoEdgeReferences,
          F: FilterNode<G::NodeId>,
{
    type EdgeRef = G::EdgeRef;
    type EdgeReferences = NodeFilteredEdgeReferences<'a, G, G::EdgeReferences, F>;
    fn edge_references(self) -> Self::EdgeReferences {
        NodeFilteredEdgeReferences {
            graph: PhantomData,
            iter: self.0.edge_references(),
            f: &self.1,
        }
    }
}

/// A filtered edges iterator.
pub struct NodeFilteredEdgeReferences<'a, G, I, F: 'a>
{
    graph: PhantomData<G>,
    iter: I,
    f: &'a F,
}

impl<'a, G, I, F> Iterator for NodeFilteredEdgeReferences<'a, G, I, F>
    where F: FilterNode<G::NodeId>,
          G: IntoEdgeReferences,
          I: Iterator<Item=G::EdgeRef>,
{
    type Item = I::Item;
    fn next(&mut self) -> Option<Self::Item> {
        let f = self.f;
        self.iter.find(move |&edge| f.include_node(edge.source()) &&
                                    f.include_node(edge.target()))
    }
}

impl<'a, G, F> IntoEdges for &'a NodeFiltered<G, F>
    where G: IntoEdges,
          F: FilterNode<G::NodeId>,
{
    type Edges = NodeFilteredEdges<'a, G, G::Edges, F>;
    fn edges(self, a: G::NodeId) -> Self::Edges {
        NodeFilteredEdges {
            graph: PhantomData,
            include_source: self.1.include_node(a),
            iter: self.0.edges(a),
            f: &self.1,
        }
    }
}

/// A filtered edges iterator.
pub struct NodeFilteredEdges<'a, G, I, F: 'a>
{
    graph: PhantomData<G>,
    include_source: bool,
    iter: I,
    f: &'a F,
}

impl<'a, G, I, F> Iterator for NodeFilteredEdges<'a, G, I, F>
    where F: FilterNode<G::NodeId>,
          G: IntoEdges,
          I: Iterator<Item=G::EdgeRef>,
{
    type Item = I::Item;
    fn next(&mut self) -> Option<Self::Item> {
        if !self.include_source {
            None
        } else {
            let f = self.f;
            self.iter.find(move |&edge| f.include_node(edge.target()))
        }
    }
}

impl<G, F> DataMap for NodeFiltered<G, F>
    where G: DataMap,
          F: FilterNode<G::NodeId>,
{
    fn node_weight(&self, id: Self::NodeId) -> Option<&Self::NodeWeight> {
        if self.1.include_node(id) {
            self.0.node_weight(id)
        } else {
            None
        }
    }

    fn edge_weight(&self, id: Self::EdgeId) -> Option<&Self::EdgeWeight> {
        self.0.edge_weight(id)
    }
}

macro_rules! access0 {
    ($e:expr) => ($e.0)
}

Data!{delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}
NodeIndexable!{delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}
GraphProp!{delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}
Visitable!{delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}

/// A graph filter for edges
pub trait FilterEdge<Edge> {
    /// Return true to have the edge be part of the graph
    fn include_edge(&self, edge: Edge) -> bool;
}

impl<F, N> FilterEdge<N> for F
    where F: Fn(N) -> bool,
{
    fn include_edge(&self, n: N) -> bool {
        (*self)(n)
    }
}

/// An edge-filtering graph adaptor.
///
/// The adaptor may filter out edges. The filter implements the trait
/// `FilterEdge`. Closures of type `Fn(G::EdgeRef) -> bool` already
/// implement this trait.
///
/// The filter may use edge source, target, id, and weight to select whether to
/// include the edge or not.
#[derive(Copy, Clone, Debug)]
pub struct EdgeFiltered<G, F>(pub G, pub F);

impl<F, G> EdgeFiltered<G, F>
    where G: IntoEdgeReferences,
          F: Fn(G::EdgeRef) -> bool,
{
    /// Create an `EdgeFiltered` adaptor from the closure `filter`.
    pub fn from_fn(graph: G, filter: F) -> Self {
        EdgeFiltered(graph, filter)
    }
}

impl<G, F> GraphBase for EdgeFiltered<G, F> where G: GraphBase {
    type NodeId = G::NodeId;
    type EdgeId = G::EdgeId;
}

impl<'a, G, F> IntoNeighbors for &'a EdgeFiltered<G, F>
    where G: IntoEdges,
          F: FilterEdge<G::EdgeRef>,
{
    type Neighbors = EdgeFilteredNeighbors<'a, G, F>;
    fn neighbors(self, n: G::NodeId) -> Self::Neighbors {
        EdgeFilteredNeighbors {
            iter: self.0.edges(n),
            f: &self.1,
        }
    }
}

impl<'a, G, F> IntoNeighborsDirected for &'a EdgeFiltered<G, F>
where
    G: IntoEdgesDirected,
    F: FilterEdge<G::EdgeRef>,
{
    type NeighborsDirected = EdgeFilteredNeighborsDirected<'a, G, F>;
    fn neighbors_directed(self, n: G::NodeId, dir: Direction) -> Self::NeighborsDirected {
        EdgeFilteredNeighborsDirected {
            iter: self.0.edges_directed(n, dir),
            f: &self.1,
            dir: dir,
            from: n,
        }
    }
}

/// A filtered neighbors iterator.
pub struct EdgeFilteredNeighbors<'a, G, F: 'a>
    where G: IntoEdges,
{
    iter: G::Edges,
    f: &'a F,
}

impl<'a, G, F> Iterator for EdgeFilteredNeighbors<'a, G, F>
    where F: FilterEdge<G::EdgeRef>,
          G: IntoEdges,
{
    type Item = G::NodeId;
    fn next(&mut self) -> Option<Self::Item> {
        let f = self.f;
        (&mut self.iter).filter_map(move |edge| {
            if f.include_edge(edge) {
                Some(edge.target())
            } else { None }
        }).next()
    }
}

impl<'a, G, F> IntoEdgeReferences for &'a EdgeFiltered<G, F>
    where G: IntoEdgeReferences,
          F: FilterEdge<G::EdgeRef>,
{
    type EdgeRef = G::EdgeRef;
    type EdgeReferences = EdgeFilteredEdges<'a, G, G::EdgeReferences, F>;
    fn edge_references(self) -> Self::EdgeReferences {
        EdgeFilteredEdges {
            graph: PhantomData,
            iter: self.0.edge_references(),
            f: &self.1,
        }
    }
}

impl<'a, G, F> IntoEdges for &'a EdgeFiltered<G, F>
    where G: IntoEdges,
          F: FilterEdge<G::EdgeRef>,
{
    type Edges = EdgeFilteredEdges<'a, G, G::Edges, F>;
    fn edges(self, n: G::NodeId) -> Self::Edges {
        EdgeFilteredEdges {
            graph: PhantomData,
            iter: self.0.edges(n),
            f: &self.1,
        }
    }
}

/// A filtered edges iterator.
pub struct EdgeFilteredEdges<'a, G, I, F: 'a>
{
    graph: PhantomData<G>,
    iter: I,
    f: &'a F,
}

impl<'a, G, I, F> Iterator for EdgeFilteredEdges<'a, G, I, F>
    where F: FilterEdge<G::EdgeRef>,
          G: IntoEdgeReferences,
          I: Iterator<Item=G::EdgeRef>,
{
    type Item = I::Item;
    fn next(&mut self) -> Option<Self::Item> {
        let f = self.f;
        self.iter.find(move |&edge| f.include_edge(edge))
    }
}

/// A filtered neighbors-directed iterator.
pub struct EdgeFilteredNeighborsDirected<'a, G, F: 'a>
where
    G: IntoEdgesDirected,
{
    iter: G::EdgesDirected,
    f: &'a F,
    dir: Direction,
    from: G::NodeId,
}

impl<'a, G, F> Iterator for EdgeFilteredNeighborsDirected<'a, G, F>
where
    F: FilterEdge<G::EdgeRef>,
    G: IntoEdgesDirected,
{
    type Item = G::NodeId;
    fn next(&mut self) -> Option<Self::Item> {
        let f = self.f;
        let dir = self.dir;
        let from = self.from;
        (&mut self.iter)
            .filter_map(move |edge| {
                if f.include_edge(edge) {
                    if edge.source() != from {
                        Some(edge.source())
                    } else if edge.target() != from {
                        Some(edge.target())
                    } else {
                        // source == target
                        Some(from)
                    }
                } else {
                    None
                }
            })
            .next()
    }
}

Data!{delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
GraphProp!{delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
IntoNodeIdentifiers!{delegate_impl [['a, G, F], G, &'a EdgeFiltered<G, F>, access0]}
IntoNodeReferences!{delegate_impl [['a, G, F], G, &'a EdgeFiltered<G, F>, access0]}
NodeCompactIndexable!{delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
NodeCount!{delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
NodeIndexable!{delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
Visitable!{delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
<commit_msg>FIX: Simplify code in EdgeFilteredNeighborsDirected<commit_after>
use prelude::*;

use fixedbitset::FixedBitSet;
use std::collections::HashSet;
use std::marker::PhantomData;

use visit::{
    GraphBase,
    GraphProp,
    IntoEdgeReferences,
    IntoEdges,
    IntoEdgesDirected,
    IntoNeighbors,
    IntoNeighborsDirected,
    IntoNodeIdentifiers,
    IntoNodeReferences,
    NodeIndexable,
    NodeRef,
    VisitMap,
    Visitable,
};
use visit::{Data, NodeCompactIndexable, NodeCount};
use data::{DataMap};

/// A graph filter for nodes.
pub trait FilterNode<N>
{
    /// Return true to have the node be part of the graph
    fn include_node(&self, node: N) -> bool;
}

impl<F, N> FilterNode<N> for F
    where F: Fn(N) -> bool,
{
    fn include_node(&self, n: N) -> bool {
        (*self)(n)
    }
}

/// This filter includes the nodes that are contained in the set.
impl<N> FilterNode<N> for FixedBitSet
    where FixedBitSet: VisitMap<N>,
{
    fn include_node(&self, n: N) -> bool {
        self.is_visited(&n)
    }
}

/// This filter includes the nodes that are contained in the set.
impl<N, S> FilterNode<N> for HashSet<N, S>
    where HashSet<N, S>: VisitMap<N>,
{
    fn include_node(&self, n: N) -> bool {
        self.is_visited(&n)
    }
}

/// A node-filtering graph adaptor.
#[derive(Copy, Clone, Debug)]
pub struct NodeFiltered<G, F>(pub G, pub F);

impl<F, G> NodeFiltered<G, F>
    where G: GraphBase,
          F: Fn(G::NodeId) -> bool,
{
    /// Create an `NodeFiltered` adaptor from the closure `filter`.
    pub fn from_fn(graph: G, filter: F) -> Self {
        NodeFiltered(graph, filter)
    }
}

impl<G, F> GraphBase for NodeFiltered<G, F> where G: GraphBase {
    type NodeId = G::NodeId;
    type EdgeId = G::EdgeId;
}

impl<'a, G, F> IntoNeighbors for &'a NodeFiltered<G, F>
    where G: IntoNeighbors,
          F: FilterNode<G::NodeId>,
{
    type Neighbors = NodeFilteredNeighbors<'a, G::Neighbors, F>;
    fn neighbors(self, n: G::NodeId) -> Self::Neighbors {
        NodeFilteredNeighbors {
            include_source: self.1.include_node(n),
            iter: self.0.neighbors(n),
            f: &self.1,
        }
    }
}

/// A filtered neighbors iterator.
pub struct NodeFilteredNeighbors<'a, I, F: 'a>
{
    include_source: bool,
    iter: I,
    f: &'a F,
}

impl<'a, I, F> Iterator for NodeFilteredNeighbors<'a, I, F>
    where I: Iterator,
          I::Item: Copy,
          F: FilterNode<I::Item>,
{
    type Item = I::Item;
    fn next(&mut self) -> Option<Self::Item> {
        let f = self.f;
        if !self.include_source {
            None
        } else {
            self.iter.find(move |&target| f.include_node(target))
        }
    }
}

impl<'a, G, F> IntoNeighborsDirected for &'a NodeFiltered<G, F>
    where G: IntoNeighborsDirected,
          F: FilterNode<G::NodeId>,
{
    type NeighborsDirected = NodeFilteredNeighbors<'a, G::NeighborsDirected, F>;
    fn neighbors_directed(self, n: G::NodeId, dir: Direction)
        -> Self::NeighborsDirected {
        NodeFilteredNeighbors {
            include_source: self.1.include_node(n),
            iter: self.0.neighbors_directed(n, dir),
            f: &self.1,
        }
    }
}

impl<'a, G, F> IntoNodeIdentifiers for &'a NodeFiltered<G, F>
    where G: IntoNodeIdentifiers,
          F: FilterNode<G::NodeId>,
{
    type NodeIdentifiers = NodeFilteredNeighbors<'a, G::NodeIdentifiers, F>;
    fn node_identifiers(self) -> Self::NodeIdentifiers {
        NodeFilteredNeighbors {
            include_source: true,
            iter: self.0.node_identifiers(),
            f: &self.1,
        }
    }
}

impl<'a, G, F> IntoNodeReferences for &'a NodeFiltered<G, F>
    where G: IntoNodeReferences,
          F: FilterNode<G::NodeId>,
{
    type NodeRef = G::NodeRef;
    type NodeReferences = NodeFilteredNodes<'a, G::NodeReferences, F>;
    fn node_references(self) -> Self::NodeReferences {
        NodeFilteredNodes {
            include_source: true,
            iter: self.0.node_references(),
            f: &self.1,
        }
    }
}

/// A filtered node references iterator.
pub struct NodeFilteredNodes<'a, I, F: 'a>
{
    include_source: bool,
    iter: I,
    f: &'a F,
}

impl<'a, I, F> Iterator for NodeFilteredNodes<'a, I, F>
    where I: Iterator,
          I::Item: Copy + NodeRef,
          F: FilterNode<<I::Item as NodeRef>::NodeId>,
{
    type Item = I::Item;
    fn next(&mut self) -> Option<Self::Item> {
        let f = self.f;
        if !self.include_source {
            None
        } else {
            self.iter.find(move |&target| f.include_node(target.id()))
        }
    }
}

impl<'a, G, F> IntoEdgeReferences for &'a NodeFiltered<G, F>
    where G: IntoEdgeReferences,
          F: FilterNode<G::NodeId>,
{
    type EdgeRef = G::EdgeRef;
    type EdgeReferences = NodeFilteredEdgeReferences<'a, G, G::EdgeReferences, F>;
    fn edge_references(self) -> Self::EdgeReferences {
        NodeFilteredEdgeReferences {
            graph: PhantomData,
            iter: self.0.edge_references(),
            f: &self.1,
        }
    }
}

/// A filtered edges iterator.
pub struct NodeFilteredEdgeReferences<'a, G, I, F: 'a>
{
    graph: PhantomData<G>,
    iter: I,
    f: &'a F,
}

impl<'a, G, I, F> Iterator for NodeFilteredEdgeReferences<'a, G, I, F>
    where F: FilterNode<G::NodeId>,
          G: IntoEdgeReferences,
          I: Iterator<Item=G::EdgeRef>,
{
    type Item = I::Item;
    fn next(&mut self) -> Option<Self::Item> {
        let f = self.f;
        self.iter.find(move |&edge| f.include_node(edge.source()) &&
                                    f.include_node(edge.target()))
    }
}

impl<'a, G, F> IntoEdges for &'a NodeFiltered<G, F>
    where G: IntoEdges,
          F: FilterNode<G::NodeId>,
{
    type Edges = NodeFilteredEdges<'a, G, G::Edges, F>;
    fn edges(self, a: G::NodeId) -> Self::Edges {
        NodeFilteredEdges {
            graph: PhantomData,
            include_source: self.1.include_node(a),
            iter: self.0.edges(a),
            f: &self.1,
        }
    }
}

/// A filtered edges iterator.
pub struct NodeFilteredEdges<'a, G, I, F: 'a>
{
    graph: PhantomData<G>,
    include_source: bool,
    iter: I,
    f: &'a F,
}

impl<'a, G, I, F> Iterator for NodeFilteredEdges<'a, G, I, F>
    where F: FilterNode<G::NodeId>,
          G: IntoEdges,
          I: Iterator<Item=G::EdgeRef>,
{
    type Item = I::Item;
    fn next(&mut self) -> Option<Self::Item> {
        if !self.include_source {
            None
        } else {
            let f = self.f;
            self.iter.find(move |&edge| f.include_node(edge.target()))
        }
    }
}

impl<G, F> DataMap for NodeFiltered<G, F>
    where G: DataMap,
          F: FilterNode<G::NodeId>,
{
    fn node_weight(&self, id: Self::NodeId) -> Option<&Self::NodeWeight> {
        if self.1.include_node(id) {
            self.0.node_weight(id)
        } else {
            None
        }
    }

    fn edge_weight(&self, id: Self::EdgeId) -> Option<&Self::EdgeWeight> {
        self.0.edge_weight(id)
    }
}

macro_rules! access0 {
    ($e:expr) => ($e.0)
}

Data!{delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}
NodeIndexable!{delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}
GraphProp!{delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}
Visitable!{delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}

/// A graph filter for edges
pub trait FilterEdge<Edge> {
    /// Return true to have the edge be part of the graph
    fn include_edge(&self, edge: Edge) -> bool;
}

impl<F, N> FilterEdge<N> for F
    where F: Fn(N) -> bool,
{
    fn include_edge(&self, n: N) -> bool {
        (*self)(n)
    }
}

/// An edge-filtering graph adaptor.
///
/// The adaptor may filter out edges. The filter implements the trait
/// `FilterEdge`. Closures of type `Fn(G::EdgeRef) -> bool` already
/// implement this trait.
///
/// The filter may use edge source, target, id, and weight to select whether to
/// include the edge or not.
#[derive(Copy, Clone, Debug)]
pub struct EdgeFiltered<G, F>(pub G, pub F);

impl<F, G> EdgeFiltered<G, F>
    where G: IntoEdgeReferences,
          F: Fn(G::EdgeRef) -> bool,
{
    /// Create an `EdgeFiltered` adaptor from the closure `filter`.
    pub fn from_fn(graph: G, filter: F) -> Self {
        EdgeFiltered(graph, filter)
    }
}

impl<G, F> GraphBase for EdgeFiltered<G, F> where G: GraphBase {
    type NodeId = G::NodeId;
    type EdgeId = G::EdgeId;
}

impl<'a, G, F> IntoNeighbors for &'a EdgeFiltered<G, F>
    where G: IntoEdges,
          F: FilterEdge<G::EdgeRef>,
{
    type Neighbors = EdgeFilteredNeighbors<'a, G, F>;
    fn neighbors(self, n: G::NodeId) -> Self::Neighbors {
        EdgeFilteredNeighbors {
            iter: self.0.edges(n),
            f: &self.1,
        }
    }
}

impl<'a, G, F> IntoNeighborsDirected for &'a EdgeFiltered<G, F>
where
    G: IntoEdgesDirected,
    F: FilterEdge<G::EdgeRef>,
{
    type NeighborsDirected = EdgeFilteredNeighborsDirected<'a, G, F>;
    fn neighbors_directed(self, n: G::NodeId, dir: Direction) -> Self::NeighborsDirected {
        EdgeFilteredNeighborsDirected {
            iter: self.0.edges_directed(n, dir),
            f: &self.1,
            from: n,
        }
    }
}

/// A filtered neighbors iterator.
pub struct EdgeFilteredNeighbors<'a, G, F: 'a>
    where G: IntoEdges,
{
    iter: G::Edges,
    f: &'a F,
}

impl<'a, G, F> Iterator for EdgeFilteredNeighbors<'a, G, F>
    where F: FilterEdge<G::EdgeRef>,
          G: IntoEdges,
{
    type Item = G::NodeId;
    fn next(&mut self) -> Option<Self::Item> {
        let f = self.f;
        (&mut self.iter).filter_map(move |edge| {
            if f.include_edge(edge) {
                Some(edge.target())
            } else { None }
        }).next()
    }
}

impl<'a, G, F> IntoEdgeReferences for &'a EdgeFiltered<G, F>
    where G: IntoEdgeReferences,
          F: FilterEdge<G::EdgeRef>,
{
    type EdgeRef = G::EdgeRef;
    type EdgeReferences = EdgeFilteredEdges<'a, G, G::EdgeReferences, F>;
    fn edge_references(self) -> Self::EdgeReferences {
        EdgeFilteredEdges {
            graph: PhantomData,
            iter: self.0.edge_references(),
            f: &self.1,
        }
    }
}

impl<'a, G, F> IntoEdges for &'a EdgeFiltered<G, F>
    where G: IntoEdges,
          F: FilterEdge<G::EdgeRef>,
{
    type Edges = EdgeFilteredEdges<'a, G, G::Edges, F>;
    fn edges(self, n: G::NodeId) -> Self::Edges {
        EdgeFilteredEdges {
            graph: PhantomData,
            iter: self.0.edges(n),
            f: &self.1,
        }
    }
}

/// A filtered edges iterator.
pub struct EdgeFilteredEdges<'a, G, I, F: 'a>
{
    graph: PhantomData<G>,
    iter: I,
    f: &'a F,
}

impl<'a, G, I, F> Iterator for EdgeFilteredEdges<'a, G, I, F>
    where F: FilterEdge<G::EdgeRef>,
          G: IntoEdgeReferences,
          I: Iterator<Item=G::EdgeRef>,
{
    type Item = I::Item;
    fn next(&mut self) -> Option<Self::Item> {
        let f = self.f;
        self.iter.find(move |&edge| f.include_edge(edge))
    }
}

/// A filtered neighbors-directed iterator.
pub struct EdgeFilteredNeighborsDirected<'a, G, F: 'a>
where
    G: IntoEdgesDirected,
{
    iter: G::EdgesDirected,
    f: &'a F,
    from: G::NodeId,
}

impl<'a, G, F> Iterator for EdgeFilteredNeighborsDirected<'a, G, F>
where
    F: FilterEdge<G::EdgeRef>,
    G: IntoEdgesDirected,
{
    type Item = G::NodeId;
    fn next(&mut self) -> Option<Self::Item> {
        let f = self.f;
        let from = self.from;
        (&mut self.iter)
            .filter_map(move |edge| {
                if f.include_edge(edge) {
                    if edge.source() != from {
                        Some(edge.source())
                    } else {
                        Some(edge.target()) // includes case where from == source == target
                    }
                } else {
                    None
                }
            })
            .next()
    }
}

Data!{delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
GraphProp!{delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
IntoNodeIdentifiers!{delegate_impl [['a, G, F], G, &'a EdgeFiltered<G, F>, access0]}
IntoNodeReferences!{delegate_impl [['a, G, F], G, &'a EdgeFiltered<G, F>, access0]}
NodeCompactIndexable!{delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
NodeCount!{delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
NodeIndexable!{delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
Visitable!{delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
<|endoftext|>


<commit_before>//! Receive and decode voice header packets.

use collect_slice::CollectSlice;

use bits::{Dibit, Hexbit, HexbitBytes};
use buffer::{Buffer, VoiceHeaderWordStorage, VoiceHeaderStorage};
use coding::{reed_solomon, golay};
use consts::HEADER_BYTES;
use error::Result;
use stats::{Stats, HasStats};
use trunking::fields::TalkGroup;
use util::slice_u16;
use voice::crypto::CryptoAlgorithm;

use error::P25Error::*;

/// State machine for receiving a voice header packet.
pub struct VoiceHeaderReceiver {
    /// Current buffered dibits for the current hexbit.
    dibits: Buffer<VoiceHeaderWordStorage>,
    /// Current buffered hexbits.
    hexbits: Buffer<VoiceHeaderStorage>,
    stats: Stats,
}

impl HasStats for VoiceHeaderReceiver {
    fn stats(&mut self) -> &mut Stats { &mut self.stats }
}

impl VoiceHeaderReceiver {
    /// Create a new `VoiceHeaderReceiver` in the initial state.
    pub fn new() -> VoiceHeaderReceiver {
        VoiceHeaderReceiver {
            dibits: Buffer::new(VoiceHeaderWordStorage::new()),
            hexbits: Buffer::new(VoiceHeaderStorage::new()),
            stats: Stats::default(),
        }
    }

    /// Feed in a baseband symbol, possibly producing a voice header packet. Return
    /// `Some(Ok(pkt))` if the packet was successfully received, `Some(Err(err))` if an
    /// error occurred, and `None` in the case of no event.
    pub fn feed(&mut self, dibit: Dibit) -> Option<Result<VoiceHeaderFields>> {
        let buf = match self.dibits.feed(dibit) {
            Some(buf) => *buf as u32,
            None => return None,
        };

        let data = match golay::shortened::decode(buf) {
            Some((data, err)) => {
                self.stats.golay_short.record_fixes(err);
                data
            },
            // Let the following RS code attempt to fix these errors.
            None => 0,
        };

        let hexbits = match self.hexbits.feed(Hexbit::new(data)) {
            Some(buf) => buf,
            None => return None,
        };

        let data = match reed_solomon::long::decode(hexbits) {
            Some((data, err)) => {
                self.stats.rs_long.record_fixes(err);
                data
            },
            None => return Some(Err(RsLongUnrecoverable)),
        };

        let mut bytes = [0; HEADER_BYTES];
        HexbitBytes::new(data.iter().cloned())
            .collect_slice_checked(&mut bytes[..]);

        Some(Ok(VoiceHeaderFields::new(bytes)))
    }
}

/// Buffer of bytes that represents a voice header packet.
pub type Buf = [u8; HEADER_BYTES];

/// Begins each voice message with information necessary to decode the following
/// superframes.
pub struct VoiceHeaderFields(Buf);

impl VoiceHeaderFields {
    /// Create a new `VoiceHeaderFields` decoder from the given bytes.
    pub fn new(buf: Buf) -> Self { VoiceHeaderFields(buf) }

    /// Initialization vector for cryptographic algorithm.
    pub fn crypto_init(&self) -> &[u8] { &self.0[..9] }
    /// Manufacturer ID.
    pub fn mfg(&self) -> u8 { self.0[9] }
    /// Cryptographic algorithm in use, if any.
    pub fn crypto_alg(&self) -> CryptoAlgorithm { CryptoAlgorithm::from_bits(self.0[10]) }
    /// Encryption key to use.
    pub fn crypto_key(&self) -> u16 { slice_u16(&self.0[11..]) }

    /// Talkgroup participating in the voice message.
    pub fn talk_group(&self) -> TalkGroup {
        TalkGroup::from_bits(slice_u16(&self.0[13..]))
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use voice::crypto::CryptoAlgorithm::*;
    use trunking::fields::TalkGroup;

    #[test]
    fn test_header() {
        let h = VoiceHeaderFields::new([
            1, 2, 3, 4, 5, 6, 7, 8, 9,
            0b00000000,
            0b10000000,
            0b00000000,
            0b00000000,
            0b11111111,
            0b11111111,
        ]);

        assert_eq!(h.crypto_init(), &[1,2,3,4,5,6,7,8,9]);
        assert_eq!(h.mfg(), 0);
        assert_eq!(h.crypto_alg(), Unencrypted);
        assert_eq!(h.crypto_key(), 0);
        assert_eq!(h.talk_group(), TalkGroup::Everbody);
    }
}
<commit_msg>Move HasStats impl<commit_after>//! Receive and decode voice header packets.

use collect_slice::CollectSlice;

use bits::{Dibit, Hexbit, HexbitBytes};
use buffer::{Buffer, VoiceHeaderWordStorage, VoiceHeaderStorage};
use coding::{reed_solomon, golay};
use consts::HEADER_BYTES;
use error::Result;
use stats::{Stats, HasStats};
use trunking::fields::TalkGroup;
use util::slice_u16;
use voice::crypto::CryptoAlgorithm;

use error::P25Error::*;

/// State machine for receiving a voice header packet.
pub struct VoiceHeaderReceiver {
    /// Current buffered dibits for the current hexbit.
    dibits: Buffer<VoiceHeaderWordStorage>,
    /// Current buffered hexbits.
    hexbits: Buffer<VoiceHeaderStorage>,
    stats: Stats,
}

impl VoiceHeaderReceiver {
    /// Create a new `VoiceHeaderReceiver` in the initial state.
    pub fn new() -> VoiceHeaderReceiver {
        VoiceHeaderReceiver {
            dibits: Buffer::new(VoiceHeaderWordStorage::new()),
            hexbits: Buffer::new(VoiceHeaderStorage::new()),
            stats: Stats::default(),
        }
    }

    /// Feed in a baseband symbol, possibly producing a voice header packet. Return
    /// `Some(Ok(pkt))` if the packet was successfully received, `Some(Err(err))` if an
    /// error occurred, and `None` in the case of no event.
    pub fn feed(&mut self, dibit: Dibit) -> Option<Result<VoiceHeaderFields>> {
        let buf = match self.dibits.feed(dibit) {
            Some(buf) => *buf as u32,
            None => return None,
        };

        let data = match golay::shortened::decode(buf) {
            Some((data, err)) => {
                self.stats.golay_short.record_fixes(err);
                data
            },
            // Let the following RS code attempt to fix these errors.
            None => 0,
        };

        let hexbits = match self.hexbits.feed(Hexbit::new(data)) {
            Some(buf) => buf,
            None => return None,
        };

        let data = match reed_solomon::long::decode(hexbits) {
            Some((data, err)) => {
                self.stats.rs_long.record_fixes(err);
                data
            },
            None => return Some(Err(RsLongUnrecoverable)),
        };

        let mut bytes = [0; HEADER_BYTES];
        HexbitBytes::new(data.iter().cloned())
            .collect_slice_checked(&mut bytes[..]);

        Some(Ok(VoiceHeaderFields::new(bytes)))
    }
}

impl HasStats for VoiceHeaderReceiver {
    fn stats(&mut self) -> &mut Stats { &mut self.stats }
}

/// Buffer of bytes that represents a voice header packet.
pub type Buf = [u8; HEADER_BYTES];

/// Begins each voice message with information necessary to decode the following
/// superframes.
pub struct VoiceHeaderFields(Buf);

impl VoiceHeaderFields {
    /// Create a new `VoiceHeaderFields` decoder from the given bytes.
    pub fn new(buf: Buf) -> Self { VoiceHeaderFields(buf) }

    /// Initialization vector for cryptographic algorithm.
    pub fn crypto_init(&self) -> &[u8] { &self.0[..9] }
    /// Manufacturer ID.
    pub fn mfg(&self) -> u8 { self.0[9] }
    /// Cryptographic algorithm in use, if any.
    pub fn crypto_alg(&self) -> CryptoAlgorithm { CryptoAlgorithm::from_bits(self.0[10]) }
    /// Encryption key to use.
    pub fn crypto_key(&self) -> u16 { slice_u16(&self.0[11..]) }

    /// Talkgroup participating in the voice message.
    pub fn talk_group(&self) -> TalkGroup {
        TalkGroup::from_bits(slice_u16(&self.0[13..]))
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use voice::crypto::CryptoAlgorithm::*;
    use trunking::fields::TalkGroup;

    #[test]
    fn test_header() {
        let h = VoiceHeaderFields::new([
            1, 2, 3, 4, 5, 6, 7, 8, 9,
            0b00000000,
            0b10000000,
            0b00000000,
            0b00000000,
            0b11111111,
            0b11111111,
        ]);

        assert_eq!(h.crypto_init(), &[1,2,3,4,5,6,7,8,9]);
        assert_eq!(h.mfg(), 0);
        assert_eq!(h.crypto_alg(), Unencrypted);
        assert_eq!(h.crypto_key(), 0);
        assert_eq!(h.talk_group(), TalkGroup::Everbody);
    }
}
<|endoftext|>


<commit_before>use analysis::rust_type::Result;
use env::Env;
use gobjects::GStatus;
use library;
use library::*;
use nameutil::module_name;

// FIXME: This module needs redundant allocations audit
// TODO: ffi_type computations should be cached

pub fn ffi_type(env: &Env, tid: library::TypeId, c_type: &str) -> Result {
    let (ptr, inner) = rustify_pointers(c_type);
    let res = match (ptr.is_empty(), ffi_inner(env, tid, inner)) {
        (true, x) => x,
        (_, Ok(s)) => Ok(format!("{} {}", ptr, s)),
        (_, Err(s)) => Err(format!("{} {}", ptr, s)),
    };
    trace!("ffi_type({:?}, {}) -> {:?}", tid, c_type, res);
    res
}

fn ffi_inner(env: &Env, tid: library::TypeId, inner: String) -> Result {
    match *env.library.type_(tid) {
        Type::Fundamental(fund) => {
            use library::Fundamental::*;
            let inner = match fund {
                None => "c_void",
                Boolean => "gboolean",
                Int8 => "i8",
                UInt8 => "u8",
                Int16 => "i16",
                UInt16 => "u16",
                Int32 => "i32",
                UInt32 => "u32",
                Int64 => "i64",
                UInt64 => "u64",
                Char => "c_char",
                UChar => "c_char",
                Short => "c_short",
                UShort => "c_ushort",
                Int => "c_int",
                UInt => "c_uint",
                Long => "c_long",
                ULong => "c_ulong",
                Size => "size_t",
                SSize => "ssize_t",
                Float => "c_float",
                Double => "c_double",
                UniChar => "u32",
                Utf8 => "c_char",
                Filename => "c_char",
                Type => "GType",
                Pointer => return Ok(inner),
                Unsupported => return Err(format!("[Unsupported type {}]", inner)),
                VarArgs => panic!("Should not reach here"),
            };
            Ok(inner.into())
        }
        Type::Record(..)
            | Type::Alias(..)
            | Type::Function(..) => Err(format!("[Not yet supported type {}]", inner)),
        // TODO: need to recurse into it
        Type::Array(inner_tid) => {
            ffi_inner(env, inner_tid, inner)
        }
        Type::List(..) | Type::SList(..) => Ok(inner),
        _ => {
            if let Some(glib_name) = env.library.type_(tid).get_glib_name() {
                if inner != glib_name {
                    let msg = format!("[c:type mismatch {} != {} of {}]", inner, glib_name,
                      env.library.type_(tid).get_name());
                    warn!("{}", msg);
                    Err(msg)
                }
                else {
                    fix_external_name(env, tid, &inner)
                }
            }
            else {
                let msg = format!("[Missing glib_name of {}, can't match != {}]",
                                  env.library.type_(tid).get_name(), inner);
                warn!("{}", msg);
                Err(msg)
            }
        }
    }
}

fn fix_external_name(env: &Env, type_id: library::TypeId, name: &str) -> Result {
    if type_id.ns_id == library::MAIN_NAMESPACE || type_id.ns_id == library::INTERNAL_NAMESPACE {
        Ok(name.into())
    } else {
        let name_with_prefix = format!("{}_ffi::{}",
            fix_namespace(env, type_id), name);
        if env.type_status_sys(&type_id.full_name(&env.library)) == GStatus::Ignore {
            Err(name_with_prefix.into())
        } else {
            Ok(name_with_prefix)
        }
    }
}

//TODO: check if need to use in non sys codegen
fn fix_namespace(env: &Env, type_id: library::TypeId) -> String {
    let mut name: &str = &module_name(&env.library.namespace(type_id.ns_id).name);
    name = match name {
        "gdk_pixbuf" => "gdk",
        "gio" => "glib",
        "g_object" => "glib",
        _ => name,
    };
    name.into()
}

fn rustify_pointers(c_type: &str) -> (String, String) {
    let mut input = c_type.trim();
    let leading_const = input.starts_with("const ");
    if leading_const {
        input = &input[6..];
    }
    let end = [
        input.find(" const"),
        input.find("*const"),
        input.find("*"),
        Some(input.len()),
    ].iter().filter_map(|&x| x).min().unwrap();
    let inner = input[..end].trim().into();

    let mut ptrs: Vec<_> = input[end..].rsplit('*').skip(1)
        .map(|s| if s.contains("const") { "*const" } else { "*mut" }).collect();
    if let (true, Some(p)) = (leading_const, ptrs.last_mut()) {
        *p = "*const";
    }

    let res = (ptrs.connect(" "), inner);
    trace!("rustify `{}` -> `{}` `{}`", c_type, res.0, res.1);
    res
}

#[cfg(test)]
mod tests {
    use super::rustify_pointers as rustify_ptr;

    fn s(x: &str, y: &str) -> (String, String) {
        (x.into(), y.into())
    }

    #[test]
    fn rustify_pointers() {
        assert_eq!(rustify_ptr("char"), s("", "char"));
        assert_eq!(rustify_ptr("char*"), s("*mut", "char"));
        assert_eq!(rustify_ptr("const char*"), s("*const", "char"));
        assert_eq!(rustify_ptr("char const*"), s("*const", "char"));
        assert_eq!(rustify_ptr("char const *"), s("*const", "char"));
        assert_eq!(rustify_ptr(" char * * "), s("*mut *mut", "char"));
        assert_eq!(rustify_ptr("const char**"), s("*mut *const", "char"));
        assert_eq!(rustify_ptr("char const**"), s("*mut *const", "char"));
        assert_eq!(rustify_ptr("const char* const*"), s("*const *const", "char"));
        assert_eq!(rustify_ptr("char const * const *"), s("*const *const", "char"));
        assert_eq!(rustify_ptr("char* const*"), s("*const *mut", "char"));
    }
}
<commit_msg>ffi_type: allow record, alias and function (callback) types<commit_after>use analysis::rust_type::Result;
use env::Env;
use gobjects::GStatus;
use library;
use library::*;
use nameutil::module_name;

// FIXME: This module needs redundant allocations audit
// TODO: ffi_type computations should be cached

pub fn ffi_type(env: &Env, tid: library::TypeId, c_type: &str) -> Result {
    let (ptr, inner) = rustify_pointers(c_type);
    let res = match (ptr.is_empty(), ffi_inner(env, tid, inner)) {
        (true, x) => x,
        (_, Ok(s)) => Ok(format!("{} {}", ptr, s)),
        (_, Err(s)) => Err(format!("{} {}", ptr, s)),
    };
    trace!("ffi_type({:?}, {}) -> {:?}", tid, c_type, res);
    res
}

fn ffi_inner(env: &Env, tid: library::TypeId, inner: String) -> Result {
    match *env.library.type_(tid) {
        Type::Fundamental(fund) => {
            use library::Fundamental::*;
            let inner = match fund {
                None => "c_void",
                Boolean => "gboolean",
                Int8 => "i8",
                UInt8 => "u8",
                Int16 => "i16",
                UInt16 => "u16",
                Int32 => "i32",
                UInt32 => "u32",
                Int64 => "i64",
                UInt64 => "u64",
                Char => "c_char",
                UChar => "c_char",
                Short => "c_short",
                UShort => "c_ushort",
                Int => "c_int",
                UInt => "c_uint",
                Long => "c_long",
                ULong => "c_ulong",
                Size => "size_t",
                SSize => "ssize_t",
                Float => "c_float",
                Double => "c_double",
                UniChar => "u32",
                Utf8 => "c_char",
                Filename => "c_char",
                Type => "GType",
                Pointer => return Ok(inner),
                Unsupported => return Err(format!("[Unsupported type {}]", inner)),
                VarArgs => panic!("Should not reach here"),
            };
            Ok(inner.into())
        }
        Type::Record(..) | Type::Alias(..) | Type::Function(..) => {
            fix_external_name(env, tid, &inner)
        }
        // TODO: need to recurse into it
        Type::Array(inner_tid) => {
            ffi_inner(env, inner_tid, inner)
        }
        Type::List(..) | Type::SList(..) => Ok(inner),
        _ => {
            if let Some(glib_name) = env.library.type_(tid).get_glib_name() {
                if inner != glib_name {
                    let msg = format!("[c:type mismatch {} != {} of {}]", inner, glib_name,
                      env.library.type_(tid).get_name());
                    warn!("{}", msg);
                    Err(msg)
                }
                else {
                    fix_external_name(env, tid, &inner)
                }
            }
            else {
                let msg = format!("[Missing glib_name of {}, can't match != {}]",
                                  env.library.type_(tid).get_name(), inner);
                warn!("{}", msg);
                Err(msg)
            }
        }
    }
}

fn fix_external_name(env: &Env, type_id: library::TypeId, name: &str) -> Result {
    if type_id.ns_id == library::MAIN_NAMESPACE || type_id.ns_id == library::INTERNAL_NAMESPACE {
        Ok(name.into())
    } else {
        let name_with_prefix = format!("{}_ffi::{}",
            fix_namespace(env, type_id), name);
        if env.type_status_sys(&type_id.full_name(&env.library)) == GStatus::Ignore {
            Err(name_with_prefix.into())
        } else {
            Ok(name_with_prefix)
        }
    }
}

//TODO: check if need to use in non sys codegen
fn fix_namespace(env: &Env, type_id: library::TypeId) -> String {
    let mut name: &str = &module_name(&env.library.namespace(type_id.ns_id).name);
    name = match name {
        "gdk_pixbuf" => "gdk",
        "gio" => "glib",
        "g_object" => "glib",
        _ => name,
    };
    name.into()
}

fn rustify_pointers(c_type: &str) -> (String, String) {
    let mut input = c_type.trim();
    let leading_const = input.starts_with("const ");
    if leading_const {
        input = &input[6..];
    }
    let end = [
        input.find(" const"),
        input.find("*const"),
        input.find("*"),
        Some(input.len()),
    ].iter().filter_map(|&x| x).min().unwrap();
    let inner = input[..end].trim().into();

    let mut ptrs: Vec<_> = input[end..].rsplit('*').skip(1)
        .map(|s| if s.contains("const") { "*const" } else { "*mut" }).collect();
    if let (true, Some(p)) = (leading_const, ptrs.last_mut()) {
        *p = "*const";
    }

    let res = (ptrs.connect(" "), inner);
    trace!("rustify `{}` -> `{}` `{}`", c_type, res.0, res.1);
    res
}

#[cfg(test)]
mod tests {
    use super::rustify_pointers as rustify_ptr;

    fn s(x: &str, y: &str) -> (String, String) {
        (x.into(), y.into())
    }

    #[test]
    fn rustify_pointers() {
        assert_eq!(rustify_ptr("char"), s("", "char"));
        assert_eq!(rustify_ptr("char*"), s("*mut", "char"));
        assert_eq!(rustify_ptr("const char*"), s("*const", "char"));
        assert_eq!(rustify_ptr("char const*"), s("*const", "char"));
        assert_eq!(rustify_ptr("char const *"), s("*const", "char"));
        assert_eq!(rustify_ptr(" char * * "), s("*mut *mut", "char"));
        assert_eq!(rustify_ptr("const char**"), s("*mut *const", "char"));
        assert_eq!(rustify_ptr("char const**"), s("*mut *const", "char"));
        assert_eq!(rustify_ptr("const char* const*"), s("*const *const", "char"));
        assert_eq!(rustify_ptr("char const * const *"), s("*const *const", "char"));
        assert_eq!(rustify_ptr("char* const*"), s("*const *mut", "char"));
    }
}
<|endoftext|>