servo/components/style/gecko/snapshot_helpers.rs
author Xidorn Quan <me@upsuper.org>
Mon, 15 May 2017 14:19:02 +1000
changeset 577632 5adc4a1fa7cc6b132794d3dd82dfe95a4f5a5690
parent 478631 56fb1073e3041215f561a41ec2a84170001267c1
child 593282 5eca9cc75c3fc7354be4655127f55eefbd7699d2
permissions -rw-r--r--
Relax the requirement of Atom::with. r?Manishearth This commit does two things: 1. change the type of callback from "&mut FnMut" to "FnOnce" 2. remove the 'static lifetime restriction for the return type The second change is necessary for the next commit. To be honest, I don't fully understand how closures work. But it seems the change here just works, and looks reasonable to me. I simply trust that rustc has confirmed the code is doing the right thing. MozReview-Commit-ID: 1RqLWlxv7wf

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Element an snapshot common logic.

use gecko_bindings::structs::nsIAtom;
use std::{ptr, slice};
use string_cache::Atom;

/// A function that, given an element of type `T`, allows you to get a single
/// class or a class list.
pub type ClassOrClassList<T> = unsafe extern fn (T, *mut *mut nsIAtom, *mut *mut *mut nsIAtom) -> u32;

/// Given an item `T`, a class name, and a getter function, return whether that
/// element has the class that `name` represents.
pub fn has_class<T>(item: T,
                    name: &Atom,
                    getter: ClassOrClassList<T>) -> bool
{
    unsafe {
        let mut class: *mut nsIAtom = ptr::null_mut();
        let mut list: *mut *mut nsIAtom = ptr::null_mut();
        let length = getter(item, &mut class, &mut list);
        match length {
            0 => false,
            1 => name.as_ptr() == class,
            n => {
                let classes = slice::from_raw_parts(list, n as usize);
                classes.iter().any(|ptr| name.as_ptr() == *ptr)
            }
        }
    }
}


/// Given an item, a callback, and a getter, execute `callback` for each class
/// this `item` has.
pub fn each_class<F, T>(item: T,
                        mut callback: F,
                        getter: ClassOrClassList<T>)
    where F: FnMut(&Atom)
{
    unsafe {
        let mut class: *mut nsIAtom = ptr::null_mut();
        let mut list: *mut *mut nsIAtom = ptr::null_mut();
        let length = getter(item, &mut class, &mut list);
        match length {
            0 => {}
            1 => Atom::with(class, callback),
            n => {
                let classes = slice::from_raw_parts(list, n as usize);
                for c in classes {
                    Atom::with(*c, &mut callback)
                }
            }
        }
    }
}