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

/*!
 * Base conversion utilities
 *
 * Provides functions for converting an integer to/from a given base. In both `to_base` and
 * `from_base` the base-N output or input (respectively) is stored as raw bytes. That means that a
 * base-10 input contains bytes each with a value from 0-9.
 */

use std::intrinsics::assume;

use ll;
use ll::limb::Limb;
use ll::limb_ptr::{Limbs, LimbsMut};

/// Information for converting to/from a given base, B. Stored in a table generated
/// by build.rs
struct Base {
    /// Number of digits a limb can hold in a given base. Except if B is a power of 2,
    /// in which case it is equal to the number of bits per digit in base B
    digits_per_limb: u32,
    /// The "big base", essentially the largest B^m that will fit in a limb.
    /// Should be the same as B^digits_per_limb
    big_base: Limb,
}
// Include BASES table
include!(concat!(env!("OUT_DIR"), "/bases_table.rs"));

#[inline(always)]
fn div_unnorm(n: Limb, d: Limb) -> (Limb, Limb) {
    (n / d, n % d)
}

#[inline]
pub unsafe fn num_base_digits(p: Limbs, n: i32, base: u32) -> usize {
    debug_assert!(base >= 2);
    assume(base >= 2);

    if n == 0 { return 1; }

    let cnt = (*p.offset((n - 1) as isize)).leading_zeros() as usize;
    let total_bits = (Limb::BITS * (n as usize)) - cnt;

    if base.is_power_of_two() {
        let big_base = BASES.get_unchecked(base as usize).big_base.0 as usize;
        (total_bits + big_base - 1) / big_base
    } else {
        // Not sure if using floating-point arithmetic here is the best idea,
        // but it should be a reasonable accurate result, maybe a little high
        let total_bits = total_bits as f64;

        let lg2b = (base as f64).log2();
        let digits = total_bits / lg2b;
        return 1 + digits.ceil() as usize;
    }
}

#[inline]
pub fn base_digits_to_len(num: usize, base: u32) -> usize {
    debug_assert!(base >= 2);

    if num == 0 { return 0; }

    let digits_per_limb = BASES[base as usize].digits_per_limb as usize;

    (num / digits_per_limb) + 1
}

/**
 * Converts `nn` limbs at `np` to the given base, storing the output in `out`. `out` is assumed to
 * have enough space for the entire digit. The output is stored from most-significant digit to least.
 *
 * The values in `out` are the raw values of the base. Conversion for output should be done as a second
 * step.
 */
pub unsafe fn to_base<F: FnMut(u8)>(base: u32, np: Limbs, nn: i32, mut out_byte: F) {
    debug_assert!(nn >= 0);
    debug_assert!(base < BASES.len() as u32);
    debug_assert!(base >= 2);
    assume(base < BASES.len() as u32);
    assume(base >= 2);

    if nn <= 0 {
        out_byte(0);
        return;
    }
    // Fast path for powers-of-two, since each limb is already in base B^m format
    if base.is_power_of_two() {
        let bits_per_digit = BASES.get_unchecked(base as usize).big_base.0 as usize;
        assume(bits_per_digit > 0);

        let mut n1 = *np.offset((nn - 1) as isize);
        let cnt = n1.leading_zeros() as usize;

        let mut bits = Limb::BITS * (nn as usize) - cnt;
        let cnt = bits % bits_per_digit;
        if cnt != 0 {
            bits += bits_per_digit - cnt;
        }

        let mut bit_pos : isize = (bits - (nn as usize - 1) * Limb::BITS) as isize;

        let mut i = nn - 1;
        // Convert each limb by shifting and masking to get the value for each output digit
        loop {
            bit_pos -= bits_per_digit as isize;
            while bit_pos >= 0 {
                let b = ((n1 >> (bit_pos as usize)) & ((Limb(1) << bits_per_digit) - 1)).0 as u8;
                out_byte(b);
                bit_pos -= bits_per_digit as isize;
            }
            i -= 1;
            if i < 0 { break; }

            let n0 = (n1 << ((-bit_pos) as usize)) & ((Limb(1) << bits_per_digit) - 1);
            n1 = *np.offset(i as isize);
            bit_pos += Limb::BITS as isize;
            // We have a potential overlap of bits, so get the value of the digit
            // that spans the two limbs.
            // The specific situation is (using 8-bit limbs as demonstration):
            //
            //    bbbbbbbb bbbbbbbb
            //          ^---^         Bits for next digit
            let b = (n0 | (n1 >> (bit_pos as usize))).0 as u8;
            out_byte(b);
        }
        return;
    }
    // TODO: Use divide-and-conquer for large numbers
    to_base_impl(0, base, np, nn, out_byte);
}

unsafe fn to_base_impl<F: FnMut(u8)>(mut len: u32, base: u32, np: Limbs, mut nn: i32, mut out_byte: F) {
    debug_assert!(base > 2);

    let buf_len = num_base_digits(np, nn, base);
    let mut buf : Vec<u8> = vec![0; buf_len];
    let mut r : Vec<Limb> = vec![Limb(0); (nn + 1) as usize];
    let rp = LimbsMut::new(&mut r[0], 0, r.len() as i32);

    ll::copy_incr(np, rp.offset(1), nn);

    let mut sz = 0;

    let s : *mut u8 = &mut buf[0];
    let mut s = s.offset(buf_len as isize);

    let base = Limb(base as ll::limb::BaseInt);

    macro_rules! base_impl (
        ($base:expr, $s:expr, $rp:expr, $sz:ident, $nn:ident) => (
            {
                let digits_per_limb = BASES.get_unchecked($base.0 as usize).digits_per_limb;
                let big_base = BASES.get_unchecked($base.0 as usize).big_base;

                // Process limbs from least-significant to most, until there is only one
                // limb left
                while $nn > 1 {
                    // Divide rp by the big_base, with a single fractional limb produced.
                    // The fractional limb is approximately 1/remainder
                    ll::divrem_1($rp, 1, $rp.offset(1).as_const(), $nn, big_base);

                    $nn -= if *$rp.offset($nn as isize) == 0 { 1 } else { 0 };
                    let mut frac = *$rp + 1;
                    // The loop below produces digits from most-significant to least, but
                    // the containing loop works from least signficant limb up, so move
                    // the first position for the output for this limb. Since we know
                    // there is at least one more limb to process after this one, it's
                    // safe to output all digits that may be produced.
                    $s = $s.offset(-(digits_per_limb as isize));
                    let mut i = digits_per_limb;
                    loop {
                        // Multiply the fraction from divrem by the base, the overflow
                        // amount is the next digit we want
                        let (digit, f) = frac.mul_hilo($base);
                        frac = f;
                        *$s = digit.0 as u8;
                        $s = $s.offset(1);

                        $sz += 1;

                        i -= 1;
                        if i == 0 { break; }
                    }

                    $s = $s.offset(-(digits_per_limb as isize));
                }

                // Last limb, use normal conversion for this one so we
                // don't overshoot the number of digits
                let mut ul = *$rp.offset(1);
                while ul != 0 {
                    let (q, r) = div_unnorm(ul, base);
                    $s = $s.offset(-1);
                    *$s = r.0 as u8;
                    ul = q;

                    $sz += 1;
                }
            }
        )
    );

    // Specialise on the base-10 conversion routine. The other common base, 16, is handled
    // by the power-of-two case in to_base. This allows the compiler to unroll the inner
    // loop in the conversion, which is a sigificant speed increase.
    if base == 10 {
        base_impl!(Limb(10), s, rp, sz, nn);
    } else {
        base_impl!(base, s, rp, sz, nn);
    }

    let mut l = sz;

    // Output any leading zeros we may want
    while l < len {
        out_byte(0);
        len -= 1;
    }

    // Copy the temporary buffer into the output string
    while l != 0 {
        out_byte(*s);
        s = s.offset(1);
        l -= 1;
    }
}

/**
 * Converts the base `base` bytestring {bp, bs}, storing the limbs in `out`. `out` is assumed to
 * have enough space to store the result.
 */
pub unsafe fn from_base(mut out: LimbsMut, bp: *const u8, bs: i32, base: u32) -> usize {
    debug_assert!(bs > 0);
    debug_assert!(base < BASES.len() as u32);
    debug_assert!(base >= 2);
    assume(base < BASES.len() as u32);
    assume(base >= 2);

    if bs <= 0 {
        *out = Limb(0);
        return 1;
    }

    if base.is_power_of_two() {
        let bits_per_digit = BASES.get_unchecked(base as usize).big_base.0 as usize;
        assume(bits_per_digit > 0);

        let mut size = 0;

        let mut b = bp.offset((bs - 1) as isize);
        let mut res_digit = Limb(0);
        let mut next_bitpos = 0;
        while b >= bp {
            let digit = Limb((*b) as ll::limb::BaseInt);

            res_digit = res_digit | (digit << next_bitpos);
            next_bitpos += bits_per_digit;
            if next_bitpos >= Limb::BITS {
                next_bitpos -= Limb::BITS;
                *out.offset(size as isize) = res_digit;
                size += 1;
                res_digit = digit >> (bits_per_digit - next_bitpos);
            }

            b = b.offset(-1);
        }

        if res_digit > 0 {
            *out.offset(size as isize) = res_digit;
            size += 1;
        }

        return size;
    }

    // TODO, use a divide-and-conquer algorithm for large inputs
    from_base_small(out, bp, bs, base)
}

unsafe fn from_base_small(mut out: LimbsMut, mut bp: *const u8, bs: i32, base: u32) -> usize {
    debug_assert!(base > 2);
    assume(base > 2);

    let big_base = BASES.get_unchecked(base as usize).big_base;
    let digits_per_limb = BASES.get_unchecked(base as usize).digits_per_limb;

    let mut i = digits_per_limb;
    let mut size : usize = 0;
    while i < (bs as u32) {
        let mut res_digit = Limb((*bp) as ll::limb::BaseInt);
        bp = bp.offset(1);

        if base == 10 {
            let mut j = digits_per_limb - 1;
            while j > 0 {
                res_digit = res_digit * 10 + ((*bp) as ll::limb::BaseInt);
                bp = bp.offset(1);
                j -= 1;
            }
        } else {
            let mut j = digits_per_limb - 1;
            while j > 0 {
                res_digit = res_digit * (base as ll::limb::BaseInt) + ((*bp) as ll::limb::BaseInt);
                bp = bp.offset(1);
                j -= 1;
            }
        }

        if size == 0 {
            if res_digit != 0 {
                *out = res_digit;
                size = 1;
            }
        } else {
            let mut carry = ll::mul_1(out, out.as_const(), size as i32, big_base);
            carry = carry + ll::add_1(out, out.as_const(), size as i32, res_digit);
            if carry != 0 {
                *out.offset(size as isize) = carry;
                size += 1;
            }
        }

        i += digits_per_limb;
    }

    let mut big_base = base as ll::limb::BaseInt;
    let mut res_digit = Limb((*bp) as ll::limb::BaseInt);
    bp = bp.offset(1);

    if base == 10 {
        let mut j = (bs as u32) - (i - digits_per_limb) - 1;
        while j > 0 {
            res_digit = res_digit * 10 + ((*bp) as ll::limb::BaseInt);
            big_base *= 10;
            bp = bp.offset(1);
            j -= 1;
        }
    } else {
        let mut j = (bs as u32) - (i - digits_per_limb) - 1;
        while j > 0 {
            res_digit = res_digit * (base as ll::limb::BaseInt) + ((*bp) as ll::limb::BaseInt);
            bp = bp.offset(1);
            big_base *= base as ll::limb::BaseInt;
            j -= 1;
        }
    }

    if size == 0 {
        if res_digit != 0 {
            *out = res_digit;
            size = 1;
        }
    } else {
        let mut carry = ll::mul_1(out, out.as_const(), size as i32, Limb(big_base));
        carry = carry + ll::add_1(out, out.as_const(), size as i32, res_digit);
        if carry != 0 {
            *out.offset(size as isize) = carry;
            size += 1;
        }
    }

    return size;
}
<commit_msg>Optimise `ll::base::num_base_digits` for 2 & other powers of it.<commit_after>// Copyright 2015 The Ramp Developers
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.

/*!
 * Base conversion utilities
 *
 * Provides functions for converting an integer to/from a given base. In both `to_base` and
 * `from_base` the base-N output or input (respectively) is stored as raw bytes. That means that a
 * base-10 input contains bytes each with a value from 0-9.
 */

use std::intrinsics::assume;

use ll;
use ll::limb::Limb;
use ll::limb_ptr::{Limbs, LimbsMut};

/// Information for converting to/from a given base, B. Stored in a table generated
/// by build.rs
struct Base {
    /// Number of digits a limb can hold in a given base. Except if B is a power of 2,
    /// in which case it is equal to the number of bits per digit in base B
    digits_per_limb: u32,
    /// The "big base", essentially the largest B^m that will fit in a limb.
    /// Should be the same as B^digits_per_limb
    big_base: Limb,
}
// Include BASES table
include!(concat!(env!("OUT_DIR"), "/bases_table.rs"));

#[inline(always)]
fn div_unnorm(n: Limb, d: Limb) -> (Limb, Limb) {
    (n / d, n % d)
}

#[inline]
pub unsafe fn num_base_digits(p: Limbs, n: i32, base: u32) -> usize {
    debug_assert!(base >= 2);
    assume(base >= 2);

    if n == 0 { return 1; }

    let cnt = (*p.offset((n - 1) as isize)).leading_zeros() as usize;
    let total_bits = (Limb::BITS * (n as usize)) - cnt;

    if base == 2 {
        // no need to do anything complicated here at all, so let's go
        // as fast as possible (this is a somewhat common case, due to
        // `bit_length`)
        total_bits
    } else if base.is_power_of_two() {
        let big_base = BASES.get_unchecked(base as usize).big_base.0 as usize;
        // doing an actual division here is much slower than this
        (total_bits + big_base - 1) >> big_base.trailing_zeros()
    } else {
        // Not sure if using floating-point arithmetic here is the best idea,
        // but it should be a reasonable accurate result, maybe a little high
        let total_bits = total_bits as f64;

        let lg2b = (base as f64).log2();
        let digits = total_bits / lg2b;
        return 1 + digits.ceil() as usize;
    }
}

#[inline]
pub fn base_digits_to_len(num: usize, base: u32) -> usize {
    debug_assert!(base >= 2);

    if num == 0 { return 0; }

    let digits_per_limb = BASES[base as usize].digits_per_limb as usize;

    (num / digits_per_limb) + 1
}

/**
 * Converts `nn` limbs at `np` to the given base, storing the output in `out`. `out` is assumed to
 * have enough space for the entire digit. The output is stored from most-significant digit to least.
 *
 * The values in `out` are the raw values of the base. Conversion for output should be done as a second
 * step.
 */
pub unsafe fn to_base<F: FnMut(u8)>(base: u32, np: Limbs, nn: i32, mut out_byte: F) {
    debug_assert!(nn >= 0);
    debug_assert!(base < BASES.len() as u32);
    debug_assert!(base >= 2);
    assume(base < BASES.len() as u32);
    assume(base >= 2);

    if nn <= 0 {
        out_byte(0);
        return;
    }
    // Fast path for powers-of-two, since each limb is already in base B^m format
    if base.is_power_of_two() {
        let bits_per_digit = BASES.get_unchecked(base as usize).big_base.0 as usize;
        assume(bits_per_digit > 0);

        let mut n1 = *np.offset((nn - 1) as isize);
        let cnt = n1.leading_zeros() as usize;

        let mut bits = Limb::BITS * (nn as usize) - cnt;
        let cnt = bits % bits_per_digit;
        if cnt != 0 {
            bits += bits_per_digit - cnt;
        }

        let mut bit_pos : isize = (bits - (nn as usize - 1) * Limb::BITS) as isize;

        let mut i = nn - 1;
        // Convert each limb by shifting and masking to get the value for each output digit
        loop {
            bit_pos -= bits_per_digit as isize;
            while bit_pos >= 0 {
                let b = ((n1 >> (bit_pos as usize)) & ((Limb(1) << bits_per_digit) - 1)).0 as u8;
                out_byte(b);
                bit_pos -= bits_per_digit as isize;
            }
            i -= 1;
            if i < 0 { break; }

            let n0 = (n1 << ((-bit_pos) as usize)) & ((Limb(1) << bits_per_digit) - 1);
            n1 = *np.offset(i as isize);
            bit_pos += Limb::BITS as isize;
            // We have a potential overlap of bits, so get the value of the digit
            // that spans the two limbs.
            // The specific situation is (using 8-bit limbs as demonstration):
            //
            //    bbbbbbbb bbbbbbbb
            //          ^---^         Bits for next digit
            let b = (n0 | (n1 >> (bit_pos as usize))).0 as u8;
            out_byte(b);
        }
        return;
    }
    // TODO: Use divide-and-conquer for large numbers
    to_base_impl(0, base, np, nn, out_byte);
}

unsafe fn to_base_impl<F: FnMut(u8)>(mut len: u32, base: u32, np: Limbs, mut nn: i32, mut out_byte: F) {
    debug_assert!(base > 2);

    let buf_len = num_base_digits(np, nn, base);
    let mut buf : Vec<u8> = vec![0; buf_len];
    let mut r : Vec<Limb> = vec![Limb(0); (nn + 1) as usize];
    let rp = LimbsMut::new(&mut r[0], 0, r.len() as i32);

    ll::copy_incr(np, rp.offset(1), nn);

    let mut sz = 0;

    let s : *mut u8 = &mut buf[0];
    let mut s = s.offset(buf_len as isize);

    let base = Limb(base as ll::limb::BaseInt);

    macro_rules! base_impl (
        ($base:expr, $s:expr, $rp:expr, $sz:ident, $nn:ident) => (
            {
                let digits_per_limb = BASES.get_unchecked($base.0 as usize).digits_per_limb;
                let big_base = BASES.get_unchecked($base.0 as usize).big_base;

                // Process limbs from least-significant to most, until there is only one
                // limb left
                while $nn > 1 {
                    // Divide rp by the big_base, with a single fractional limb produced.
                    // The fractional limb is approximately 1/remainder
                    ll::divrem_1($rp, 1, $rp.offset(1).as_const(), $nn, big_base);

                    $nn -= if *$rp.offset($nn as isize) == 0 { 1 } else { 0 };
                    let mut frac = *$rp + 1;
                    // The loop below produces digits from most-significant to least, but
                    // the containing loop works from least signficant limb up, so move
                    // the first position for the output for this limb. Since we know
                    // there is at least one more limb to process after this one, it's
                    // safe to output all digits that may be produced.
                    $s = $s.offset(-(digits_per_limb as isize));
                    let mut i = digits_per_limb;
                    loop {
                        // Multiply the fraction from divrem by the base, the overflow
                        // amount is the next digit we want
                        let (digit, f) = frac.mul_hilo($base);
                        frac = f;
                        *$s = digit.0 as u8;
                        $s = $s.offset(1);

                        $sz += 1;

                        i -= 1;
                        if i == 0 { break; }
                    }

                    $s = $s.offset(-(digits_per_limb as isize));
                }

                // Last limb, use normal conversion for this one so we
                // don't overshoot the number of digits
                let mut ul = *$rp.offset(1);
                while ul != 0 {
                    let (q, r) = div_unnorm(ul, base);
                    $s = $s.offset(-1);
                    *$s = r.0 as u8;
                    ul = q;

                    $sz += 1;
                }
            }
        )
    );

    // Specialise on the base-10 conversion routine. The other common base, 16, is handled
    // by the power-of-two case in to_base. This allows the compiler to unroll the inner
    // loop in the conversion, which is a sigificant speed increase.
    if base == 10 {
        base_impl!(Limb(10), s, rp, sz, nn);
    } else {
        base_impl!(base, s, rp, sz, nn);
    }

    let mut l = sz;

    // Output any leading zeros we may want
    while l < len {
        out_byte(0);
        len -= 1;
    }

    // Copy the temporary buffer into the output string
    while l != 0 {
        out_byte(*s);
        s = s.offset(1);
        l -= 1;
    }
}

/**
 * Converts the base `base` bytestring {bp, bs}, storing the limbs in `out`. `out` is assumed to
 * have enough space to store the result.
 */
pub unsafe fn from_base(mut out: LimbsMut, bp: *const u8, bs: i32, base: u32) -> usize {
    debug_assert!(bs > 0);
    debug_assert!(base < BASES.len() as u32);
    debug_assert!(base >= 2);
    assume(base < BASES.len() as u32);
    assume(base >= 2);

    if bs <= 0 {
        *out = Limb(0);
        return 1;
    }

    if base.is_power_of_two() {
        let bits_per_digit = BASES.get_unchecked(base as usize).big_base.0 as usize;
        assume(bits_per_digit > 0);

        let mut size = 0;

        let mut b = bp.offset((bs - 1) as isize);
        let mut res_digit = Limb(0);
        let mut next_bitpos = 0;
        while b >= bp {
            let digit = Limb((*b) as ll::limb::BaseInt);

            res_digit = res_digit | (digit << next_bitpos);
            next_bitpos += bits_per_digit;
            if next_bitpos >= Limb::BITS {
                next_bitpos -= Limb::BITS;
                *out.offset(size as isize) = res_digit;
                size += 1;
                res_digit = digit >> (bits_per_digit - next_bitpos);
            }

            b = b.offset(-1);
        }

        if res_digit > 0 {
            *out.offset(size as isize) = res_digit;
            size += 1;
        }

        return size;
    }

    // TODO, use a divide-and-conquer algorithm for large inputs
    from_base_small(out, bp, bs, base)
}

unsafe fn from_base_small(mut out: LimbsMut, mut bp: *const u8, bs: i32, base: u32) -> usize {
    debug_assert!(base > 2);
    assume(base > 2);

    let big_base = BASES.get_unchecked(base as usize).big_base;
    let digits_per_limb = BASES.get_unchecked(base as usize).digits_per_limb;

    let mut i = digits_per_limb;
    let mut size : usize = 0;
    while i < (bs as u32) {
        let mut res_digit = Limb((*bp) as ll::limb::BaseInt);
        bp = bp.offset(1);

        if base == 10 {
            let mut j = digits_per_limb - 1;
            while j > 0 {
                res_digit = res_digit * 10 + ((*bp) as ll::limb::BaseInt);
                bp = bp.offset(1);
                j -= 1;
            }
        } else {
            let mut j = digits_per_limb - 1;
            while j > 0 {
                res_digit = res_digit * (base as ll::limb::BaseInt) + ((*bp) as ll::limb::BaseInt);
                bp = bp.offset(1);
                j -= 1;
            }
        }

        if size == 0 {
            if res_digit != 0 {
                *out = res_digit;
                size = 1;
            }
        } else {
            let mut carry = ll::mul_1(out, out.as_const(), size as i32, big_base);
            carry = carry + ll::add_1(out, out.as_const(), size as i32, res_digit);
            if carry != 0 {
                *out.offset(size as isize) = carry;
                size += 1;
            }
        }

        i += digits_per_limb;
    }

    let mut big_base = base as ll::limb::BaseInt;
    let mut res_digit = Limb((*bp) as ll::limb::BaseInt);
    bp = bp.offset(1);

    if base == 10 {
        let mut j = (bs as u32) - (i - digits_per_limb) - 1;
        while j > 0 {
            res_digit = res_digit * 10 + ((*bp) as ll::limb::BaseInt);
            big_base *= 10;
            bp = bp.offset(1);
            j -= 1;
        }
    } else {
        let mut j = (bs as u32) - (i - digits_per_limb) - 1;
        while j > 0 {
            res_digit = res_digit * (base as ll::limb::BaseInt) + ((*bp) as ll::limb::BaseInt);
            bp = bp.offset(1);
            big_base *= base as ll::limb::BaseInt;
            j -= 1;
        }
    }

    if size == 0 {
        if res_digit != 0 {
            *out = res_digit;
            size = 1;
        }
    } else {
        let mut carry = ll::mul_1(out, out.as_const(), size as i32, Limb(big_base));
        carry = carry + ll::add_1(out, out.as_const(), size as i32, res_digit);
        if carry != 0 {
            *out.offset(size as isize) = carry;
            size += 1;
        }
    }

    return size;
}
<|endoftext|>


<commit_before>use std::io;
use std::io::stdio;
use std::sync;

use api;
use api::Level;
use config;

pub struct ConfigurationLogger {
    pub output: Vec<api::BoxedLogger>,
    pub level: Level,
    pub format: Box<Fn(&str, &Level) -> String + Sync + Send>,
}

impl ConfigurationLogger {
    pub fn new(format: Box<Fn(&str, &Level) -> String + Sync + Send>, config_output: Vec<config::OutputConfig>, level: Level)
                    -> io::IoResult<ConfigurationLogger> {

        let output = try!(config_output.into_iter().fold(Ok(Vec::new()),
                                            |processed: io::IoResult<Vec<api::BoxedLogger>>, next: config::OutputConfig| {
            // If an error has already been found, don't try to process any future outputs, just continue passing along the error.
            let mut processed_so_far = try!(processed);
            return match next.into_logger() {
                Err(e) => Err(e), // If this one errors, return the error instead of the Vec so far
                Ok(processed_value) => {
                    // If it's ok, add the processed logger to the vec, and pass the vec along
                    processed_so_far.push(processed_value);
                    Ok(processed_so_far)
                }
            };
        }));

        return Ok(ConfigurationLogger {
            output: output,
            level: level,
            format: format,
        });
    }
}

impl api::Logger for ConfigurationLogger {
    fn log(&self, level: &Level, msg: &str) -> io::IoResult<()> {
        if level.as_int() < self.level.as_int() {
            return Ok(());
        }
        let new_msg = self.format.call((msg, level));
        for logger in self.output.iter() {
            try!(logger.log(level, new_msg.as_slice()));
        }
        return Ok(());
    }
}

pub struct WriterLogger<T: io::Writer + Send> {
    writer: sync::Arc<sync::Mutex<T>>,
}

impl <T: io::Writer + Send> WriterLogger<T> {
    pub fn new(writer: T) -> WriterLogger<T> {
        return WriterLogger {
            writer: sync::Arc::new(sync::Mutex::new(writer)),
        };
    }

    pub fn with_stdout() -> WriterLogger<io::stdio::StdWriter> {
        return WriterLogger::new(stdio::stdout_raw());
    }

    pub fn with_stderr() -> WriterLogger<io::stdio::StdWriter> {
        return WriterLogger::new(stdio::stderr_raw());
    }

    pub fn with_file(path: &Path) -> io::IoResult<WriterLogger<io::File>> {
        return Ok(WriterLogger::new(try!(io::File::create(path))));
    }
}

impl <T: io::Writer + Send> api::Logger for WriterLogger<T> {
    fn log(&self, _level: &Level, message: &str) -> io::IoResult<()> {
        return self.writer.lock().write_line(message);
    }
}
<commit_msg>Append to log files by default, instead of truncating<commit_after>use std::io;
use std::io::stdio;
use std::sync;

use api;
use api::Level;
use config;

pub struct ConfigurationLogger {
    pub output: Vec<api::BoxedLogger>,
    pub level: Level,
    pub format: Box<Fn(&str, &Level) -> String + Sync + Send>,
}

impl ConfigurationLogger {
    pub fn new(format: Box<Fn(&str, &Level) -> String + Sync + Send>, config_output: Vec<config::OutputConfig>, level: Level)
                    -> io::IoResult<ConfigurationLogger> {

        let output = try!(config_output.into_iter().fold(Ok(Vec::new()),
                                            |processed: io::IoResult<Vec<api::BoxedLogger>>, next: config::OutputConfig| {
            // If an error has already been found, don't try to process any future outputs, just continue passing along the error.
            let mut processed_so_far = try!(processed);
            return match next.into_logger() {
                Err(e) => Err(e), // If this one errors, return the error instead of the Vec so far
                Ok(processed_value) => {
                    // If it's ok, add the processed logger to the vec, and pass the vec along
                    processed_so_far.push(processed_value);
                    Ok(processed_so_far)
                }
            };
        }));

        return Ok(ConfigurationLogger {
            output: output,
            level: level,
            format: format,
        });
    }
}

impl api::Logger for ConfigurationLogger {
    fn log(&self, level: &Level, msg: &str) -> io::IoResult<()> {
        if level.as_int() < self.level.as_int() {
            return Ok(());
        }
        let new_msg = self.format.call((msg, level));
        for logger in self.output.iter() {
            try!(logger.log(level, new_msg.as_slice()));
        }
        return Ok(());
    }
}

pub struct WriterLogger<T: io::Writer + Send> {
    writer: sync::Arc<sync::Mutex<T>>,
}

impl <T: io::Writer + Send> WriterLogger<T> {
    pub fn new(writer: T) -> WriterLogger<T> {
        return WriterLogger {
            writer: sync::Arc::new(sync::Mutex::new(writer)),
        };
    }

    pub fn with_stdout() -> WriterLogger<io::stdio::StdWriter> {
        return WriterLogger::new(stdio::stdout_raw());
    }

    pub fn with_stderr() -> WriterLogger<io::stdio::StdWriter> {
        return WriterLogger::new(stdio::stderr_raw());
    }

    pub fn with_file(path: &Path) -> io::IoResult<WriterLogger<io::File>> {
        return Ok(WriterLogger::new(try!(io::File::open_mode(path, io::FileMode::Append, io::FileAccess::Write))));
    }
}

impl <T: io::Writer + Send> api::Logger for WriterLogger<T> {
    fn log(&self, _level: &Level, message: &str) -> io::IoResult<()> {
        return self.writer.lock().write_line(message);
    }
}
<|endoftext|>


<commit_before>use crate::syntax::{Namespace, Pair, RustName, Symbol, Types};
use proc_macro2::{Ident, Span};
use std::iter;

impl Pair {
    pub fn new(namespace: Namespace, cxx: Ident, rust: Ident) -> Self {
        Self {
            namespace,
            cxx,
            rust,
        }
    }

    pub fn to_symbol(&self) -> Symbol {
        Symbol::from_idents(self.iter_all_segments())
    }

    pub fn to_fully_qualified(&self) -> String {
        let mut fully_qualified = String::new();
        for segment in self.iter_all_segments() {
            fully_qualified += "::";
            fully_qualified += &segment.to_string();
        }
        fully_qualified
    }

    fn iter_all_segments(&self) -> impl Iterator<Item = &Ident> {
        self.namespace.iter().chain(iter::once(&self.cxx))
    }
}

impl RustName {
    pub fn new(ident: Ident) -> Self {
        Self { rust: ident }
    }

    pub fn from_ref(ident: &Ident) -> &Self {
        unsafe { &*(ident as *const Ident as *const Self) }
    }

    pub fn span(&self) -> Span {
        self.rust.span()
    }

    pub fn to_symbol(&self, types: &Types) -> Symbol {
        types.resolve(self).to_symbol()
    }
}
<commit_msg>Touch up Pair and RustName construction for consistency<commit_after>use crate::syntax::{Namespace, Pair, RustName, Symbol, Types};
use proc_macro2::{Ident, Span};
use std::iter;

impl Pair {
    pub fn new(namespace: Namespace, cxx: Ident, rust: Ident) -> Self {
        Pair {
            namespace,
            cxx,
            rust,
        }
    }

    pub fn to_symbol(&self) -> Symbol {
        Symbol::from_idents(self.iter_all_segments())
    }

    pub fn to_fully_qualified(&self) -> String {
        let mut fully_qualified = String::new();
        for segment in self.iter_all_segments() {
            fully_qualified += "::";
            fully_qualified += &segment.to_string();
        }
        fully_qualified
    }

    fn iter_all_segments(&self) -> impl Iterator<Item = &Ident> {
        self.namespace.iter().chain(iter::once(&self.cxx))
    }
}

impl RustName {
    pub fn new(rust: Ident) -> Self {
        RustName { rust }
    }

    pub fn from_ref(rust: &Ident) -> &Self {
        unsafe { &*(rust as *const Ident as *const Self) }
    }

    pub fn span(&self) -> Span {
        self.rust.span()
    }

    pub fn to_symbol(&self, types: &Types) -> Symbol {
        types.resolve(self).to_symbol()
    }
}
<|endoftext|>


<commit_before>//! Lua functionality

use hlua;
use hlua::{Lua, LuaError};
use hlua::any::AnyLuaValue;

use rustc_serialize::json::Json;

use std::thread;
use std::fs::{File};
use std::path::Path;
use std::io::Write;
use std::fmt::{Debug, Formatter};
use std::fmt::Result as FmtResult;

use std::sync::{Mutex, RwLock};
use std::sync::mpsc::{channel, Sender, Receiver};

#[macro_use]
mod funcs;
#[cfg(test)]
mod tests;

lazy_static! {
    /// Sends requests to the lua thread
    static ref SENDER: Mutex<Option<Sender<LuaMessage>>> = Mutex::new(None);

    /// Whether the lua thread is currently running
    pub static ref RUNNING: RwLock<bool> = RwLock::new(false);
}

/// Represents an identifier for dealing with nested tables.
///
/// To access foo.bar.baz, use vec!["foo", "bar", "baz"].
///
/// To access foo[2], use vec!["foo", 2].
pub type LuaIdentifier = Vec<AnyLuaValue>;

/// Messages sent to the lua thread
#[derive(Debug)]
pub enum LuaQuery {
    /// Pings the lua thread
    Ping,
    /// Halt the lua thread
    Terminate,
    // Restart the lua thread
    Restart,

    /// Execute a string
    Execute(String),
    /// Execute a file
    ExecFile(String),

    /// Get a variable, expecting an AnyLuaValue
    GetValue(LuaIdentifier),
    /// Invoke a function found at the position,
    /// with the specified arguments.
    Invoke(LuaIdentifier, Vec<AnyLuaValue>),
    /// Set a value
    SetValue {
        /// The name of the thing to stuff
        name: LuaIdentifier,
        /// The value to store.
        val: Json
    },
    /// Create a new table
    NewTable(LuaIdentifier),
}

/// Messages received from lua thread
pub enum LuaResponse {
    /// Lua variable obtained
    Variable(Option<AnyLuaValue>),
    /// Lua error
    Error(hlua::LuaError),
    /// A function is returned
    Function(hlua::functions_read::LuaFunction<String>),
    /// Pong response from lua ping
    Pong,
}

/// Struct sent to the lua query
#[derive(Debug)]
struct LuaMessage {
    reply: Sender<LuaResponse>,
    query: LuaQuery
}

unsafe impl Send for LuaQuery { }
unsafe impl Sync for LuaQuery { }
unsafe impl Send for LuaResponse { }
unsafe impl Sync for LuaResponse { }
unsafe impl Send for LuaMessage { }
unsafe impl Sync for LuaMessage { }

impl Debug for LuaResponse {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        match *self {
            LuaResponse::Variable(ref var) =>
                write!(f, "LuaResponse::Variable({:?})", var),
            LuaResponse::Error(ref err) =>
                write!(f, "LuaResponse::Error({:?})", err),
            LuaResponse::Function(_) =>
                write!(f, "LuaResponse::Function"),
            LuaResponse::Pong =>
                write!(f, "LuaResponse::Pong")
        }
    }
}

/// Whether the lua thread is currently available
pub fn thread_running() -> bool {
    *RUNNING.read().unwrap()
}

/// Errors which may arise from attempting
/// to sending a message to the lua thread.
#[derive(Debug)]
pub enum LuaSendError {
    /// The thread crashed, was shut down, or rebooted.
    ThreadClosed,
    /// The thread has not been initialized yet (maybe not used)
    ThreadUninitialized,
    /// The sender had an issue, most likey because the thread panicked.
    /// Following the `Sender` API, the original value sent is returned.
    Sender(LuaQuery)
}

/// Attemps to send a LuaQuery to the lua thread.
pub fn try_send(query: LuaQuery) -> Result<Receiver<LuaResponse>,LuaSendError> {
    if !thread_running() {
        Err(LuaSendError::ThreadClosed)
    }
    else if let Some(ref sender) = *SENDER.lock().unwrap() {
        let (tx, rx) = channel();
        let message = LuaMessage { reply: tx, query: query };
        match sender.send(message) {
            Ok(_) => Ok(rx),
            Err(e) => Err(LuaSendError::Sender(e.0.query))
        }
    }
    else {
        Err(LuaSendError::ThreadUninitialized)
    }
}

/// Initialize the lua thread
pub fn init() {
    trace!("Initializing...");
    let (query_tx, query_rx) = channel::<LuaMessage>();
    {
        let mut sender = SENDER.lock().unwrap();
        *sender = Some(query_tx);
    }

    thread::spawn(move || {
        thread_init(query_rx);
    });
    trace!("Created thread. Init finished.");
}

fn thread_init(receiver: Receiver<LuaMessage>) {
    trace!("thread: initializing.");
    let mut lua = Lua::new();
    //unsafe {
    //    hlua_ffi::lua_atpanic(&mut lua.as_mut_lua().0, thread_on_panic);
    //}
    debug!("thread: Loading Lua libraries...");
    lua.openlibs();
    trace!("thread: Loading way-cooler lua extensions...");
    // We should have some good file handling, read files from /usr by default,
    // but for now we're reading directly from the source.
    lua.execute_from_reader::<(), File>(
        File::open("lib/lua/init.lua").unwrap()
    ).unwrap();
    trace!("thread: loading way-cooler libraries...");
    funcs::register_libraries(&mut lua);
    // Only ready after loading libs
    *RUNNING.write().unwrap() = true;
    debug!("thread: entering main loop...");
    thread_main_loop(receiver, &mut lua);
}

fn thread_main_loop(receiver: Receiver<LuaMessage>, lua: &mut Lua) {
    loop {
        let request = receiver.recv();
        match request {
            Err(e) => {
                error!("Lua thread: unable to receive message: {}", e);
                error!("Lua thread: now panicking!");
                *RUNNING.write().unwrap() = false;

                panic!("Lua thread: lost contact with host, exiting!");
            }
            Ok(message) => {
                trace!("Handling a request");
                thread_handle_message(message, lua);
            }
        }
    }
}

fn thread_handle_message(request: LuaMessage, lua: &mut Lua) {
    match request.query {
        LuaQuery::Terminate => {
            trace!("thread: Received terminate signal");
            *RUNNING.write().unwrap() = false;

            info!("thread: Lua thread terminating!");
            thread_send(request.reply, LuaResponse::Pong);
            return;
        },

        LuaQuery::Restart => {
            trace!("thread: Received restart signal!");
            error!("thread: Lua thread restart not supported!");

            *RUNNING.write().unwrap() = false;
            thread_send(request.reply, LuaResponse::Pong);

            panic!("Lua thread: Restart not supported!");
        },

        LuaQuery::Execute(code) => {
            trace!("thread: Received request to execute code");
            trace!("thread: Executing {:?}", code);

            match lua.execute::<()>(&code) {
                Err(error) => {
                    warn!("thread: Error executing code: {:?}", error);
                    let response = LuaResponse::Error(error);

                    thread_send(request.reply, response);
                }
                Ok(_) => {
                    // This is gonna be really spammy one day
                    trace!("thread: Code executed okay.");
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
        },

        LuaQuery::ExecFile(name) => {
            trace!("thread: Received request to execute file {}", name);
            info!("thread: Executing {}", name);

            let path = Path::new(&name);
            let try_file = File::open(path);

            if let Ok(file) = try_file {
                let result = lua.execute_from_reader::<(), File>(file);
                if let Err(err) = result {
                    warn!("thread: Error executing {}!", name);

                    thread_send(request.reply, LuaResponse::Error(err));
                }
                else {
                    trace!("thread: Execution of {} successful.", name);
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
            else { // Could not open file
                // Unwrap_err is used because we're in the else of let
                let read_error =
                    LuaError::ReadError(try_file.unwrap_err());

                thread_send(request.reply, LuaResponse::Error(read_error));
            }
        },

        LuaQuery::GetValue(varname) => {
            trace!("thread: Received request to get variable {:?}", varname);
            let var_result = lua.get(format!("{:?}", varname));

            match var_result {
                Some(var) => {
                    thread_send(request.reply, LuaResponse::Variable(Some(var)));
                }
                None => {
                    warn!("thread: Unable to get variable {:?}", varname);

                    thread_send(request.reply, LuaResponse::Variable(None));
                }
            }
        },

        LuaQuery::SetValue { name: _name, val: _val } => {
            panic!("thread: unimplemented LuaQuery::SetValue!");
        },

        LuaQuery::NewTable(_name) => {
            panic!("thread: unimplemented LuaQuery::NewTable!");
        },

        LuaQuery::Ping => {
            panic!("thread: unimplemented LuaQuery::Ping!");
        },
        _ => {
            panic!("Unimplemented send type for lua thread!");
        }
    }
}

fn thread_send(sender: Sender<LuaResponse>, response: LuaResponse) {
    match sender.send(response) {
        Err(_) => {
            error!("thread: Unable to broadcast response!");
            error!("thread: Shutting down in response to inability \
                    to continue!");
            *RUNNING.write().unwrap() = false;
            panic!("Lua thread unable to communicate with main thread, \
                    shutting down!");
        }
        Ok(_) => {}
    }
}
<commit_msg>Clone sender when sending for less time locking<commit_after>//! Lua functionality

use hlua;
use hlua::{Lua, LuaError};
use hlua::any::AnyLuaValue;

use rustc_serialize::json::Json;

use std::thread;
use std::fs::{File};
use std::path::Path;
use std::io::Write;
use std::fmt::{Debug, Formatter};
use std::fmt::Result as FmtResult;

use std::sync::{Mutex, RwLock};
use std::sync::mpsc::{channel, Sender, Receiver};

#[macro_use]
mod funcs;
#[cfg(test)]
mod tests;

lazy_static! {
    /// Sends requests to the lua thread
    static ref SENDER: Mutex<Option<Sender<LuaMessage>>> = Mutex::new(None);

    /// Whether the lua thread is currently running
    pub static ref RUNNING: RwLock<bool> = RwLock::new(false);
}

/// Represents an identifier for dealing with nested tables.
///
/// To access foo.bar.baz, use vec!["foo", "bar", "baz"].
///
/// To access foo[2], use vec!["foo", 2].
pub type LuaIdentifier = Vec<AnyLuaValue>;

/// Messages sent to the lua thread
#[derive(Debug)]
pub enum LuaQuery {
    /// Pings the lua thread
    Ping,
    /// Halt the lua thread
    Terminate,
    // Restart the lua thread
    Restart,

    /// Execute a string
    Execute(String),
    /// Execute a file
    ExecFile(String),

    /// Get a variable, expecting an AnyLuaValue
    GetValue(LuaIdentifier),
    /// Invoke a function found at the position,
    /// with the specified arguments.
    Invoke(LuaIdentifier, Vec<AnyLuaValue>),
    /// Set a value
    SetValue {
        /// The name of the thing to stuff
        name: LuaIdentifier,
        /// The value to store.
        val: Json
    },
    /// Create a new table
    NewTable(LuaIdentifier),
}

/// Messages received from lua thread
pub enum LuaResponse {
    /// Lua variable obtained
    Variable(Option<AnyLuaValue>),
    /// Lua error
    Error(hlua::LuaError),
    /// A function is returned
    Function(hlua::functions_read::LuaFunction<String>),
    /// Pong response from lua ping
    Pong,
}

/// Struct sent to the lua query
#[derive(Debug)]
struct LuaMessage {
    reply: Sender<LuaResponse>,
    query: LuaQuery
}

unsafe impl Send for LuaQuery { }
unsafe impl Sync for LuaQuery { }
unsafe impl Send for LuaResponse { }
unsafe impl Sync for LuaResponse { }
unsafe impl Send for LuaMessage { }
unsafe impl Sync for LuaMessage { }

impl Debug for LuaResponse {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        match *self {
            LuaResponse::Variable(ref var) =>
                write!(f, "LuaResponse::Variable({:?})", var),
            LuaResponse::Error(ref err) =>
                write!(f, "LuaResponse::Error({:?})", err),
            LuaResponse::Function(_) =>
                write!(f, "LuaResponse::Function"),
            LuaResponse::Pong =>
                write!(f, "LuaResponse::Pong")
        }
    }
}

/// Whether the lua thread is currently available
pub fn thread_running() -> bool {
    *RUNNING.read().unwrap()
}

/// Errors which may arise from attempting
/// to sending a message to the lua thread.
#[derive(Debug)]
pub enum LuaSendError {
    /// The thread crashed, was shut down, or rebooted.
    ThreadClosed,
    /// The thread has not been initialized yet (maybe not used)
    ThreadUninitialized,
    /// The sender had an issue, most likey because the thread panicked.
    /// Following the `Sender` API, the original value sent is returned.
    Sender(LuaQuery)
}

/// Attemps to send a LuaQuery to the lua thread.
pub fn try_send(query: LuaQuery) -> Result<Receiver<LuaResponse>,LuaSendError> {
    if !thread_running() {
        Err(LuaSendError::ThreadClosed)
    }
    else if let Some(sender) = SENDER.lock().unwrap().clone() {
        let (tx, rx) = channel();
        let message = LuaMessage { reply: tx, query: query };
        match sender.send(message) {
            Ok(_) => Ok(rx),
            Err(e) => Err(LuaSendError::Sender(e.0.query))
        }
    }
    else {
        Err(LuaSendError::ThreadUninitialized)
    }
}

/// Initialize the lua thread
pub fn init() {
    trace!("Initializing...");
    let (query_tx, query_rx) = channel::<LuaMessage>();
    {
        let mut sender = SENDER.lock().unwrap();
        *sender = Some(query_tx);
    }

    thread::spawn(move || {
        thread_init(query_rx);
    });
    trace!("Created thread. Init finished.");
}

fn thread_init(receiver: Receiver<LuaMessage>) {
    trace!("thread: initializing.");
    let mut lua = Lua::new();
    //unsafe {
    //    hlua_ffi::lua_atpanic(&mut lua.as_mut_lua().0, thread_on_panic);
    //}
    debug!("thread: Loading Lua libraries...");
    lua.openlibs();
    trace!("thread: Loading way-cooler lua extensions...");
    // We should have some good file handling, read files from /usr by default,
    // but for now we're reading directly from the source.
    lua.execute_from_reader::<(), File>(
        File::open("lib/lua/init.lua").unwrap()
    ).unwrap();
    trace!("thread: loading way-cooler libraries...");
    funcs::register_libraries(&mut lua);
    // Only ready after loading libs
    *RUNNING.write().unwrap() = true;
    debug!("thread: entering main loop...");
    thread_main_loop(receiver, &mut lua);
}

fn thread_main_loop(receiver: Receiver<LuaMessage>, lua: &mut Lua) {
    loop {
        let request = receiver.recv();
        match request {
            Err(e) => {
                error!("Lua thread: unable to receive message: {}", e);
                error!("Lua thread: now panicking!");
                *RUNNING.write().unwrap() = false;

                panic!("Lua thread: lost contact with host, exiting!");
            }
            Ok(message) => {
                trace!("Handling a request");
                thread_handle_message(message, lua);
            }
        }
    }
}

fn thread_handle_message(request: LuaMessage, lua: &mut Lua) {
    match request.query {
        LuaQuery::Terminate => {
            trace!("thread: Received terminate signal");
            *RUNNING.write().unwrap() = false;

            info!("thread: Lua thread terminating!");
            thread_send(request.reply, LuaResponse::Pong);
            return;
        },

        LuaQuery::Restart => {
            trace!("thread: Received restart signal!");
            error!("thread: Lua thread restart not supported!");

            *RUNNING.write().unwrap() = false;
            thread_send(request.reply, LuaResponse::Pong);

            panic!("Lua thread: Restart not supported!");
        },

        LuaQuery::Execute(code) => {
            trace!("thread: Received request to execute code");
            trace!("thread: Executing {:?}", code);

            match lua.execute::<()>(&code) {
                Err(error) => {
                    warn!("thread: Error executing code: {:?}", error);
                    let response = LuaResponse::Error(error);

                    thread_send(request.reply, response);
                }
                Ok(_) => {
                    // This is gonna be really spammy one day
                    trace!("thread: Code executed okay.");
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
        },

        LuaQuery::ExecFile(name) => {
            trace!("thread: Received request to execute file {}", name);
            info!("thread: Executing {}", name);

            let path = Path::new(&name);
            let try_file = File::open(path);

            if let Ok(file) = try_file {
                let result = lua.execute_from_reader::<(), File>(file);
                if let Err(err) = result {
                    warn!("thread: Error executing {}!", name);

                    thread_send(request.reply, LuaResponse::Error(err));
                }
                else {
                    trace!("thread: Execution of {} successful.", name);
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
            else { // Could not open file
                // Unwrap_err is used because we're in the else of let
                let read_error =
                    LuaError::ReadError(try_file.unwrap_err());

                thread_send(request.reply, LuaResponse::Error(read_error));
            }
        },

        LuaQuery::GetValue(varname) => {
            trace!("thread: Received request to get variable {:?}", varname);
            let var_result = lua.get(format!("{:?}", varname));

            match var_result {
                Some(var) => {
                    thread_send(request.reply, LuaResponse::Variable(Some(var)));
                }
                None => {
                    warn!("thread: Unable to get variable {:?}", varname);

                    thread_send(request.reply, LuaResponse::Variable(None));
                }
            }
        },

        LuaQuery::SetValue { name: _name, val: _val } => {
            panic!("thread: unimplemented LuaQuery::SetValue!");
        },

        LuaQuery::NewTable(_name) => {
            panic!("thread: unimplemented LuaQuery::NewTable!");
        },

        LuaQuery::Ping => {
            panic!("thread: unimplemented LuaQuery::Ping!");
        },
        _ => {
            panic!("Unimplemented send type for lua thread!");
        }
    }
}

fn thread_send(sender: Sender<LuaResponse>, response: LuaResponse) {
    match sender.send(response) {
        Err(_) => {
            error!("thread: Unable to broadcast response!");
            error!("thread: Shutting down in response to inability \
                    to continue!");
            *RUNNING.write().unwrap() = false;
            panic!("Lua thread unable to communicate with main thread, \
                    shutting down!");
        }
        Ok(_) => {}
    }
}
<|endoftext|>


<commit_before>/* 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/. */

//! Helper module to build up a selector safely and efficiently.
//!
//! Our selector representation is designed to optimize matching, and has
//! several requirements:
//! * All simple selectors and combinators are stored inline in the same buffer
//!   as Component instances.
//! * We store the top-level compound selectors from right to left, i.e. in
//!   matching order.
//! * We store the simple selectors for each combinator from left to right, so
//!   that we match the cheaper simple selectors first.
//!
//! Meeting all these constraints without extra memmove traffic during parsing
//! is non-trivial. This module encapsulates those details and presents an
//! easy-to-use API for the parser.

use parser::{Combinator, Component, SelectorImpl};
use servo_arc::{Arc, HeaderWithLength, ThinArc};
use sink::Push;
use smallvec::{self, SmallVec};
use std::cmp;
use std::iter;
use std::ops::Add;
use std::ptr;
use std::slice;

/// Top-level SelectorBuilder struct. This should be stack-allocated by the
/// consumer and never moved (because it contains a lot of inline data that
/// would be slow to memmov).
///
/// After instantation, callers may call the push_simple_selector() and
/// push_combinator() methods to append selector data as it is encountered
/// (from left to right). Once the process is complete, callers should invoke
/// build(), which transforms the contents of the SelectorBuilder into a heap-
/// allocated Selector and leaves the builder in a drained state.
#[derive(Debug)]
pub struct SelectorBuilder<Impl: SelectorImpl> {
    /// The entire sequence of simple selectors, from left to right, without combinators.
    ///
    /// We make this large because the result of parsing a selector is fed into a new
    /// Arc-ed allocation, so any spilled vec would be a wasted allocation. Also,
    /// Components are large enough that we don't have much cache locality benefit
    /// from reserving stack space for fewer of them.
    simple_selectors: SmallVec<[Component<Impl>; 32]>,
    /// The combinators, and the length of the compound selector to their left.
    combinators: SmallVec<[(Combinator, usize); 16]>,
    /// The length of the current compount selector.
    current_len: usize,
}

impl<Impl: SelectorImpl> Default for SelectorBuilder<Impl> {
    #[inline(always)]
    fn default() -> Self {
        SelectorBuilder {
            simple_selectors: SmallVec::new(),
            combinators: SmallVec::new(),
            current_len: 0,
        }
    }
}

impl<Impl: SelectorImpl> Push<Component<Impl>> for SelectorBuilder<Impl> {
    fn push(&mut self, value: Component<Impl>) {
        self.push_simple_selector(value);
    }
}

impl<Impl: SelectorImpl> SelectorBuilder<Impl> {
    /// Pushes a simple selector onto the current compound selector.
    #[inline(always)]
    pub fn push_simple_selector(&mut self, ss: Component<Impl>) {
        debug_assert!(!ss.is_combinator());
        self.simple_selectors.push(ss);
        self.current_len += 1;
    }

    /// Completes the current compound selector and starts a new one, delimited
    /// by the given combinator.
    #[inline(always)]
    pub fn push_combinator(&mut self, c: Combinator) {
        self.combinators.push((c, self.current_len));
        self.current_len = 0;
    }

    /// Returns true if no simple selectors have ever been pushed to this builder.
    #[inline(always)]
    pub fn is_empty(&self) -> bool {
        self.simple_selectors.is_empty()
    }

    /// Returns true if combinators have ever been pushed to this builder.
    #[inline(always)]
    pub fn has_combinators(&self) -> bool {
        !self.combinators.is_empty()
    }

    /// Consumes the builder, producing a Selector.
    #[inline(always)]
    pub fn build(
        &mut self,
        parsed_pseudo: bool,
        parsed_slotted: bool,
    ) -> ThinArc<SpecificityAndFlags, Component<Impl>> {
        // Compute the specificity and flags.
        let mut spec = SpecificityAndFlags(specificity(&*self, self.simple_selectors.iter()));
        if parsed_pseudo {
            spec.0 |= HAS_PSEUDO_BIT;
        }

        if parsed_slotted {
            spec.0 |= HAS_SLOTTED_BIT;
        }

        self.build_with_specificity_and_flags(spec)
    }

    /// Builds with an explicit SpecificityAndFlags. This is separated from build() so
    /// that unit tests can pass an explicit specificity.
    #[inline(always)]
    pub fn build_with_specificity_and_flags(
        &mut self,
        spec: SpecificityAndFlags,
    ) -> ThinArc<SpecificityAndFlags, Component<Impl>> {
        // First, compute the total number of Components we'll need to allocate
        // space for.
        let full_len = self.simple_selectors.len() + self.combinators.len();

        // Create the header.
        let header = HeaderWithLength::new(spec, full_len);

        // Create the Arc using an iterator that drains our buffers.

        // Use a raw pointer to be able to call set_len despite "borrowing" the slice.
        // This is similar to SmallVec::drain, but we use a slice here because
        // we’re gonna traverse it non-linearly.
        let raw_simple_selectors: *const [Component<Impl>] = &*self.simple_selectors;
        unsafe {
            // Panic-safety: if SelectorBuilderIter is not iterated to the end,
            // some simple selectors will safely leak.
            self.simple_selectors.set_len(0)
        }
        let (rest, current) = split_from_end(unsafe { &*raw_simple_selectors }, self.current_len);
        let iter = SelectorBuilderIter {
            current_simple_selectors: current.iter(),
            rest_of_simple_selectors: rest,
            combinators: self.combinators.drain().rev(),
        };

        Arc::into_thin(Arc::from_header_and_iter(header, iter))
    }
}

struct SelectorBuilderIter<'a, Impl: SelectorImpl> {
    current_simple_selectors: slice::Iter<'a, Component<Impl>>,
    rest_of_simple_selectors: &'a [Component<Impl>],
    combinators: iter::Rev<smallvec::Drain<'a, (Combinator, usize)>>,
}

impl<'a, Impl: SelectorImpl> ExactSizeIterator for SelectorBuilderIter<'a, Impl> {
    fn len(&self) -> usize {
        self.current_simple_selectors.len() + self.rest_of_simple_selectors.len() +
            self.combinators.len()
    }
}

impl<'a, Impl: SelectorImpl> Iterator for SelectorBuilderIter<'a, Impl> {
    type Item = Component<Impl>;
    #[inline(always)]
    fn next(&mut self) -> Option<Self::Item> {
        if let Some(simple_selector_ref) = self.current_simple_selectors.next() {
            // Move a simple selector out of this slice iterator.
            // This is safe because we’ve called SmallVec::set_len(0) above,
            // so SmallVec::drop won’t drop this simple selector.
            unsafe { Some(ptr::read(simple_selector_ref)) }
        } else {
            self.combinators.next().map(|(combinator, len)| {
                let (rest, current) = split_from_end(self.rest_of_simple_selectors, len);
                self.rest_of_simple_selectors = rest;
                self.current_simple_selectors = current.iter();
                Component::Combinator(combinator)
            })
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.len(), Some(self.len()))
    }
}

fn split_from_end<T>(s: &[T], at: usize) -> (&[T], &[T]) {
    s.split_at(s.len() - at)
}

pub const HAS_PSEUDO_BIT: u32 = 1 << 30;
pub const HAS_SLOTTED_BIT: u32 = 1 << 31;

/// We use ten bits for each specificity kind (id, class, element), and the two
/// high bits for the pseudo and slotted flags.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct SpecificityAndFlags(pub u32);

impl SpecificityAndFlags {
    #[inline]
    pub fn specificity(&self) -> u32 {
        self.0 & !(HAS_PSEUDO_BIT | HAS_SLOTTED_BIT)
    }

    #[inline]
    pub fn has_pseudo_element(&self) -> bool {
        (self.0 & HAS_PSEUDO_BIT) != 0
    }

    #[inline]
    pub fn is_slotted(&self) -> bool {
        (self.0 & HAS_SLOTTED_BIT) != 0
    }
}

const MAX_10BIT: u32 = (1u32 << 10) - 1;

#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
struct Specificity {
    id_selectors: u32,
    class_like_selectors: u32,
    element_selectors: u32,
}

impl Add for Specificity {
    type Output = Specificity;

    fn add(self, rhs: Specificity) -> Specificity {
        Specificity {
            id_selectors: self.id_selectors + rhs.id_selectors,
            class_like_selectors: self.class_like_selectors + rhs.class_like_selectors,
            element_selectors: self.element_selectors + rhs.element_selectors,
        }
    }
}

impl Default for Specificity {
    fn default() -> Specificity {
        Specificity {
            id_selectors: 0,
            class_like_selectors: 0,
            element_selectors: 0,
        }
    }
}

impl From<u32> for Specificity {
    fn from(value: u32) -> Specificity {
        assert!(value <= MAX_10BIT << 20 | MAX_10BIT << 10 | MAX_10BIT);
        Specificity {
            id_selectors: value >> 20,
            class_like_selectors: (value >> 10) & MAX_10BIT,
            element_selectors: value & MAX_10BIT,
        }
    }
}

impl From<Specificity> for u32 {
    fn from(specificity: Specificity) -> u32 {
        cmp::min(specificity.id_selectors, MAX_10BIT) << 20 |
            cmp::min(specificity.class_like_selectors, MAX_10BIT) << 10 |
            cmp::min(specificity.element_selectors, MAX_10BIT)
    }
}

fn specificity<Impl>(builder: &SelectorBuilder<Impl>, iter: slice::Iter<Component<Impl>>) -> u32
where
    Impl: SelectorImpl,
{
    complex_selector_specificity(builder, iter).into()
}

fn complex_selector_specificity<Impl>(
    builder: &SelectorBuilder<Impl>,
    mut iter: slice::Iter<Component<Impl>>,
) -> Specificity
where
    Impl: SelectorImpl,
{
    fn simple_selector_specificity<Impl>(
        builder: &SelectorBuilder<Impl>,
        simple_selector: &Component<Impl>,
        specificity: &mut Specificity,
    ) where
        Impl: SelectorImpl,
    {
        match *simple_selector {
            Component::Combinator(ref combinator) => {
                unreachable!(
                    "Found combinator {:?} in simple selectors vector? {:?}",
                    combinator,
                    builder,
                );
            }
            // FIXME(emilio): Spec doesn't define any particular specificity for
            // ::slotted(), so apply the general rule for pseudos per:
            //
            // https://github.com/w3c/csswg-drafts/issues/1915
            //
            // Though other engines compute it dynamically, so maybe we should
            // do that instead, eventually.
            Component::Slotted(..) | Component::PseudoElement(..) | Component::LocalName(..) => {
                specificity.element_selectors += 1
            },
            Component::ID(..) => specificity.id_selectors += 1,
            Component::Class(..) |
            Component::AttributeInNoNamespace { .. } |
            Component::AttributeInNoNamespaceExists { .. } |
            Component::AttributeOther(..) |
            Component::FirstChild |
            Component::LastChild |
            Component::OnlyChild |
            Component::Root |
            Component::Empty |
            Component::Scope |
            Component::Host(..) |
            Component::NthChild(..) |
            Component::NthLastChild(..) |
            Component::NthOfType(..) |
            Component::NthLastOfType(..) |
            Component::FirstOfType |
            Component::LastOfType |
            Component::OnlyOfType |
            Component::NonTSPseudoClass(..) => specificity.class_like_selectors += 1,
            Component::ExplicitUniversalType |
            Component::ExplicitAnyNamespace |
            Component::ExplicitNoNamespace |
            Component::DefaultNamespace(..) |
            Component::Namespace(..) => {
                // Does not affect specificity
            },
            Component::Negation(ref negated) => {
                for ss in negated.iter() {
                    simple_selector_specificity(builder, &ss, specificity);
                }
            },
        }
    }

    let mut specificity = Default::default();
    for simple_selector in &mut iter {
        simple_selector_specificity(builder, &simple_selector, &mut specificity);
    }
    specificity
}
<commit_msg>style: Make :host() and ::slotted() account for the inner selector's specificity.<commit_after>/* 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/. */

//! Helper module to build up a selector safely and efficiently.
//!
//! Our selector representation is designed to optimize matching, and has
//! several requirements:
//! * All simple selectors and combinators are stored inline in the same buffer
//!   as Component instances.
//! * We store the top-level compound selectors from right to left, i.e. in
//!   matching order.
//! * We store the simple selectors for each combinator from left to right, so
//!   that we match the cheaper simple selectors first.
//!
//! Meeting all these constraints without extra memmove traffic during parsing
//! is non-trivial. This module encapsulates those details and presents an
//! easy-to-use API for the parser.

use parser::{Combinator, Component, SelectorImpl};
use servo_arc::{Arc, HeaderWithLength, ThinArc};
use sink::Push;
use smallvec::{self, SmallVec};
use std::cmp;
use std::iter;
use std::ops::{AddAssign, Add};
use std::ptr;
use std::slice;

/// Top-level SelectorBuilder struct. This should be stack-allocated by the
/// consumer and never moved (because it contains a lot of inline data that
/// would be slow to memmov).
///
/// After instantation, callers may call the push_simple_selector() and
/// push_combinator() methods to append selector data as it is encountered
/// (from left to right). Once the process is complete, callers should invoke
/// build(), which transforms the contents of the SelectorBuilder into a heap-
/// allocated Selector and leaves the builder in a drained state.
#[derive(Debug)]
pub struct SelectorBuilder<Impl: SelectorImpl> {
    /// The entire sequence of simple selectors, from left to right, without combinators.
    ///
    /// We make this large because the result of parsing a selector is fed into a new
    /// Arc-ed allocation, so any spilled vec would be a wasted allocation. Also,
    /// Components are large enough that we don't have much cache locality benefit
    /// from reserving stack space for fewer of them.
    simple_selectors: SmallVec<[Component<Impl>; 32]>,
    /// The combinators, and the length of the compound selector to their left.
    combinators: SmallVec<[(Combinator, usize); 16]>,
    /// The length of the current compount selector.
    current_len: usize,
}

impl<Impl: SelectorImpl> Default for SelectorBuilder<Impl> {
    #[inline(always)]
    fn default() -> Self {
        SelectorBuilder {
            simple_selectors: SmallVec::new(),
            combinators: SmallVec::new(),
            current_len: 0,
        }
    }
}

impl<Impl: SelectorImpl> Push<Component<Impl>> for SelectorBuilder<Impl> {
    fn push(&mut self, value: Component<Impl>) {
        self.push_simple_selector(value);
    }
}

impl<Impl: SelectorImpl> SelectorBuilder<Impl> {
    /// Pushes a simple selector onto the current compound selector.
    #[inline(always)]
    pub fn push_simple_selector(&mut self, ss: Component<Impl>) {
        debug_assert!(!ss.is_combinator());
        self.simple_selectors.push(ss);
        self.current_len += 1;
    }

    /// Completes the current compound selector and starts a new one, delimited
    /// by the given combinator.
    #[inline(always)]
    pub fn push_combinator(&mut self, c: Combinator) {
        self.combinators.push((c, self.current_len));
        self.current_len = 0;
    }

    /// Returns true if no simple selectors have ever been pushed to this builder.
    #[inline(always)]
    pub fn is_empty(&self) -> bool {
        self.simple_selectors.is_empty()
    }

    /// Returns true if combinators have ever been pushed to this builder.
    #[inline(always)]
    pub fn has_combinators(&self) -> bool {
        !self.combinators.is_empty()
    }

    /// Consumes the builder, producing a Selector.
    #[inline(always)]
    pub fn build(
        &mut self,
        parsed_pseudo: bool,
        parsed_slotted: bool,
    ) -> ThinArc<SpecificityAndFlags, Component<Impl>> {
        // Compute the specificity and flags.
        let mut spec = SpecificityAndFlags(specificity(&*self, self.simple_selectors.iter()));
        if parsed_pseudo {
            spec.0 |= HAS_PSEUDO_BIT;
        }

        if parsed_slotted {
            spec.0 |= HAS_SLOTTED_BIT;
        }

        self.build_with_specificity_and_flags(spec)
    }

    /// Builds with an explicit SpecificityAndFlags. This is separated from build() so
    /// that unit tests can pass an explicit specificity.
    #[inline(always)]
    pub fn build_with_specificity_and_flags(
        &mut self,
        spec: SpecificityAndFlags,
    ) -> ThinArc<SpecificityAndFlags, Component<Impl>> {
        // First, compute the total number of Components we'll need to allocate
        // space for.
        let full_len = self.simple_selectors.len() + self.combinators.len();

        // Create the header.
        let header = HeaderWithLength::new(spec, full_len);

        // Create the Arc using an iterator that drains our buffers.

        // Use a raw pointer to be able to call set_len despite "borrowing" the slice.
        // This is similar to SmallVec::drain, but we use a slice here because
        // we’re gonna traverse it non-linearly.
        let raw_simple_selectors: *const [Component<Impl>] = &*self.simple_selectors;
        unsafe {
            // Panic-safety: if SelectorBuilderIter is not iterated to the end,
            // some simple selectors will safely leak.
            self.simple_selectors.set_len(0)
        }
        let (rest, current) = split_from_end(unsafe { &*raw_simple_selectors }, self.current_len);
        let iter = SelectorBuilderIter {
            current_simple_selectors: current.iter(),
            rest_of_simple_selectors: rest,
            combinators: self.combinators.drain().rev(),
        };

        Arc::into_thin(Arc::from_header_and_iter(header, iter))
    }
}

struct SelectorBuilderIter<'a, Impl: SelectorImpl> {
    current_simple_selectors: slice::Iter<'a, Component<Impl>>,
    rest_of_simple_selectors: &'a [Component<Impl>],
    combinators: iter::Rev<smallvec::Drain<'a, (Combinator, usize)>>,
}

impl<'a, Impl: SelectorImpl> ExactSizeIterator for SelectorBuilderIter<'a, Impl> {
    fn len(&self) -> usize {
        self.current_simple_selectors.len() + self.rest_of_simple_selectors.len() +
            self.combinators.len()
    }
}

impl<'a, Impl: SelectorImpl> Iterator for SelectorBuilderIter<'a, Impl> {
    type Item = Component<Impl>;
    #[inline(always)]
    fn next(&mut self) -> Option<Self::Item> {
        if let Some(simple_selector_ref) = self.current_simple_selectors.next() {
            // Move a simple selector out of this slice iterator.
            // This is safe because we’ve called SmallVec::set_len(0) above,
            // so SmallVec::drop won’t drop this simple selector.
            unsafe { Some(ptr::read(simple_selector_ref)) }
        } else {
            self.combinators.next().map(|(combinator, len)| {
                let (rest, current) = split_from_end(self.rest_of_simple_selectors, len);
                self.rest_of_simple_selectors = rest;
                self.current_simple_selectors = current.iter();
                Component::Combinator(combinator)
            })
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.len(), Some(self.len()))
    }
}

fn split_from_end<T>(s: &[T], at: usize) -> (&[T], &[T]) {
    s.split_at(s.len() - at)
}

pub const HAS_PSEUDO_BIT: u32 = 1 << 30;
pub const HAS_SLOTTED_BIT: u32 = 1 << 31;

/// We use ten bits for each specificity kind (id, class, element), and the two
/// high bits for the pseudo and slotted flags.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct SpecificityAndFlags(pub u32);

impl SpecificityAndFlags {
    #[inline]
    pub fn specificity(&self) -> u32 {
        self.0 & !(HAS_PSEUDO_BIT | HAS_SLOTTED_BIT)
    }

    #[inline]
    pub fn has_pseudo_element(&self) -> bool {
        (self.0 & HAS_PSEUDO_BIT) != 0
    }

    #[inline]
    pub fn is_slotted(&self) -> bool {
        (self.0 & HAS_SLOTTED_BIT) != 0
    }
}

const MAX_10BIT: u32 = (1u32 << 10) - 1;

#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
struct Specificity {
    id_selectors: u32,
    class_like_selectors: u32,
    element_selectors: u32,
}

impl AddAssign for Specificity {
    #[inline]
    fn add_assign(&mut self, rhs: Self) {
        self.id_selectors += rhs.id_selectors;
        self.class_like_selectors += rhs.class_like_selectors;
        self.element_selectors += rhs.element_selectors;
    }
}

impl Add for Specificity {
    type Output = Specificity;

    fn add(self, rhs: Specificity) -> Specificity {
        Specificity {
            id_selectors: self.id_selectors + rhs.id_selectors,
            class_like_selectors: self.class_like_selectors + rhs.class_like_selectors,
            element_selectors: self.element_selectors + rhs.element_selectors,
        }
    }
}

impl Default for Specificity {
    fn default() -> Specificity {
        Specificity {
            id_selectors: 0,
            class_like_selectors: 0,
            element_selectors: 0,
        }
    }
}

impl From<u32> for Specificity {
    #[inline]
    fn from(value: u32) -> Specificity {
        assert!(value <= MAX_10BIT << 20 | MAX_10BIT << 10 | MAX_10BIT);
        Specificity {
            id_selectors: value >> 20,
            class_like_selectors: (value >> 10) & MAX_10BIT,
            element_selectors: value & MAX_10BIT,
        }
    }
}

impl From<Specificity> for u32 {
    #[inline]
    fn from(specificity: Specificity) -> u32 {
        cmp::min(specificity.id_selectors, MAX_10BIT) << 20 |
            cmp::min(specificity.class_like_selectors, MAX_10BIT) << 10 |
            cmp::min(specificity.element_selectors, MAX_10BIT)
    }
}

fn specificity<Impl>(builder: &SelectorBuilder<Impl>, iter: slice::Iter<Component<Impl>>) -> u32
where
    Impl: SelectorImpl,
{
    complex_selector_specificity(builder, iter).into()
}

fn complex_selector_specificity<Impl>(
    builder: &SelectorBuilder<Impl>,
    mut iter: slice::Iter<Component<Impl>>,
) -> Specificity
where
    Impl: SelectorImpl,
{
    fn simple_selector_specificity<Impl>(
        builder: &SelectorBuilder<Impl>,
        simple_selector: &Component<Impl>,
        specificity: &mut Specificity,
    ) where
        Impl: SelectorImpl,
    {
        match *simple_selector {
            Component::Combinator(ref combinator) => {
                unreachable!(
                    "Found combinator {:?} in simple selectors vector? {:?}",
                    combinator,
                    builder,
                );
            }
            Component::PseudoElement(..) | Component::LocalName(..) => {
                specificity.element_selectors += 1
            },
            Component::Slotted(ref selector) => {
                specificity.element_selectors += 1;
                // Note that due to the way ::slotted works we only compete with
                // other ::slotted rules, so the above rule doesn't really
                // matter, but we do it still for consistency with other
                // pseudo-elements.
                //
                // See: https://github.com/w3c/csswg-drafts/issues/1915
                *specificity += Specificity::from(selector.specificity());
            },
            Component::Host(ref selector) => {
                specificity.class_like_selectors += 1;
                if let Some(ref selector) = *selector {
                    // See: https://github.com/w3c/csswg-drafts/issues/1915
                    *specificity += Specificity::from(selector.specificity());
                }
            }
            Component::ID(..) => {
                specificity.id_selectors += 1;
            },
            Component::Class(..) |
            Component::AttributeInNoNamespace { .. } |
            Component::AttributeInNoNamespaceExists { .. } |
            Component::AttributeOther(..) |
            Component::FirstChild |
            Component::LastChild |
            Component::OnlyChild |
            Component::Root |
            Component::Empty |
            Component::Scope |
            Component::NthChild(..) |
            Component::NthLastChild(..) |
            Component::NthOfType(..) |
            Component::NthLastOfType(..) |
            Component::FirstOfType |
            Component::LastOfType |
            Component::OnlyOfType |
            Component::NonTSPseudoClass(..) => {
                specificity.class_like_selectors += 1;
            },
            Component::ExplicitUniversalType |
            Component::ExplicitAnyNamespace |
            Component::ExplicitNoNamespace |
            Component::DefaultNamespace(..) |
            Component::Namespace(..) => {
                // Does not affect specificity
            },
            Component::Negation(ref negated) => {
                for ss in negated.iter() {
                    simple_selector_specificity(builder, &ss, specificity);
                }
            },
        }
    }

    let mut specificity = Default::default();
    for simple_selector in &mut iter {
        simple_selector_specificity(builder, &simple_selector, &mut specificity);
    }
    specificity
}
<|endoftext|>


<commit_before>use std::collections::{HashMap};

use num::bigint::{BigInt};

use opcode::{OpCode, BooleanOrInt};
use value::{Value};

pub struct Machine {
    stack: Vec<Value>,
    memo: HashMap<usize, Value>,
    marker: Option<usize>,
}

impl Machine {
    fn new() -> Self {
        Machine {
            stack: Vec::new(),
            memo: HashMap::new(),
            marker: None,
        }
    }

    fn split_off(&mut self, at: usize) -> Vec<Value> {
        if at > self.stack.len() {
            panic!("Stack too small");
        }
        self.stack.split_off(at)
    }

    fn pop(&mut self) -> Value {
        match self.stack.pop() {
            None => panic!("Empty stack"),
            Some(value) => value,
        }
    }

    fn execute(&mut self, opcode: OpCode) {
        match opcode {
            OpCode::Proto(_) => (),
            OpCode::Stop => (),  // TODO: !!!

            OpCode::Int(value) => {
                self.stack.push(match value {
                    BooleanOrInt::Boolean(v) => Value::Bool(v),
                    BooleanOrInt::Int(v) => Value::Int(BigInt::from(v)),
                })
            },
            OpCode::BinInt(i) => self.stack.push(Value::Int(BigInt::from(i))),
            OpCode::BinInt1(i) => self.stack.push(Value::Int(BigInt::from(i))),
            OpCode::BinInt2(i) => self.stack.push(Value::Int(BigInt::from(i))),
            OpCode::Long(i) => self.stack.push(Value::Int(BigInt::from(i))),
            OpCode::Long1(i) => self.stack.push(Value::Int(BigInt::from(i))),
            OpCode::Long4(i) => self.stack.push(Value::Int(BigInt::from(i))),

            OpCode::String(s) => self.stack.push(Value::String(s)),
            OpCode::BinString(s) => self.stack.push(Value::String(s)),
            OpCode::ShortBinString(s) => self.stack.push(Value::String(s)),

            OpCode::None => self.stack.push(Value::None),

            OpCode::NewTrue => self.stack.push(Value::Bool(true)),
            OpCode::NewFalse => self.stack.push(Value::Bool(false)),

            OpCode::Unicode(s) => self.stack.push(Value::Unicode(s)),
            OpCode::BinUnicode(s) => self.stack.push(Value::Unicode(s)),

            OpCode::Float(i) => self.stack.push(Value::Float(i)),
            OpCode::BinFloat(i) => self.stack.push(Value::Float(i)),

            OpCode::EmptyList => self.stack.push(Value::List(Vec::new())),
            OpCode::Append => {
                let v = self.pop();
                match self.stack.last_mut() {
                    None => panic!("Empty stack"),
                    Some(&mut Value::List(ref mut list)) => list.push(v),
                    _ => panic!("Invalid value on stack"),
                }
            },
            OpCode::Appends => {
                match self.marker {
                    None => panic!("Empty marker"),
                    Some(marker) => {
                        let values = self.split_off(marker);
                        match self.stack.last_mut() {
                            None => panic!("Empty stack"),
                            Some(&mut Value::List(ref mut list)) => {
                                list.extend(values);
                            },
                            _ => panic!("Invalid value on stack"),
                        }
                    }
                }
            },
            OpCode::List => {
                match self.marker {
                    None => panic!("Empty marker"),
                    Some(marker) => {
                        let values = self.split_off(marker);
                        self.stack.push(Value::List(values));
                    }
                }
            },

            OpCode::EmptyTuple => self.stack.push(Value::Tuple(Vec::new())),
            OpCode::Tuple => {
                match self.marker {
                    None => panic!("Empty marker"),
                    Some(marker) => {
                        let values = self.split_off(marker);
                        self.stack.push(Value::Tuple(values));
                    }
                }
            },
            OpCode::Tuple1 => {
                let v1 = self.pop();
                self.stack.push(Value::Tuple(vec![v1]))
            },
            OpCode::Tuple2 => {
                let v1 = self.pop();
                let v2 = self.pop();
                self.stack.push(Value::Tuple(vec![v1, v2]))
            },
            OpCode::Tuple3 => {
                let v1 = self.pop();
                let v2 = self.pop();
                let v3 = self.pop();
                self.stack.push(Value::Tuple(vec![v1, v2, v3]))
            }

            OpCode::EmptyDict => self.stack.push(Value::Dict(Vec::new())),
            OpCode::Dict => {
                match self.marker {
                    None => panic!("Empty marker"),
                    Some(marker) => {
                        let mut values = self.split_off(marker);
                        let mut dict = Vec::new();

                        for i in 0 .. values.len() / 2 { // TODO: Check panic
                            let key = values.remove(2 * i);
                            let value = values.remove(2 * i + 1);
                            dict.push((key, value));
                        }
                        self.stack.push(Value::Dict(dict));
                    }
                }
            },
            OpCode::SetItem => {
                let value = self.pop();
                let key = self.pop();
                match self.stack.last_mut() {
                    None => panic!("Empty stack"),
                    Some(&mut Value::Dict(ref mut dict)) => dict.push((key, value)),
                    _ => panic!("Invalid value on stack"),
                }
            },
            OpCode::SetItems => {
                match self.marker {
                    None => panic!("Empty marker"),
                    Some(marker) => {
                        let mut values = self.split_off(marker);

                        match self.stack.last_mut() {
                            None => panic!("Empty stack"),
                            Some(&mut Value::Dict(ref mut dict)) => {
                                for i in 0 .. values.len() / 2 { // TODO: Check panic
                                    let key = values.remove(2 * i);
                                    let value = values.remove(2 * i + 1);
                                    dict.push((key, value));
                                }
                            },
                            _ => panic!("Invalid value on stack"),
                        }
                    }
                }
            },

            OpCode::Pop => {
                self.pop();
            },
            OpCode::Dup => {
                let value = match self.stack.last() {
                    None => panic!("Empty stack"),
                    Some(ref v) => (*v).clone(),
                };
                self.stack.push(value)
            },
            OpCode::Mark => {
                self.marker = Some(self.stack.len())
            },
            OpCode::PopMark => {
                match self.marker {
                    None => panic!("Empty marker"),
                    Some(marker) => {
                        self.split_off(marker);
                    }
                }
            },

            _ => panic!("Not implemented")
        }
    }
}<commit_msg>Simplify operations with the marker<commit_after>use std::collections::{HashMap};

use num::bigint::{BigInt};

use opcode::{OpCode, BooleanOrInt};
use value::{Value};

pub struct Machine {
    stack: Vec<Value>,
    memo: HashMap<usize, Value>,
    marker: Option<usize>,
}

impl Machine {
    fn new() -> Self {
        Machine {
            stack: Vec::new(),
            memo: HashMap::new(),
            marker: None,
        }
    }

    fn split_off(&mut self) -> Vec<Value> {
        let at = match self.marker {
            None => panic!("Empty marker"),
            Some(marker) => marker,
        };

        if at > self.stack.len() {
            panic!("Stack too small");
        }

        self.stack.split_off(at)
    }

    fn pop(&mut self) -> Value {
        match self.stack.pop() {
            None => panic!("Empty stack"),
            Some(value) => value,
        }
    }

    fn execute(&mut self, opcode: OpCode) {
        match opcode {
            OpCode::Proto(_) => (),
            OpCode::Stop => (),  // TODO: !!!

            OpCode::Int(value) => {
                self.stack.push(match value {
                    BooleanOrInt::Boolean(v) => Value::Bool(v),
                    BooleanOrInt::Int(v) => Value::Int(BigInt::from(v)),
                })
            },
            OpCode::BinInt(i) => self.stack.push(Value::Int(BigInt::from(i))),
            OpCode::BinInt1(i) => self.stack.push(Value::Int(BigInt::from(i))),
            OpCode::BinInt2(i) => self.stack.push(Value::Int(BigInt::from(i))),
            OpCode::Long(i) => self.stack.push(Value::Int(BigInt::from(i))),
            OpCode::Long1(i) => self.stack.push(Value::Int(BigInt::from(i))),
            OpCode::Long4(i) => self.stack.push(Value::Int(BigInt::from(i))),

            OpCode::String(s) => self.stack.push(Value::String(s)),
            OpCode::BinString(s) => self.stack.push(Value::String(s)),
            OpCode::ShortBinString(s) => self.stack.push(Value::String(s)),

            OpCode::None => self.stack.push(Value::None),

            OpCode::NewTrue => self.stack.push(Value::Bool(true)),
            OpCode::NewFalse => self.stack.push(Value::Bool(false)),

            OpCode::Unicode(s) => self.stack.push(Value::Unicode(s)),
            OpCode::BinUnicode(s) => self.stack.push(Value::Unicode(s)),

            OpCode::Float(i) => self.stack.push(Value::Float(i)),
            OpCode::BinFloat(i) => self.stack.push(Value::Float(i)),

            OpCode::EmptyList => self.stack.push(Value::List(Vec::new())),
            OpCode::Append => {
                let v = self.pop();
                match self.stack.last_mut() {
                    None => panic!("Empty stack"),
                    Some(&mut Value::List(ref mut list)) => list.push(v),
                    _ => panic!("Invalid value on stack"),
                }
            },
            OpCode::Appends => {
                let values = self.split_off();
                match self.stack.last_mut() {
                    None => panic!("Empty stack"),
                    Some(&mut Value::List(ref mut list)) => {
                        list.extend(values);
                    },
                    _ => panic!("Invalid value on stack"),
                }
            },
            OpCode::List => {
                let values = self.split_off();
                self.stack.push(Value::List(values));
            },

            OpCode::EmptyTuple => self.stack.push(Value::Tuple(Vec::new())),
            OpCode::Tuple => {
                let values = self.split_off();
                self.stack.push(Value::Tuple(values));
            },
            OpCode::Tuple1 => {
                let v1 = self.pop();
                self.stack.push(Value::Tuple(vec![v1]))
            },
            OpCode::Tuple2 => {
                let v1 = self.pop();
                let v2 = self.pop();
                self.stack.push(Value::Tuple(vec![v1, v2]))
            },
            OpCode::Tuple3 => {
                let v1 = self.pop();
                let v2 = self.pop();
                let v3 = self.pop();
                self.stack.push(Value::Tuple(vec![v1, v2, v3]))
            }

            OpCode::EmptyDict => self.stack.push(Value::Dict(Vec::new())),
            OpCode::Dict => {
                let mut values = self.split_off();
                let mut dict = Vec::new();

                for i in 0 .. values.len() / 2 { // TODO: Check panic
                    let key = values.remove(2 * i);
                    let value = values.remove(2 * i + 1);
                    dict.push((key, value));
                }
                self.stack.push(Value::Dict(dict));
            },
            OpCode::SetItem => {
                let value = self.pop();
                let key = self.pop();
                match self.stack.last_mut() {
                    None => panic!("Empty stack"),
                    Some(&mut Value::Dict(ref mut dict)) => dict.push((key, value)),
                    _ => panic!("Invalid value on stack"),
                }
            },
            OpCode::SetItems => {
                let mut values = self.split_off();

                match self.stack.last_mut() {
                    None => panic!("Empty stack"),
                    Some(&mut Value::Dict(ref mut dict)) => {
                        for i in 0 .. values.len() / 2 { // TODO: Check panic
                            let key = values.remove(2 * i);
                            let value = values.remove(2 * i + 1);
                            dict.push((key, value));
                        }
                    },
                    _ => panic!("Invalid value on stack"),
                }
            },

            OpCode::Pop => {
                self.pop();
            },
            OpCode::Dup => {
                let value = match self.stack.last() {
                    None => panic!("Empty stack"),
                    Some(ref v) => (*v).clone(),
                };
                self.stack.push(value)
            },
            OpCode::Mark => {
                self.marker = Some(self.stack.len())
            },
            OpCode::PopMark => {
                self.split_off();
            },

            _ => panic!("Not implemented")
        }
    }
}<|endoftext|>