<commit_before>//! Atoms and atomic traits.

use std::{char, u8, u16, u32, u64, usize};
use std::{ascii, cmp};
use std::ops::Range;
use std::fmt::{self, Debug};

use super::{Class, Element, Sequence, Repetition, Union};

use util::set::{self, Contains, IsSubsetOf};

/// Trait-bounds requirements for atomic values in a pattern.
pub trait Atom: Debug + Copy + Clone + Eq + Ord + Distance + Step {}
impl<T> Atom for T where T: Debug + Copy + Clone + Eq + Ord + Distance + Step {}

// ----------------------------------------------------------------
// set::IsSubsetOf

impl<T: Atom> set::IsSubsetOf<T> for T {
    #[inline(always)]
    fn is_subset_of(&self, other: &T) -> bool {
        self == other
    }
}

impl<T: Atom> set::IsSubsetOf<Class<T>> for T {
    #[inline(always)]
    fn is_subset_of(&self, class: &Class<T>) -> bool {
        class.contains(*self)
    }
}

impl<T: Atom> set::IsSubsetOf<Union<T>> for T {
    #[inline]
    fn is_subset_of(&self, union: &Union<T>) -> bool {
        union.iter().any(|m| self.is_subset_of(m))
    }
}

impl<T: Atom> set::IsSubsetOf<Repetition<T>> for T {
    #[inline]
    fn is_subset_of(&self, rep: &Repetition<T>) -> bool {
        self.is_subset_of(rep.element()) && rep.count().contains(1)
    }
}

impl<T: Atom> set::IsSubsetOf<Element<T>> for T {
    fn is_subset_of(&self, elt: &Element<T>) -> bool {
        match elt {
            &Element::Wildcard => true,
            &Element::Atom(a) => *self == a,

            &Element::Class(ref class) => self.is_subset_of(class),
            &Element::Union(ref union) => self.is_subset_of(union),
            &Element::Repeat(ref rep) => self.is_subset_of(rep),
            &Element::Tagged{ref element, ..} => self.is_subset_of(&**element),

            &Element::Sequence(_) |
            &Element::Anchor(_)
                => false,
        }
    }
}

// ----------------------------------------------------------------
// set::Difference

impl<T: Atom, U> set::Difference<U> for T
    where T: set::IsSubsetOf<U> {
    type Output = Element<T>;
    fn difference(self, other: &U) -> Self::Output {
        if self.is_subset_of(other) {
            Element::empty()
        } else {
            Element::Atom(self)
        }
    }
}

// ----------------------------------------------------------------

/// Trait for types whose values can be stepped through by increment/decrement
/// operatons
pub trait Step: PartialEq<Self> {
    ///  Fetch the next value after the one provided in the positive direction.
    ///  If the supplied value is already at its maximum, return it.
    fn increment(&self) -> Self;

    ///  Fetch the next value after the one provided in the negative direction.
    ///  If the supplied value is already at its minimum, return it.
    fn decrement(&self) -> Self;
}

/// Trait used to determine the distance between two atoms.
pub trait Distance {
    /// Calculate the distance between `self` and the given value, returning
    /// the number of `Self`-sized steps between them.
    fn distance(&self, b: &Self) -> usize;
}

macro_rules! impl_step_distance_for_primitives {
    ($first: tt, $($rest:tt),+) => (
        impl_step_distance_for_primitives!($first);
        impl_step_distance_for_primitives!($($rest),+);
    );
    ($tp: tt) => (
        impl Step for $tp {
            fn increment(&self) -> Self {
                if *self >= $tp::MAX { *self }
                else { ((*self) + 1) as $tp }
            }
            fn decrement(&self) -> Self {
                if *self == 0 { *self }
                else { (*self - 1) as $tp }
            }
        }
        impl Distance for $tp {
            fn distance(&self, b: &Self) -> usize {
                if *self > *b { (*self - *b) as usize }
                else { (*b - *self) as usize }
            }
        }
    );
}

impl_step_distance_for_primitives!(u8, u16, u32, u64, usize);

const SURROGATE_RANGE: Range<u32> = 0xD800..0xE000;

impl Distance for char {
    fn distance(&self, b: &Self) -> usize {
        let (a, b) = (cmp::min(*self, *b) as u32, cmp::max(*self, *b) as u32);
        let a_surrogate = SURROGATE_RANGE.contains(a);
        let b_surrogate = SURROGATE_RANGE.contains(b);

        if a_surrogate && b_surrogate { 0 }
        else if a_surrogate { b as usize }
        else if b_surrogate { a as usize }
        else if (a < SURROGATE_RANGE.start && b < SURROGATE_RANGE.start) || (a >= SURROGATE_RANGE.end && b >= SURROGATE_RANGE.end) {
            (b - a) as usize
        } else {
            (b - SURROGATE_RANGE.end + SURROGATE_RANGE.start - a) as usize
        }
    }
}

impl Step for char {
    fn increment(&self) -> Self {
        if *self >= char::MAX {
            *self
        } else {
            let mut o = *self as u32 + 1;
            if SURROGATE_RANGE.contains(o) {
                o += SURROGATE_RANGE.len() as u32;
            }

            // We've manually skipped the surrogate range and done range
            // checking above, so this *should* actually be safe.
            unsafe { char::from_u32_unchecked(o) }
        }
    }

    fn decrement(&self) -> Self {
        if *self == '\0' {
            *self
        } else {
            let mut o = *self as u32 - 1;
            if SURROGATE_RANGE.contains(o) {
                o -= SURROGATE_RANGE.len() as u32;
            }

            // We've manually skipped the surrogate range and done range
            // checking above, so this *should* actually be safe.
            unsafe { char::from_u32_unchecked(o) }
        }
    }
}

/// Atom type for use with mixed binary/text data.
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)]
pub enum ByteOrChar {
    /// Single byte
    Byte(u8),
    /// Character
    Char(char)
}

impl From<u8> for ByteOrChar {
    fn from(byte: u8) -> Self {
        ByteOrChar::Byte(byte)
    }
}

impl From<char> for ByteOrChar {
    fn from(c: char) -> Self {
        ByteOrChar::Char(c)
    }
}

impl Distance for ByteOrChar {
    fn distance(&self, b: &Self) -> usize {
        Distance::distance(&Into::<char>::into(*self), &Into::<char>::into(*b))
    }
}

impl Step for ByteOrChar {
    fn increment(&self) -> Self {
        match self {
            &ByteOrChar::Byte(b) => ByteOrChar::Byte(b.increment()),
            &ByteOrChar::Char(c) => ByteOrChar::Char(c.increment()),
        }
    }
    fn decrement(&self) -> Self {
        match self {
            &ByteOrChar::Byte(b) => ByteOrChar::Byte(b.increment()),
            &ByteOrChar::Char(c) => ByteOrChar::Char(c.increment()),
        }
    }
}

impl Into<char> for ByteOrChar {
    fn into(self) -> char {
        match self {
            ByteOrChar::Byte(b) => b as char,
            ByteOrChar::Char(c) => c,
        }
    }
}

macro_rules! BoC_ascii_ext_forward {
    ($slf: ident, $name: ident) => (match $slf {
        &ByteOrChar::Byte(b) => b.$name(),
        &ByteOrChar::Char(c) => c.$name()
    });
    (mut $slf: ident, $name: ident) => (match *$slf {
        ByteOrChar::Byte(ref mut b) => b.$name(),
        ByteOrChar::Char(ref mut c) => c.$name()
    });
    ($slf: ident, $name: ident -> $conv: ident) => (match $slf {
        &ByteOrChar::Byte(b) => b.$name().$conv(),
        &ByteOrChar::Char(c) => c.$name().$conv()
    });
}

impl ascii::AsciiExt for ByteOrChar {
    type Owned = ByteOrChar;
    #[inline]
    fn is_ascii(&self) -> bool { BoC_ascii_ext_forward!(self, is_ascii) }
    #[inline]
    fn to_ascii_uppercase(&self) -> Self::Owned { BoC_ascii_ext_forward!(self, to_ascii_uppercase -> into) }
    #[inline]
    fn to_ascii_lowercase(&self) -> Self::Owned { BoC_ascii_ext_forward!(self, to_ascii_uppercase -> into) }
    #[inline]
    fn make_ascii_uppercase(&mut self) { BoC_ascii_ext_forward!(mut self, make_ascii_uppercase) }
    #[inline]
    fn make_ascii_lowercase(&mut self) { BoC_ascii_ext_forward!(mut self, make_ascii_lowercase) }

    #[inline]
    fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
        match self {
            &ByteOrChar::Byte(b1) => match other {
                &ByteOrChar::Byte(b2) => b1.eq_ignore_ascii_case(&b2),
                _ => false },
            &ByteOrChar::Char(c1) => match other {
                &ByteOrChar::Char(c2) => c1.eq_ignore_ascii_case(&c2),
                _ => false }
        }
    }
}
<commit_msg>pattern/atom: improvements/additions to IsSubsetOf impls<commit_after>//! Atoms and atomic traits.

use std::{char, u8, u16, u32, u64, usize};
use std::{ascii, cmp};
use std::ops::Range;
use std::fmt::{self, Debug};

use super::{Anchor, Class, Element, Sequence, Repetition, Union};

use util::set::{self, Contains, IsSubsetOf};

/// Trait-bounds requirements for atomic values in a pattern.
pub trait Atom: Debug + Copy + Clone + Eq + Ord + Distance + Step {}
impl<T> Atom for T where T: Debug + Copy + Clone + Eq + Ord + Distance + Step {}

// ----------------------------------------------------------------
// set::IsSubsetOf

impl<T: Atom> set::IsSubsetOf<T> for T {
    #[inline(always)]
    fn is_subset_of(&self, other: &T) -> bool {
        self == other
    }
}
impl<T: Atom> set::IsSubsetOf<Anchor<T>> for T {
    /// An atom is never a subset of an anchor.
    #[inline(always)]
    fn is_subset_of(&self, _: &Anchor<T>) -> bool {
        false
    }
}

impl<T: Atom> set::IsSubsetOf<Class<T>> for T {
    #[inline(always)]
    fn is_subset_of(&self, class: &Class<T>) -> bool {
        class.contains(*self)
    }
}

impl<T: Atom> set::IsSubsetOf<Union<T>> for T {
    #[inline]
    fn is_subset_of(&self, union: &Union<T>) -> bool {
        union.iter().any(|m| self.is_subset_of(m))
    }
}

impl<T: Atom> set::IsSubsetOf<Sequence<T>> for T {
    #[inline]
    fn is_subset_of(&self, seq: &Sequence<T>) -> bool {
        seq.len() == 1 && self.is_subset_of(&seq[0])
    }
}

impl<T: Atom> set::IsSubsetOf<Repetition<T>> for T {
    #[inline]
    fn is_subset_of(&self, rep: &Repetition<T>) -> bool {
        self.is_subset_of(rep.element()) && rep.count().contains(1)
    }
}

impl<T: Atom> set::IsSubsetOf<Element<T>> for T {
    fn is_subset_of(&self, elt: &Element<T>) -> bool {
        match elt {
            &Element::Wildcard => true,
            &Element::Atom(a) => self.is_subset_of(&a),

            &Element::Class(ref class) => self.is_subset_of(class),
            &Element::Union(ref union) => self.is_subset_of(union),
            &Element::Repeat(ref rep) => self.is_subset_of(rep),
            &Element::Tagged{ref element, ..} => self.is_subset_of(&**element),

            &Element::Sequence(ref seq) => self.is_subset_of(seq),
            &Element::Anchor(ref anch) => self.is_subset_of(anch)
        }
    }
}

// ----------------------------------------------------------------
// set::Difference

impl<T: Atom, U> set::Difference<U> for T
    where T: set::IsSubsetOf<U> {
    type Output = Element<T>;
    fn difference(self, other: &U) -> Self::Output {
        if self.is_subset_of(other) {
            Element::empty()
        } else {
            Element::Atom(self)
        }
    }
}

// ----------------------------------------------------------------

/// Trait for types whose values can be stepped through by increment/decrement
/// operatons
pub trait Step: PartialEq<Self> {
    ///  Fetch the next value after the one provided in the positive direction.
    ///  If the supplied value is already at its maximum, return it.
    fn increment(&self) -> Self;

    ///  Fetch the next value after the one provided in the negative direction.
    ///  If the supplied value is already at its minimum, return it.
    fn decrement(&self) -> Self;
}

/// Trait used to determine the distance between two atoms.
pub trait Distance {
    /// Calculate the distance between `self` and the given value, returning
    /// the number of `Self`-sized steps between them.
    fn distance(&self, b: &Self) -> usize;
}

macro_rules! impl_step_distance_for_primitives {
    ($first: tt, $($rest:tt),+) => (
        impl_step_distance_for_primitives!($first);
        impl_step_distance_for_primitives!($($rest),+);
    );
    ($tp: tt) => (
        impl Step for $tp {
            fn increment(&self) -> Self {
                if *self >= $tp::MAX { *self }
                else { ((*self) + 1) as $tp }
            }
            fn decrement(&self) -> Self {
                if *self == 0 { *self }
                else { (*self - 1) as $tp }
            }
        }
        impl Distance for $tp {
            fn distance(&self, b: &Self) -> usize {
                if *self > *b { (*self - *b) as usize }
                else { (*b - *self) as usize }
            }
        }
    );
}

impl_step_distance_for_primitives!(u8, u16, u32, u64, usize);

const SURROGATE_RANGE: Range<u32> = 0xD800..0xE000;

impl Distance for char {
    fn distance(&self, b: &Self) -> usize {
        let (a, b) = (cmp::min(*self, *b) as u32, cmp::max(*self, *b) as u32);
        let a_surrogate = SURROGATE_RANGE.contains(a);
        let b_surrogate = SURROGATE_RANGE.contains(b);

        if a_surrogate && b_surrogate { 0 }
        else if a_surrogate { b as usize }
        else if b_surrogate { a as usize }
        else if (a < SURROGATE_RANGE.start && b < SURROGATE_RANGE.start) || (a >= SURROGATE_RANGE.end && b >= SURROGATE_RANGE.end) {
            (b - a) as usize
        } else {
            (b - SURROGATE_RANGE.end + SURROGATE_RANGE.start - a) as usize
        }
    }
}

impl Step for char {
    fn increment(&self) -> Self {
        if *self >= char::MAX {
            *self
        } else {
            let mut o = *self as u32 + 1;
            if SURROGATE_RANGE.contains(o) {
                o += SURROGATE_RANGE.len() as u32;
            }

            // We've manually skipped the surrogate range and done range
            // checking above, so this *should* actually be safe.
            unsafe { char::from_u32_unchecked(o) }
        }
    }

    fn decrement(&self) -> Self {
        if *self == '\0' {
            *self
        } else {
            let mut o = *self as u32 - 1;
            if SURROGATE_RANGE.contains(o) {
                o -= SURROGATE_RANGE.len() as u32;
            }

            // We've manually skipped the surrogate range and done range
            // checking above, so this *should* actually be safe.
            unsafe { char::from_u32_unchecked(o) }
        }
    }
}

/// Atom type for use with mixed binary/text data.
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)]
pub enum ByteOrChar {
    /// Single byte
    Byte(u8),
    /// Character
    Char(char)
}

impl From<u8> for ByteOrChar {
    fn from(byte: u8) -> Self {
        ByteOrChar::Byte(byte)
    }
}

impl From<char> for ByteOrChar {
    fn from(c: char) -> Self {
        ByteOrChar::Char(c)
    }
}

impl Distance for ByteOrChar {
    fn distance(&self, b: &Self) -> usize {
        Distance::distance(&Into::<char>::into(*self), &Into::<char>::into(*b))
    }
}

impl Step for ByteOrChar {
    fn increment(&self) -> Self {
        match self {
            &ByteOrChar::Byte(b) => ByteOrChar::Byte(b.increment()),
            &ByteOrChar::Char(c) => ByteOrChar::Char(c.increment()),
        }
    }
    fn decrement(&self) -> Self {
        match self {
            &ByteOrChar::Byte(b) => ByteOrChar::Byte(b.increment()),
            &ByteOrChar::Char(c) => ByteOrChar::Char(c.increment()),
        }
    }
}

impl Into<char> for ByteOrChar {
    fn into(self) -> char {
        match self {
            ByteOrChar::Byte(b) => b as char,
            ByteOrChar::Char(c) => c,
        }
    }
}

macro_rules! BoC_ascii_ext_forward {
    ($slf: ident, $name: ident) => (match $slf {
        &ByteOrChar::Byte(b) => b.$name(),
        &ByteOrChar::Char(c) => c.$name()
    });
    (mut $slf: ident, $name: ident) => (match *$slf {
        ByteOrChar::Byte(ref mut b) => b.$name(),
        ByteOrChar::Char(ref mut c) => c.$name()
    });
    ($slf: ident, $name: ident -> $conv: ident) => (match $slf {
        &ByteOrChar::Byte(b) => b.$name().$conv(),
        &ByteOrChar::Char(c) => c.$name().$conv()
    });
}

impl ascii::AsciiExt for ByteOrChar {
    type Owned = ByteOrChar;
    #[inline]
    fn is_ascii(&self) -> bool { BoC_ascii_ext_forward!(self, is_ascii) }
    #[inline]
    fn to_ascii_uppercase(&self) -> Self::Owned { BoC_ascii_ext_forward!(self, to_ascii_uppercase -> into) }
    #[inline]
    fn to_ascii_lowercase(&self) -> Self::Owned { BoC_ascii_ext_forward!(self, to_ascii_uppercase -> into) }
    #[inline]
    fn make_ascii_uppercase(&mut self) { BoC_ascii_ext_forward!(mut self, make_ascii_uppercase) }
    #[inline]
    fn make_ascii_lowercase(&mut self) { BoC_ascii_ext_forward!(mut self, make_ascii_lowercase) }

    #[inline]
    fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
        match self {
            &ByteOrChar::Byte(b1) => match other {
                &ByteOrChar::Byte(b2) => b1.eq_ignore_ascii_case(&b2),
                _ => false },
            &ByteOrChar::Char(c1) => match other {
                &ByteOrChar::Char(c2) => c1.eq_ignore_ascii_case(&c2),
                _ => false }
        }
    }
}
<|endoftext|>


<commit_before>pub const RUNTIME: &'static str = r#"
#include "ruby.h"
#include <stdbool.h>
#include <string.h>

static const char *DOT = ".";

static VALUE escape_html(VALUE value) {
    VALUE cgi = rb_const_get(rb_cObject, rb_intern("CGI"));
    return rb_funcall(cgi, rb_intern("escapeHTML"), 1, value);
}

static VALUE fetch(VALUE context, VALUE key) {
    if (RSTRING_LEN(key) == 1 && strncmp(StringValuePtr(key), DOT, 1) == 0) {
        return context;
    }

    switch (rb_type(context)) {
        case T_HASH:
            return rb_hash_aref(context, key);
        case T_STRUCT:
            // TODO Check rb_struct_members to avoid name error.
            return rb_struct_aref(context, key);
        case T_OBJECT:
            // TODO Prevent undefined method error and check arity.
            return rb_funcall(context, rb_to_id(key), 0);
        default:
            return Qundef;
    }
}

static VALUE context_fetch(VALUE stack, VALUE key) {
    for (long i = RARRAY_LEN(stack) - 1; i >= 0; i--) {
        VALUE context = rb_ary_entry(stack, i);
        VALUE value = fetch(context, key);
        if (value != Qundef) {
            return value;
        }
    }
    return Qnil;
}

static VALUE fetch_path(VALUE stack, VALUE path) {
    VALUE value = context_fetch(stack, rb_ary_entry(path, 0));
    if (value == Qnil) {
        return Qnil;
    }
    for (long i = 1; i < RARRAY_LEN(path); i++) {
        value = fetch(value, rb_ary_entry(path, i));
        if (value == Qundef) {
            return Qnil;
        }
    }
    return value;
}

static void append_value(VALUE buf, VALUE stack, VALUE path, bool escape) {
    VALUE value = fetch_path(stack, path);
    switch (rb_type(value)) {
        case T_NIL:
        case T_UNDEF:
            return;
        case T_STRING:
            break;
        default:
            value = rb_funcall(value, rb_intern("to_s"), 0);
            break;
    }
    rb_str_buf_append(buf, escape ? escape_html(value) : value);
}

static void section(VALUE buf, VALUE stack, VALUE path, void (*block)(VALUE, VALUE)) {
    VALUE value = fetch_path(stack, path);
    switch (rb_type(value)) {
        case T_ARRAY:
            for (long i = 0; i < RARRAY_LEN(value); i++) {
                rb_ary_push(stack, rb_ary_entry(value, i));
                block(buf, stack);
                rb_ary_pop(stack);
            }
            break;
        case T_HASH:
        case T_OBJECT:
        case T_STRUCT:
            rb_ary_push(stack, value);
            block(buf, stack);
            rb_ary_pop(stack);
            break;
        case T_NIL:
        case T_UNDEF:
        case T_FALSE:
            break;
        default:
            block(buf, stack);
            break;
    }
}

static void inverted(VALUE buf, VALUE stack, VALUE path, void (*block)(VALUE, VALUE)) {
    VALUE value = fetch_path(stack, path);
    switch (rb_type(value)) {
        case T_ARRAY:
            if (RARRAY_LEN(value) == 0) {
                block(buf, stack);
            }
            break;
        case T_NIL:
        case T_UNDEF:
        case T_FALSE:
            block(buf, stack);
            break;
    }
}
"#;
<commit_msg>Resolve value from Hash only if key exists<commit_after>pub const RUNTIME: &'static str = r#"
#include "ruby.h"
#include <stdbool.h>
#include <string.h>

static const char *DOT = ".";

static VALUE escape_html(VALUE value) {
    VALUE cgi = rb_const_get(rb_cObject, rb_intern("CGI"));
    return rb_funcall(cgi, rb_intern("escapeHTML"), 1, value);
}

static VALUE fetch(VALUE context, VALUE key) {
    if (RSTRING_LEN(key) == 1 && strncmp(StringValuePtr(key), DOT, 1) == 0) {
        return context;
    }

    switch (rb_type(context)) {
        case T_HASH:
            if (rb_funcall(context, rb_intern("key?"), 1, key) == Qtrue) {
                return rb_hash_aref(context, key);
            } else {
                return Qundef;
            }
        case T_STRUCT:
            // TODO Check rb_struct_members to avoid name error.
            return rb_struct_aref(context, key);
        case T_OBJECT:
            // TODO Prevent undefined method error and check arity.
            return rb_funcall(context, rb_to_id(key), 0);
        default:
            return Qundef;
    }
}

static VALUE context_fetch(VALUE stack, VALUE key) {
    for (long i = RARRAY_LEN(stack) - 1; i >= 0; i--) {
        VALUE context = rb_ary_entry(stack, i);
        VALUE value = fetch(context, key);
        if (value != Qundef) {
            return value;
        }
    }
    return Qnil;
}

static VALUE fetch_path(VALUE stack, VALUE path) {
    VALUE value = context_fetch(stack, rb_ary_entry(path, 0));
    if (value == Qnil) {
        return Qnil;
    }
    for (long i = 1; i < RARRAY_LEN(path); i++) {
        value = fetch(value, rb_ary_entry(path, i));
        if (value == Qundef) {
            return Qnil;
        }
    }
    return value;
}

static void append_value(VALUE buf, VALUE stack, VALUE path, bool escape) {
    VALUE value = fetch_path(stack, path);
    switch (rb_type(value)) {
        case T_NIL:
        case T_UNDEF:
            return;
        case T_STRING:
            break;
        default:
            value = rb_funcall(value, rb_intern("to_s"), 0);
            break;
    }
    rb_str_buf_append(buf, escape ? escape_html(value) : value);
}

static void section(VALUE buf, VALUE stack, VALUE path, void (*block)(VALUE, VALUE)) {
    VALUE value = fetch_path(stack, path);
    switch (rb_type(value)) {
        case T_ARRAY:
            for (long i = 0; i < RARRAY_LEN(value); i++) {
                rb_ary_push(stack, rb_ary_entry(value, i));
                block(buf, stack);
                rb_ary_pop(stack);
            }
            break;
        case T_HASH:
        case T_OBJECT:
        case T_STRUCT:
            rb_ary_push(stack, value);
            block(buf, stack);
            rb_ary_pop(stack);
            break;
        case T_NIL:
        case T_UNDEF:
        case T_FALSE:
            break;
        default:
            block(buf, stack);
            break;
    }
}

static void inverted(VALUE buf, VALUE stack, VALUE path, void (*block)(VALUE, VALUE)) {
    VALUE value = fetch_path(stack, path);
    switch (rb_type(value)) {
        case T_ARRAY:
            if (RARRAY_LEN(value) == 0) {
                block(buf, stack);
            }
            break;
        case T_NIL:
        case T_UNDEF:
        case T_FALSE:
            block(buf, stack);
            break;
    }
}
"#;
<|endoftext|>


<commit_before>// Copyright (c) 2018-2021, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use std::cmp::Ordering;

use crate::context::*;
use crate::header::PRIMARY_REF_NONE;
use crate::partition::BlockSize;
use crate::rdo::spatiotemporal_scale;
use crate::rdo::DistortionScale;
use crate::tiling::TileStateMut;
use crate::util::Pixel;
use crate::FrameInvariants;
use crate::FrameState;

pub const MAX_SEGMENTS: usize = 8;

// This value was obtained through testing over multiple runs in AWCY.
const BASE_AQ_MULT: f64 = -9.0;

pub fn segmentation_optimize<T: Pixel>(
  fi: &FrameInvariants<T>, fs: &mut FrameState<T>,
) {
  assert!(fi.enable_segmentation);
  fs.segmentation.enabled = true;

  if fs.segmentation.enabled {
    fs.segmentation.update_map = true;

    // We don't change the values between frames.
    fs.segmentation.update_data = fi.primary_ref_frame == PRIMARY_REF_NONE;

    // Avoid going into lossless mode by never bringing qidx below 1.
    // Because base_q_idx changes more frequently than the segmentation
    // data, it is still possible for a segment to enter lossless, so
    // enforcement elsewhere is needed.
    let offset_lower_limit = 1 - fi.base_q_idx as i16;

    if !fs.segmentation.update_data {
      let mut min_segment = MAX_SEGMENTS;
      for i in 0..MAX_SEGMENTS {
        if fs.segmentation.features[i][SegLvl::SEG_LVL_ALT_Q as usize]
          && fs.segmentation.data[i][SegLvl::SEG_LVL_ALT_Q as usize]
            >= offset_lower_limit
        {
          min_segment = i;
          break;
        }
      }
      assert_ne!(min_segment, MAX_SEGMENTS);
      fs.segmentation.min_segment = min_segment as u8;
      fs.segmentation.update_threshold(fi.base_q_idx, fi.config.bit_depth);
      return;
    }

    segmentation_optimize_inner(fi, fs, offset_lower_limit);

    /* Figure out parameters */
    fs.segmentation.preskip = false;
    fs.segmentation.last_active_segid = 0;
    for i in 0..MAX_SEGMENTS {
      for j in 0..SegLvl::SEG_LVL_MAX as usize {
        if fs.segmentation.features[i][j] {
          fs.segmentation.last_active_segid = i as u8;
          if j >= SegLvl::SEG_LVL_REF_FRAME as usize {
            fs.segmentation.preskip = true;
          }
        }
      }
    }
  }
}

fn segmentation_optimize_inner<T: Pixel>(
  fi: &FrameInvariants<T>, fs: &mut FrameState<T>, offset_lower_limit: i16,
) {
  const AVG_SEG: f64 = 3.0;

  let coded_data = fi.coded_frame_data.as_ref().unwrap();
  let segments: Box<[_]> = coded_data
    .spatiotemporal_scores
    .iter()
    .map(|&s| segment_idx_from_distortion(&INIT_THRESHOLD, s))
    .collect();
  let mut seg_counts = [0usize; MAX_SEGMENTS];
  segments.iter().for_each(|&seg| {
    seg_counts[seg as usize % 8] += 1;
  });

  let mut num_neg = 0usize;
  let mut num_pos = 0usize;
  let mut tmp_delta = [0f64; MAX_SEGMENTS];
  for i in 0..MAX_SEGMENTS {
    tmp_delta[i] = (AVG_SEG - i as f64) * BASE_AQ_MULT * fi.config.aq_strength;
    if tmp_delta[i] > 0f64 {
      num_pos += 1;
    } else if tmp_delta[i] < 0f64 {
      num_neg += 1;
    }
  }

  // We want at least 1/12 of the blocks in a segment in order to code it.
  // In most cases this results in 3-4 segments being coded, which is optimal.
  let threshold = segments.len() / 12;

  let mut remap_segment_tab: [usize; MAX_SEGMENTS] = [0, 1, 2, 3, 4, 5, 6, 7];
  let mut num_segments = MAX_SEGMENTS;

  loop {
    let mut changed = false;

    if num_segments < 4 {
      break;
    }

    for i in (0..MAX_SEGMENTS).rev() {
      if seg_counts[remap_segment_tab[i]] >= threshold {
        continue;
      };
      if seg_counts[remap_segment_tab[i]] == 0 {
        continue;
      }; /* Already eliminated */

      let prev_id = remap_segment_tab[i];

      #[derive(Debug, Default, Clone, Copy)]
      struct ScoreTab {
        idx: usize,
        score: f64,
      }
      let mut s_array =
        [ScoreTab { idx: usize::max_value(), score: std::f64::MAX };
          MAX_SEGMENTS];

      for j in 0..MAX_SEGMENTS {
        s_array[j].idx = remap_segment_tab[j];
        if (remap_segment_tab[j] == prev_id)
          || (seg_counts[remap_segment_tab[j]] == 0)
          || (((num_neg < 2) || (num_pos < 2))
            && (tmp_delta[remap_segment_tab[j]].signum()
              != tmp_delta[prev_id].signum()))
        {
          s_array[j].score = std::f64::MAX;
        } else {
          s_array[j].score =
            (tmp_delta[remap_segment_tab[j]] - tmp_delta[prev_id]).abs();
        }
      }

      s_array.sort_by(|a, b| {
        (a.score).partial_cmp(&b.score).unwrap_or(Ordering::Less)
      });

      if s_array[0].score == std::f64::MAX {
        continue;
      }

      /* Remap any old mappings to the current segment as well */
      for j in 0..MAX_SEGMENTS {
        if remap_segment_tab[j] == prev_id {
          remap_segment_tab[j] = s_array[0].idx;
        }
      }

      let num_2bins = seg_counts[remap_segment_tab[i]] + seg_counts[prev_id];
      let mut ratio_new =
        (seg_counts[remap_segment_tab[i]] as f64) / (num_2bins as f64);
      let mut ratio_old = (seg_counts[prev_id] as f64) / (num_2bins as f64);

      ratio_new *= tmp_delta[remap_segment_tab[i]];
      ratio_old *= tmp_delta[prev_id];

      num_pos -= (tmp_delta[prev_id] > 0f64) as usize;
      num_neg -= (tmp_delta[prev_id] < 0f64) as usize;

      tmp_delta[remap_segment_tab[i]] = ratio_new + ratio_old;
      tmp_delta[prev_id] = std::f64::MAX;

      seg_counts[remap_segment_tab[i]] += seg_counts[prev_id];
      seg_counts[prev_id] = 0;

      num_segments -= 1;

      changed = true;
      break;
    }

    if !changed {
      break;
    }
  }

  tmp_delta.iter_mut().for_each(|delta| {
    if *delta > 0.0 {
      // We want the strength of the bitrate reduction to be
      // less than the strength of the bitrate increase.
      *delta *= 0.8;
    }
  });

  /* Get all unique values in the intentionally unsorted array (its a LUT) */
  let mut uniq_array = [0usize; MAX_SEGMENTS];
  let mut num_segments = 0;
  for i in 0..MAX_SEGMENTS {
    let mut seen_match = false;
    for j in 0..num_segments {
      if remap_segment_tab[i] == uniq_array[j] {
        seen_match = true;
      }
    }
    if !seen_match {
      uniq_array[num_segments] = remap_segment_tab[i];
      num_segments += 1;
    }
  }

  let mut seg_delta = [0f64; MAX_SEGMENTS];
  for i in 0..num_segments {
    /* Collect all used segment deltas into the actual segment map */
    seg_delta[i] = tmp_delta[uniq_array[i]];

    /* Remap the LUT to make it match the layout of the seg deltaq map */
    for j in 0..MAX_SEGMENTS {
      if remap_segment_tab[j] == uniq_array[i] {
        remap_segment_tab[j] = i;
      }
    }
  }

  fs.segmentation.max_segment = num_segments as u8 - 1;
  for i in 0..num_segments {
    fs.segmentation.features[i][SegLvl::SEG_LVL_ALT_Q as usize] = true;
    fs.segmentation.data[i][SegLvl::SEG_LVL_ALT_Q as usize] =
      (seg_delta[i].round() as i16).max(offset_lower_limit);
  }

  fs.segmentation.update_threshold(fi.base_q_idx, fi.config.bit_depth);
}

pub fn select_segment<T: Pixel>(
  fi: &FrameInvariants<T>, ts: &TileStateMut<'_, T>, tile_bo: TileBlockOffset,
  bsize: BlockSize, skip: bool,
) -> std::ops::RangeInclusive<u8> {
  // If skip is true or segmentation is turned off, sidx is not coded.
  if skip || !fi.enable_segmentation {
    return 0..=0;
  }

  use crate::api::SegmentationLevel;
  if fi.config.speed_settings.segmentation == SegmentationLevel::Full {
    return ts.segmentation.min_segment..=ts.segmentation.max_segment;
  }

  let frame_bo = ts.to_frame_block_offset(tile_bo);
  let scale = spatiotemporal_scale(fi, frame_bo, bsize);

  let sidx = segment_idx_from_distortion(&ts.segmentation.threshold, scale);

  // Avoid going into lossless mode by never bringing qidx below 1.
  let sidx = sidx.max(ts.segmentation.min_segment);

  sidx..=sidx
}

const fn d3(num: u64) -> DistortionScale {
  DistortionScale::new(num, 1000)
}

// These values were obtained based on thorough testing
// around the idea that the resulting encode filesize
// with dynamic segment maps should be, on average, the same as
// with the static segment maps.
// i.e. These values were found to improve perceptual quality
// without significantly impacting filesize.
static INIT_THRESHOLD: [DistortionScale; MAX_SEGMENTS - 1] =
  [d3(2_000), d3(1_500), d3(1_150), d3(900), d3(800), d3(700), d3(625)];

fn segment_idx_from_distortion(
  threshold: &[DistortionScale; MAX_SEGMENTS - 1], s: DistortionScale,
) -> u8 {
  threshold.partition_point(|&t| s.0 < t.0) as u8
}
<commit_msg>Derive segments by k-means of spatiotemporal scales<commit_after>// Copyright (c) 2018-2021, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use crate::context::*;
use crate::header::PRIMARY_REF_NONE;
use crate::partition::BlockSize;
use crate::rdo::spatiotemporal_scale;
use crate::rdo::DistortionScale;
use crate::tiling::TileStateMut;
use crate::util::Pixel;
use crate::FrameInvariants;
use crate::FrameState;

pub const MAX_SEGMENTS: usize = 8;

pub fn segmentation_optimize<T: Pixel>(
  fi: &FrameInvariants<T>, fs: &mut FrameState<T>,
) {
  assert!(fi.enable_segmentation);
  fs.segmentation.enabled = true;

  if fs.segmentation.enabled {
    fs.segmentation.update_map = true;

    // We don't change the values between frames.
    fs.segmentation.update_data = fi.primary_ref_frame == PRIMARY_REF_NONE;

    // Avoid going into lossless mode by never bringing qidx below 1.
    // Because base_q_idx changes more frequently than the segmentation
    // data, it is still possible for a segment to enter lossless, so
    // enforcement elsewhere is needed.
    let offset_lower_limit = 1 - fi.base_q_idx as i16;

    if !fs.segmentation.update_data {
      let mut min_segment = MAX_SEGMENTS;
      for i in 0..MAX_SEGMENTS {
        if fs.segmentation.features[i][SegLvl::SEG_LVL_ALT_Q as usize]
          && fs.segmentation.data[i][SegLvl::SEG_LVL_ALT_Q as usize]
            >= offset_lower_limit
        {
          min_segment = i;
          break;
        }
      }
      assert_ne!(min_segment, MAX_SEGMENTS);
      fs.segmentation.min_segment = min_segment as u8;
      fs.segmentation.update_threshold(fi.base_q_idx, fi.config.bit_depth);
      return;
    }

    segmentation_optimize_inner(fi, fs, offset_lower_limit);

    /* Figure out parameters */
    fs.segmentation.preskip = false;
    fs.segmentation.last_active_segid = 0;
    for i in 0..MAX_SEGMENTS {
      for j in 0..SegLvl::SEG_LVL_MAX as usize {
        if fs.segmentation.features[i][j] {
          fs.segmentation.last_active_segid = i as u8;
          if j >= SegLvl::SEG_LVL_REF_FRAME as usize {
            fs.segmentation.preskip = true;
          }
        }
      }
    }
  }
}

fn segmentation_optimize_inner<T: Pixel>(
  fi: &FrameInvariants<T>, fs: &mut FrameState<T>, offset_lower_limit: i16,
) {
  use crate::quantize::{ac_q, select_ac_qi};
  use crate::util::kmeans;
  use arrayvec::ArrayVec;
  use std::ops::Mul;

  let coded_data = fi.coded_frame_data.as_ref().unwrap();

  // Find k-means of log(spatiotemporal scale), k in 3..=8
  let c: ([_; 8], [_; 7], [_; 6], [_; 5], [_; 4], [_; 3]) = {
    let mut l: Box<[i32]> = coded_data
      .spatiotemporal_scores
      .iter()
      .map(|&s| ((f64::from(s)).log2() * (1 << 28) as f64) as i32)
      .collect();
    l.sort_unstable();
    (kmeans(&l), kmeans(&l), kmeans(&l), kmeans(&l), kmeans(&l), kmeans(&l))
  };

  // Find variance in spacing between successive log(quantizer)
  let var = |c: &[i32]| {
    let delta = ArrayVec::<_, MAX_SEGMENTS>::from_iter(
      c.iter().skip(1).zip(c).map(|(&a, &b)| b as i64 - a as i64),
    );
    let mean = delta.iter().sum::<i64>() / delta.len() as i64;
    delta.iter().map(|&d| (d - mean).pow(2)).sum::<i64>() as u64
  };
  let variance =
    [var(&c.0), var(&c.1), var(&c.2), var(&c.3), var(&c.4), var(&c.5)];

  // Choose the k value with minimal variance in spacing
  let min_variance = *variance.iter().min().unwrap();
  let position = variance.iter().rposition(|&v| v == min_variance).unwrap();

  // Fit to the nearest matching quantizer index deltas
  let base_ac_q = ac_q(fi.base_q_idx, 0, fi.config.bit_depth);
  let compute_delta = |centroids: &[i32]| {
    centroids
      .iter()
      .rev()
      .map(|&delta_log_q| {
        (-f64::from(delta_log_q) / f64::from(1 << 29))
          .exp2()
          .mul(f64::from(base_ac_q))
          .round() as i64
      })
      .map(|q| {
        // Avoid going into lossless mode by never bringing qidx below 1.
        select_ac_qi(q, fi.config.bit_depth).max(1) as i16
          - fi.base_q_idx as i16
      })
      .collect::<ArrayVec<_, MAX_SEGMENTS>>()
  };

  // Compute segment deltas for best value of k
  let seg_delta = match position {
    0 => compute_delta(&c.0),
    1 => compute_delta(&c.1),
    2 => compute_delta(&c.2),
    3 => compute_delta(&c.3),
    4 => compute_delta(&c.4),
    _ => compute_delta(&c.5),
  };

  // Update the segmentation data
  fs.segmentation.max_segment = seg_delta.len() as u8 - 1;
  for (&delta, (features, data)) in seg_delta
    .iter()
    .zip(fs.segmentation.features.iter_mut().zip(&mut fs.segmentation.data))
  {
    features[SegLvl::SEG_LVL_ALT_Q as usize] = true;
    data[SegLvl::SEG_LVL_ALT_Q as usize] = delta.max(offset_lower_limit);
  }

  fs.segmentation.update_threshold(fi.base_q_idx, fi.config.bit_depth);
}

pub fn select_segment<T: Pixel>(
  fi: &FrameInvariants<T>, ts: &TileStateMut<'_, T>, tile_bo: TileBlockOffset,
  bsize: BlockSize, skip: bool,
) -> std::ops::RangeInclusive<u8> {
  // If skip is true or segmentation is turned off, sidx is not coded.
  if skip || !fi.enable_segmentation {
    return 0..=0;
  }

  use crate::api::SegmentationLevel;
  if fi.config.speed_settings.segmentation == SegmentationLevel::Full {
    return ts.segmentation.min_segment..=ts.segmentation.max_segment;
  }

  let frame_bo = ts.to_frame_block_offset(tile_bo);
  let scale = spatiotemporal_scale(fi, frame_bo, bsize);

  let sidx = segment_idx_from_distortion(&ts.segmentation.threshold, scale);

  // Avoid going into lossless mode by never bringing qidx below 1.
  let sidx = sidx.max(ts.segmentation.min_segment);

  sidx..=sidx
}

fn segment_idx_from_distortion(
  threshold: &[DistortionScale; MAX_SEGMENTS - 1], s: DistortionScale,
) -> u8 {
  threshold.partition_point(|&t| s.0 < t.0) as u8
}
<|endoftext|>


<commit_before>//! Combinators applying parsers in sequence

#[cfg(test)]
mod tests;

use crate::error::ParseError;
use crate::internal::{IResult, Parser};

/// Gets an object from the first parser,
/// then gets another object from the second parser.
///
/// # Arguments
/// * `first` The first parser to apply.
/// * `second` The second parser to apply.
/// ```rust
/// # use nom::{Err, error::ErrorKind, Needed};
/// # use nom::Needed::Size;
/// use nom::sequence::pair;
/// use nom::bytes::complete::tag;
///
/// let mut parser = pair(tag("abc"), tag("efg"));
///
/// assert_eq!(parser("abcefg"), Ok(("", ("abc", "efg"))));
/// assert_eq!(parser("abcefghij"), Ok(("hij", ("abc", "efg"))));
/// assert_eq!(parser(""), Err(Err::Error(("", ErrorKind::Tag))));
/// assert_eq!(parser("123"), Err(Err::Error(("123", ErrorKind::Tag))));
/// ```
pub fn pair<I, O1, O2, E: ParseError<I>, F, G>(
  mut first: F,
  mut second: G,
) -> impl FnMut(I) -> IResult<I, (O1, O2), E>
where
  F: Parser<I, O1, E>,
  G: Parser<I, O2, E>,
{
  move |input: I| {
    let (input, o1) = first.parse(input)?;
    second.parse(input).map(|(i, o2)| (i, (o1, o2)))
  }
}

/// Matches an object from the first parser and discards it,
/// then gets an object from the second parser.
///
/// # Arguments
/// * `first` The opening parser.
/// * `second` The second parser to get object.
/// ```rust
/// # use nom::{Err, error::ErrorKind, Needed};
/// # use nom::Needed::Size;
/// use nom::sequence::preceded;
/// use nom::bytes::complete::tag;
///
/// let mut parser = preceded(tag("abc"), tag("efg"));
///
/// assert_eq!(parser("abcefg"), Ok(("", "efg")));
/// assert_eq!(parser("abcefghij"), Ok(("hij", "efg")));
/// assert_eq!(parser(""), Err(Err::Error(("", ErrorKind::Tag))));
/// assert_eq!(parser("123"), Err(Err::Error(("123", ErrorKind::Tag))));
/// ```
pub fn preceded<I, O1, O2, E: ParseError<I>, F, G>(
  mut first: F,
  mut second: G,
) -> impl FnMut(I) -> IResult<I, O2, E>
where
  F: Parser<I, O1, E>,
  G: Parser<I, O2, E>,
{
  move |input: I| {
    let (input, _) = first.parse(input)?;
    second.parse(input)
  }
}

/// Gets an object from the first parser,
/// then matches an object from the second parser and discards it.
///
/// # Arguments
/// * `first` The first parser to apply.
/// * `second` The second parser to match an object.
/// ```rust
/// # use nom::{Err, error::ErrorKind, Needed};
/// # use nom::Needed::Size;
/// use nom::sequence::terminated;
/// use nom::bytes::complete::tag;
///
/// let mut parser = terminated(tag("abc"), tag("efg"));
///
/// assert_eq!(parser("abcefg"), Ok(("", "abc")));
/// assert_eq!(parser("abcefghij"), Ok(("hij", "abc")));
/// assert_eq!(parser(""), Err(Err::Error(("", ErrorKind::Tag))));
/// assert_eq!(parser("123"), Err(Err::Error(("123", ErrorKind::Tag))));
/// ```
pub fn terminated<I, O1, O2, E: ParseError<I>, F, G>(
  mut first: F,
  mut second: G,
) -> impl FnMut(I) -> IResult<I, O1, E>
where
  F: Parser<I, O1, E>,
  G: Parser<I, O2, E>,
{
  move |input: I| {
    let (input, o1) = first.parse(input)?;
    second.parse(input).map(|(i, _)| (i, o1))
  }
}

/// Gets an object from the first parser,
/// then matches an object from the sep_parser and discards it,
/// then gets another object from the second parser.
///
/// # Arguments
/// * `first` The first parser to apply.
/// * `sep` The separator parser to apply.
/// * `second` The second parser to apply.
/// ```rust
/// # use nom::{Err, error::ErrorKind, Needed};
/// # use nom::Needed::Size;
/// use nom::sequence::separated_pair;
/// use nom::bytes::complete::tag;
///
/// let mut parser = separated_pair(tag("abc"), tag("|"), tag("efg"));
///
/// assert_eq!(parser("abc|efg"), Ok(("", ("abc", "efg"))));
/// assert_eq!(parser("abc|efghij"), Ok(("hij", ("abc", "efg"))));
/// assert_eq!(parser(""), Err(Err::Error(("", ErrorKind::Tag))));
/// assert_eq!(parser("123"), Err(Err::Error(("123", ErrorKind::Tag))));
/// ```
pub fn separated_pair<I, O1, O2, O3, E: ParseError<I>, F, G, H>(
  mut first: F,
  mut sep: G,
  mut second: H,
) -> impl FnMut(I) -> IResult<I, (O1, O3), E>
where
  F: Parser<I, O1, E>,
  G: Parser<I, O2, E>,
  H: Parser<I, O3, E>,
{
  move |input: I| {
    let (input, o1) = first.parse(input)?;
    let (input, _) = sep.parse(input)?;
    second.parse(input).map(|(i, o2)| (i, (o1, o2)))
  }
}

/// Matches an object from the first parser and discards it,
/// then gets an object from the second parser,
/// and finally matches an object from the third parser and discards it.
///
/// # Arguments
/// * `first` The first parser to apply and discard.
/// * `second` The second parser to apply.
/// * `third` The third parser to apply and discard.
/// ```rust
/// # use nom::{Err, error::ErrorKind, Needed};
/// # use nom::Needed::Size;
/// use nom::sequence::delimited;
/// use nom::bytes::complete::tag;
///
/// let mut parser = delimited(tag("("), tag("abc"), tag(")"));
///
/// assert_eq!(parser("(abc)"), Ok(("", "abc")));
/// assert_eq!(parser("(abc)def"), Ok(("def", "abc")));
/// assert_eq!(parser(""), Err(Err::Error(("", ErrorKind::Tag))));
/// assert_eq!(parser("123"), Err(Err::Error(("123", ErrorKind::Tag))));
/// ```
pub fn delimited<I, O1, O2, O3, E: ParseError<I>, F, G, H>(
  mut first: F,
  mut second: G,
  mut third: H,
) -> impl FnMut(I) -> IResult<I, O2, E>
where
  F: Parser<I, O1, E>,
  G: Parser<I, O2, E>,
  H: Parser<I, O3, E>,
{
  move |input: I| {
    let (input, _) = first.parse(input)?;
    let (input, o2) = second.parse(input)?;
    third.parse(input).map(|(i, _)| (i, o2))
  }
}

/// Helper trait for the tuple combinator.
///
/// This trait is implemented for tuples of parsers of up to 21 elements.
pub trait Tuple<I, O, E> {
  /// Parses the input and returns a tuple of results of each parser.
  fn parse(&mut self, input: I) -> IResult<I, O, E>;
}

impl<Input, Output, Error: ParseError<Input>, F: Parser<Input, Output, Error>>
  Tuple<Input, (Output,), Error> for (F,)
{
  fn parse(&mut self, input: Input) -> IResult<Input, (Output,), Error> {
    self.0.parse(input).map(|(i, o)| (i, (o,)))
  }
}

macro_rules! tuple_trait(
  ($name1:ident $ty1:ident, $name2: ident $ty2:ident, $($name:ident $ty:ident),*) => (
    tuple_trait!(__impl $name1 $ty1, $name2 $ty2; $($name $ty),*);
  );
  (__impl $($name:ident $ty: ident),+; $name1:ident $ty1:ident, $($name2:ident $ty2:ident),*) => (
    tuple_trait_impl!($($name $ty),+);
    tuple_trait!(__impl $($name $ty),+ , $name1 $ty1; $($name2 $ty2),*);
  );
  (__impl $($name:ident $ty: ident),+; $name1:ident $ty1:ident) => (
    tuple_trait_impl!($($name $ty),+);
    tuple_trait_impl!($($name $ty),+, $name1 $ty1);
  );
);

macro_rules! tuple_trait_impl(
  ($($name:ident $ty: ident),+) => (
    impl<
      Input: Clone, $($ty),+ , Error: ParseError<Input>,
      $($name: Parser<Input, $ty, Error>),+
    > Tuple<Input, ( $($ty),+ ), Error> for ( $($name),+ ) {

      fn parse(&mut self, input: Input) -> IResult<Input, ( $($ty),+ ), Error> {
        tuple_trait_inner!(0, self, input, (), $($name)+)

      }
    }
  );
);

macro_rules! tuple_trait_inner(
  ($it:tt, $self:expr, $input:expr, (), $head:ident $($id:ident)+) => ({
    let (i, o) = $self.$it.parse($input.clone())?;

    succ!($it, tuple_trait_inner!($self, i, ( o ), $($id)+))
  });
  ($it:tt, $self:expr, $input:expr, ($($parsed:tt)*), $head:ident $($id:ident)+) => ({
    let (i, o) = $self.$it.parse($input.clone())?;

    succ!($it, tuple_trait_inner!($self, i, ($($parsed)* , o), $($id)+))
  });
  ($it:tt, $self:expr, $input:expr, ($($parsed:tt)*), $head:ident) => ({
    let (i, o) = $self.$it.parse($input.clone())?;

    Ok((i, ($($parsed)* , o)))
  });
);

tuple_trait!(FnA A, FnB B, FnC C, FnD D, FnE E, FnF F, FnG G, FnH H, FnI I, FnJ J, FnK K, FnL L,
  FnM M, FnN N, FnO O, FnP P, FnQ Q, FnR R, FnS S, FnT T, FnU U);

///Applies a tuple of parsers one by one and returns their results as a tuple.
///
/// ```rust
/// # use nom::{Err, error::ErrorKind};
/// use nom::sequence::tuple;
/// use nom::character::complete::{alpha1, digit1};
/// let mut parser = tuple((alpha1, digit1, alpha1));
///
/// assert_eq!(parser("abc123def"), Ok(("", ("abc", "123", "def"))));
/// assert_eq!(parser("123def"), Err(Err::Error(("123def", ErrorKind::Alpha))));
/// ```
pub fn tuple<I, O, E: ParseError<I>, List: Tuple<I, O, E>>(
  mut l: List,
) -> impl FnMut(I) -> IResult<I, O, E> {
  move |i: I| l.parse(i)
}
<commit_msg>fix: fixed doc code blocks<commit_after>//! Combinators applying parsers in sequence

#[cfg(test)]
mod tests;

use crate::error::ParseError;
use crate::internal::{IResult, Parser};

/// Gets an object from the first parser,
/// then gets another object from the second parser.
///
/// # Arguments
/// * `first` The first parser to apply.
/// * `second` The second parser to apply.
///
/// ```rust
/// # use nom::{Err, error::ErrorKind, Needed};
/// # use nom::Needed::Size;
/// use nom::sequence::pair;
/// use nom::bytes::complete::tag;
///
/// let mut parser = pair(tag("abc"), tag("efg"));
///
/// assert_eq!(parser("abcefg"), Ok(("", ("abc", "efg"))));
/// assert_eq!(parser("abcefghij"), Ok(("hij", ("abc", "efg"))));
/// assert_eq!(parser(""), Err(Err::Error(("", ErrorKind::Tag))));
/// assert_eq!(parser("123"), Err(Err::Error(("123", ErrorKind::Tag))));
/// ```
pub fn pair<I, O1, O2, E: ParseError<I>, F, G>(
  mut first: F,
  mut second: G,
) -> impl FnMut(I) -> IResult<I, (O1, O2), E>
where
  F: Parser<I, O1, E>,
  G: Parser<I, O2, E>,
{
  move |input: I| {
    let (input, o1) = first.parse(input)?;
    second.parse(input).map(|(i, o2)| (i, (o1, o2)))
  }
}

/// Matches an object from the first parser and discards it,
/// then gets an object from the second parser.
///
/// # Arguments
/// * `first` The opening parser.
/// * `second` The second parser to get object.
///
/// ```rust
/// # use nom::{Err, error::ErrorKind, Needed};
/// # use nom::Needed::Size;
/// use nom::sequence::preceded;
/// use nom::bytes::complete::tag;
///
/// let mut parser = preceded(tag("abc"), tag("efg"));
///
/// assert_eq!(parser("abcefg"), Ok(("", "efg")));
/// assert_eq!(parser("abcefghij"), Ok(("hij", "efg")));
/// assert_eq!(parser(""), Err(Err::Error(("", ErrorKind::Tag))));
/// assert_eq!(parser("123"), Err(Err::Error(("123", ErrorKind::Tag))));
/// ```
pub fn preceded<I, O1, O2, E: ParseError<I>, F, G>(
  mut first: F,
  mut second: G,
) -> impl FnMut(I) -> IResult<I, O2, E>
where
  F: Parser<I, O1, E>,
  G: Parser<I, O2, E>,
{
  move |input: I| {
    let (input, _) = first.parse(input)?;
    second.parse(input)
  }
}

/// Gets an object from the first parser,
/// then matches an object from the second parser and discards it.
///
/// # Arguments
/// * `first` The first parser to apply.
/// * `second` The second parser to match an object.
///
/// ```rust
/// # use nom::{Err, error::ErrorKind, Needed};
/// # use nom::Needed::Size;
/// use nom::sequence::terminated;
/// use nom::bytes::complete::tag;
///
/// let mut parser = terminated(tag("abc"), tag("efg"));
///
/// assert_eq!(parser("abcefg"), Ok(("", "abc")));
/// assert_eq!(parser("abcefghij"), Ok(("hij", "abc")));
/// assert_eq!(parser(""), Err(Err::Error(("", ErrorKind::Tag))));
/// assert_eq!(parser("123"), Err(Err::Error(("123", ErrorKind::Tag))));
/// ```
pub fn terminated<I, O1, O2, E: ParseError<I>, F, G>(
  mut first: F,
  mut second: G,
) -> impl FnMut(I) -> IResult<I, O1, E>
where
  F: Parser<I, O1, E>,
  G: Parser<I, O2, E>,
{
  move |input: I| {
    let (input, o1) = first.parse(input)?;
    second.parse(input).map(|(i, _)| (i, o1))
  }
}

/// Gets an object from the first parser,
/// then matches an object from the sep_parser and discards it,
/// then gets another object from the second parser.
///
/// # Arguments
/// * `first` The first parser to apply.
/// * `sep` The separator parser to apply.
/// * `second` The second parser to apply.
///
/// ```rust
/// # use nom::{Err, error::ErrorKind, Needed};
/// # use nom::Needed::Size;
/// use nom::sequence::separated_pair;
/// use nom::bytes::complete::tag;
///
/// let mut parser = separated_pair(tag("abc"), tag("|"), tag("efg"));
///
/// assert_eq!(parser("abc|efg"), Ok(("", ("abc", "efg"))));
/// assert_eq!(parser("abc|efghij"), Ok(("hij", ("abc", "efg"))));
/// assert_eq!(parser(""), Err(Err::Error(("", ErrorKind::Tag))));
/// assert_eq!(parser("123"), Err(Err::Error(("123", ErrorKind::Tag))));
/// ```
pub fn separated_pair<I, O1, O2, O3, E: ParseError<I>, F, G, H>(
  mut first: F,
  mut sep: G,
  mut second: H,
) -> impl FnMut(I) -> IResult<I, (O1, O3), E>
where
  F: Parser<I, O1, E>,
  G: Parser<I, O2, E>,
  H: Parser<I, O3, E>,
{
  move |input: I| {
    let (input, o1) = first.parse(input)?;
    let (input, _) = sep.parse(input)?;
    second.parse(input).map(|(i, o2)| (i, (o1, o2)))
  }
}

/// Matches an object from the first parser and discards it,
/// then gets an object from the second parser,
/// and finally matches an object from the third parser and discards it.
///
/// # Arguments
/// * `first` The first parser to apply and discard.
/// * `second` The second parser to apply.
/// * `third` The third parser to apply and discard.
///
/// ```rust
/// # use nom::{Err, error::ErrorKind, Needed};
/// # use nom::Needed::Size;
/// use nom::sequence::delimited;
/// use nom::bytes::complete::tag;
///
/// let mut parser = delimited(tag("("), tag("abc"), tag(")"));
///
/// assert_eq!(parser("(abc)"), Ok(("", "abc")));
/// assert_eq!(parser("(abc)def"), Ok(("def", "abc")));
/// assert_eq!(parser(""), Err(Err::Error(("", ErrorKind::Tag))));
/// assert_eq!(parser("123"), Err(Err::Error(("123", ErrorKind::Tag))));
/// ```
pub fn delimited<I, O1, O2, O3, E: ParseError<I>, F, G, H>(
  mut first: F,
  mut second: G,
  mut third: H,
) -> impl FnMut(I) -> IResult<I, O2, E>
where
  F: Parser<I, O1, E>,
  G: Parser<I, O2, E>,
  H: Parser<I, O3, E>,
{
  move |input: I| {
    let (input, _) = first.parse(input)?;
    let (input, o2) = second.parse(input)?;
    third.parse(input).map(|(i, _)| (i, o2))
  }
}

/// Helper trait for the tuple combinator.
///
/// This trait is implemented for tuples of parsers of up to 21 elements.
pub trait Tuple<I, O, E> {
  /// Parses the input and returns a tuple of results of each parser.
  fn parse(&mut self, input: I) -> IResult<I, O, E>;
}

impl<Input, Output, Error: ParseError<Input>, F: Parser<Input, Output, Error>>
  Tuple<Input, (Output,), Error> for (F,)
{
  fn parse(&mut self, input: Input) -> IResult<Input, (Output,), Error> {
    self.0.parse(input).map(|(i, o)| (i, (o,)))
  }
}

macro_rules! tuple_trait(
  ($name1:ident $ty1:ident, $name2: ident $ty2:ident, $($name:ident $ty:ident),*) => (
    tuple_trait!(__impl $name1 $ty1, $name2 $ty2; $($name $ty),*);
  );
  (__impl $($name:ident $ty: ident),+; $name1:ident $ty1:ident, $($name2:ident $ty2:ident),*) => (
    tuple_trait_impl!($($name $ty),+);
    tuple_trait!(__impl $($name $ty),+ , $name1 $ty1; $($name2 $ty2),*);
  );
  (__impl $($name:ident $ty: ident),+; $name1:ident $ty1:ident) => (
    tuple_trait_impl!($($name $ty),+);
    tuple_trait_impl!($($name $ty),+, $name1 $ty1);
  );
);

macro_rules! tuple_trait_impl(
  ($($name:ident $ty: ident),+) => (
    impl<
      Input: Clone, $($ty),+ , Error: ParseError<Input>,
      $($name: Parser<Input, $ty, Error>),+
    > Tuple<Input, ( $($ty),+ ), Error> for ( $($name),+ ) {

      fn parse(&mut self, input: Input) -> IResult<Input, ( $($ty),+ ), Error> {
        tuple_trait_inner!(0, self, input, (), $($name)+)

      }
    }
  );
);

macro_rules! tuple_trait_inner(
  ($it:tt, $self:expr, $input:expr, (), $head:ident $($id:ident)+) => ({
    let (i, o) = $self.$it.parse($input.clone())?;

    succ!($it, tuple_trait_inner!($self, i, ( o ), $($id)+))
  });
  ($it:tt, $self:expr, $input:expr, ($($parsed:tt)*), $head:ident $($id:ident)+) => ({
    let (i, o) = $self.$it.parse($input.clone())?;

    succ!($it, tuple_trait_inner!($self, i, ($($parsed)* , o), $($id)+))
  });
  ($it:tt, $self:expr, $input:expr, ($($parsed:tt)*), $head:ident) => ({
    let (i, o) = $self.$it.parse($input.clone())?;

    Ok((i, ($($parsed)* , o)))
  });
);

tuple_trait!(FnA A, FnB B, FnC C, FnD D, FnE E, FnF F, FnG G, FnH H, FnI I, FnJ J, FnK K, FnL L,
  FnM M, FnN N, FnO O, FnP P, FnQ Q, FnR R, FnS S, FnT T, FnU U);

///Applies a tuple of parsers one by one and returns their results as a tuple.
///
/// ```rust
/// # use nom::{Err, error::ErrorKind};
/// use nom::sequence::tuple;
/// use nom::character::complete::{alpha1, digit1};
/// let mut parser = tuple((alpha1, digit1, alpha1));
///
/// assert_eq!(parser("abc123def"), Ok(("", ("abc", "123", "def"))));
/// assert_eq!(parser("123def"), Err(Err::Error(("123def", ErrorKind::Alpha))));
/// ```
pub fn tuple<I, O, E: ParseError<I>, List: Tuple<I, O, E>>(
  mut l: List,
) -> impl FnMut(I) -> IResult<I, O, E> {
  move |i: I| l.parse(i)
}
<|endoftext|>


<commit_before>//! Simplifying Candidates
//!
//! *Simplifying* a match pair `place @ pattern` means breaking it down
//! into bindings or other, simpler match pairs. For example:
//!
//! - `place @ (P1, P2)` can be simplified to `[place.0 @ P1, place.1 @ P2]`
//! - `place @ x` can be simplified to `[]` by binding `x` to `place`
//!
//! The `simplify_candidate` routine just repeatedly applies these
//! sort of simplifications until there is nothing left to
//! simplify. Match pairs cannot be simplified if they require some
//! sort of test: for example, testing which variant an enum is, or
//! testing a value against a constant.

use crate::build::Builder;
use crate::build::matches::{Ascription, Binding, MatchPair, Candidate};
use crate::hair::{self, *};
use rustc::ty;
use rustc::ty::layout::{Integer, IntegerExt, Size};
use syntax::attr::{SignedInt, UnsignedInt};
use rustc::hir::RangeEnd;
use rustc::mir::interpret::truncate;

use std::mem;

impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
    pub fn simplify_candidate<'pat>(&mut self,
                                    candidate: &mut Candidate<'pat, 'tcx>) {
        // repeatedly simplify match pairs until fixed point is reached
        loop {
            let match_pairs = mem::replace(&mut candidate.match_pairs, vec![]);
            let mut changed = false;
            for match_pair in match_pairs {
                match self.simplify_match_pair(match_pair, candidate) {
                    Ok(()) => {
                        changed = true;
                    }
                    Err(match_pair) => {
                        candidate.match_pairs.push(match_pair);
                    }
                }
            }
            if !changed {
                return; // if we were not able to simplify any, done.
            }
        }
    }

    /// Tries to simplify `match_pair`, returning `Ok(())` if
    /// successful. If successful, new match pairs and bindings will
    /// have been pushed into the candidate. If no simplification is
    /// possible, `Err` is returned and no changes are made to
    /// candidate.
    fn simplify_match_pair<'pat>(&mut self,
                                 match_pair: MatchPair<'pat, 'tcx>,
                                 candidate: &mut Candidate<'pat, 'tcx>)
                                 -> Result<(), MatchPair<'pat, 'tcx>> {
        let tcx = self.hir.tcx();
        match *match_pair.pattern.kind {
            PatternKind::AscribeUserType {
                ref subpattern,
                ascription: hair::pattern::Ascription {
                    variance,
                    ref user_ty,
                    user_ty_span,
                },
            } => {
                // Apply the type ascription to the value at `match_pair.place`, which is the
                // value being matched, taking the variance field into account.
                candidate.ascriptions.push(Ascription {
                    span: user_ty_span,
                    user_ty: user_ty.clone(),
                    source: match_pair.place.clone(),
                    variance,
                });

                candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));

                Ok(())
            }

            PatternKind::Wild => {
                // nothing left to do
                Ok(())
            }

            PatternKind::Binding { name, mutability, mode, var, ty, ref subpattern } => {
                candidate.bindings.push(Binding {
                    name,
                    mutability,
                    span: match_pair.pattern.span,
                    source: match_pair.place.clone(),
                    var_id: var,
                    var_ty: ty,
                    binding_mode: mode,
                });

                if let Some(subpattern) = subpattern.as_ref() {
                    // this is the `x @ P` case; have to keep matching against `P` now
                    candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));
                }

                Ok(())
            }

            PatternKind::Constant { .. } => {
                // FIXME normalize patterns when possible
                Err(match_pair)
            }

            PatternKind::Range(PatternRange { lo, hi, ty, end }) => {
                let (range, bias) = match ty.sty {
                    ty::Char => {
                        (Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))), 0)
                    }
                    ty::Int(ity) => {
                        // FIXME(49937): refactor these bit manipulations into interpret.
                        let size = Integer::from_attr(&tcx, SignedInt(ity)).size();
                        let max = truncate(u128::max_value(), size);
                        let bias = 1u128 << (size.bits() - 1);
                        (Some((0, max, size)), bias)
                    }
                    ty::Uint(uty) => {
                        // FIXME(49937): refactor these bit manipulations into interpret.
                        let size = Integer::from_attr(&tcx, UnsignedInt(uty)).size();
                        let max = truncate(u128::max_value(), size);
                        (Some((0, max, size)), 0)
                    }
                    _ => (None, 0),
                };
                if let Some((min, max, sz)) = range {
                    if let (Some(lo), Some(hi)) = (lo.val.try_to_bits(sz), hi.val.try_to_bits(sz)) {
                        // We want to compare ranges numerically, but the order of the bitwise
                        // representation of signed integers does not match their numeric order.
                        // Thus, to correct the ordering, we need to shift the range of signed
                        // integers to correct the comparison. This is achieved by XORing with a
                        // bias (see pattern/_match.rs for another pertinent example of this
                        // pattern).
                        let (lo, hi) = (lo ^ bias, hi ^ bias);
                        if lo <= min && (hi > max || hi == max && end == RangeEnd::Included) {
                            // Irrefutable pattern match.
                            return Ok(());
                        }
                    }
                }
                Err(match_pair)
            }

            PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
                if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
                    // irrefutable
                    self.prefix_slice_suffix(&mut candidate.match_pairs,
                                             &match_pair.place,
                                             prefix,
                                             slice.as_ref(),
                                             suffix);
                    Ok(())
                } else {
                    Err(match_pair)
                }
            }

            PatternKind::Variant { adt_def, substs, variant_index, ref subpatterns } => {
                let irrefutable = adt_def.variants.iter_enumerated().all(|(i, v)| {
                    i == variant_index || {
                        self.hir.tcx().features().never_type &&
                        self.hir.tcx().features().exhaustive_patterns &&
                        self.hir.tcx().is_variant_uninhabited_from_all_modules(v, substs)
                    }
                });
                if irrefutable {
                    let place = match_pair.place.downcast(adt_def, variant_index);
                    candidate.match_pairs.extend(self.field_match_pairs(place, subpatterns));
                    Ok(())
                } else {
                    Err(match_pair)
                }
            }

            PatternKind::Array { ref prefix, ref slice, ref suffix } => {
                self.prefix_slice_suffix(&mut candidate.match_pairs,
                                         &match_pair.place,
                                         prefix,
                                         slice.as_ref(),
                                         suffix);
                Ok(())
            }

            PatternKind::Leaf { ref subpatterns } => {
                // tuple struct, match subpats (if any)
                candidate.match_pairs
                         .extend(self.field_match_pairs(match_pair.place, subpatterns));
                Ok(())
            }

            PatternKind::Deref { ref subpattern } => {
                let place = match_pair.place.deref();
                candidate.match_pairs.push(MatchPair::new(place, subpattern));
                Ok(())
            }
        }
    }
}
<commit_msg>removed some unnecessary comments.<commit_after>//! Simplifying Candidates
//!
//! *Simplifying* a match pair `place @ pattern` means breaking it down
//! into bindings or other, simpler match pairs. For example:
//!
//! - `place @ (P1, P2)` can be simplified to `[place.0 @ P1, place.1 @ P2]`
//! - `place @ x` can be simplified to `[]` by binding `x` to `place`
//!
//! The `simplify_candidate` routine just repeatedly applies these
//! sort of simplifications until there is nothing left to
//! simplify. Match pairs cannot be simplified if they require some
//! sort of test: for example, testing which variant an enum is, or
//! testing a value against a constant.

use crate::build::Builder;
use crate::build::matches::{Ascription, Binding, MatchPair, Candidate};
use crate::hair::{self, *};
use rustc::ty;
use rustc::ty::layout::{Integer, IntegerExt, Size};
use syntax::attr::{SignedInt, UnsignedInt};
use rustc::hir::RangeEnd;
use rustc::mir::interpret::truncate;

use std::mem;

impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
    pub fn simplify_candidate<'pat>(&mut self,
                                    candidate: &mut Candidate<'pat, 'tcx>) {
        // repeatedly simplify match pairs until fixed point is reached
        loop {
            let match_pairs = mem::replace(&mut candidate.match_pairs, vec![]);
            let mut changed = false;
            for match_pair in match_pairs {
                match self.simplify_match_pair(match_pair, candidate) {
                    Ok(()) => {
                        changed = true;
                    }
                    Err(match_pair) => {
                        candidate.match_pairs.push(match_pair);
                    }
                }
            }
            if !changed {
                return; // if we were not able to simplify any, done.
            }
        }
    }

    /// Tries to simplify `match_pair`, returning `Ok(())` if
    /// successful. If successful, new match pairs and bindings will
    /// have been pushed into the candidate. If no simplification is
    /// possible, `Err` is returned and no changes are made to
    /// candidate.
    fn simplify_match_pair<'pat>(&mut self,
                                 match_pair: MatchPair<'pat, 'tcx>,
                                 candidate: &mut Candidate<'pat, 'tcx>)
                                 -> Result<(), MatchPair<'pat, 'tcx>> {
        let tcx = self.hir.tcx();
        match *match_pair.pattern.kind {
            PatternKind::AscribeUserType {
                ref subpattern,
                ascription: hair::pattern::Ascription {
                    variance,
                    ref user_ty,
                    user_ty_span,
                },
            } => {
                // Apply the type ascription to the value at `match_pair.place`, which is the
                // value being matched, taking the variance field into account.
                candidate.ascriptions.push(Ascription {
                    span: user_ty_span,
                    user_ty: user_ty.clone(),
                    source: match_pair.place.clone(),
                    variance,
                });

                candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));

                Ok(())
            }

            PatternKind::Wild => {
                // nothing left to do
                Ok(())
            }

            PatternKind::Binding { name, mutability, mode, var, ty, ref subpattern } => {
                candidate.bindings.push(Binding {
                    name,
                    mutability,
                    span: match_pair.pattern.span,
                    source: match_pair.place.clone(),
                    var_id: var,
                    var_ty: ty,
                    binding_mode: mode,
                });

                if let Some(subpattern) = subpattern.as_ref() {
                    // this is the `x @ P` case; have to keep matching against `P` now
                    candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));
                }

                Ok(())
            }

            PatternKind::Constant { .. } => {
                // FIXME normalize patterns when possible
                Err(match_pair)
            }

            PatternKind::Range(PatternRange { lo, hi, ty, end }) => {
                let (range, bias) = match ty.sty {
                    ty::Char => {
                        (Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))), 0)
                    }
                    ty::Int(ity) => {
                        let size = Integer::from_attr(&tcx, SignedInt(ity)).size();
                        let max = truncate(u128::max_value(), size);
                        let bias = 1u128 << (size.bits() - 1);
                        (Some((0, max, size)), bias)
                    }
                    ty::Uint(uty) => {
                        let size = Integer::from_attr(&tcx, UnsignedInt(uty)).size();
                        let max = truncate(u128::max_value(), size);
                        (Some((0, max, size)), 0)
                    }
                    _ => (None, 0),
                };
                if let Some((min, max, sz)) = range {
                    if let (Some(lo), Some(hi)) = (lo.val.try_to_bits(sz), hi.val.try_to_bits(sz)) {
                        // We want to compare ranges numerically, but the order of the bitwise
                        // representation of signed integers does not match their numeric order.
                        // Thus, to correct the ordering, we need to shift the range of signed
                        // integers to correct the comparison. This is achieved by XORing with a
                        // bias (see pattern/_match.rs for another pertinent example of this
                        // pattern).
                        let (lo, hi) = (lo ^ bias, hi ^ bias);
                        if lo <= min && (hi > max || hi == max && end == RangeEnd::Included) {
                            // Irrefutable pattern match.
                            return Ok(());
                        }
                    }
                }
                Err(match_pair)
            }

            PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
                if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
                    // irrefutable
                    self.prefix_slice_suffix(&mut candidate.match_pairs,
                                             &match_pair.place,
                                             prefix,
                                             slice.as_ref(),
                                             suffix);
                    Ok(())
                } else {
                    Err(match_pair)
                }
            }

            PatternKind::Variant { adt_def, substs, variant_index, ref subpatterns } => {
                let irrefutable = adt_def.variants.iter_enumerated().all(|(i, v)| {
                    i == variant_index || {
                        self.hir.tcx().features().never_type &&
                        self.hir.tcx().features().exhaustive_patterns &&
                        self.hir.tcx().is_variant_uninhabited_from_all_modules(v, substs)
                    }
                });
                if irrefutable {
                    let place = match_pair.place.downcast(adt_def, variant_index);
                    candidate.match_pairs.extend(self.field_match_pairs(place, subpatterns));
                    Ok(())
                } else {
                    Err(match_pair)
                }
            }

            PatternKind::Array { ref prefix, ref slice, ref suffix } => {
                self.prefix_slice_suffix(&mut candidate.match_pairs,
                                         &match_pair.place,
                                         prefix,
                                         slice.as_ref(),
                                         suffix);
                Ok(())
            }

            PatternKind::Leaf { ref subpatterns } => {
                // tuple struct, match subpats (if any)
                candidate.match_pairs
                         .extend(self.field_match_pairs(match_pair.place, subpatterns));
                Ok(())
            }

            PatternKind::Deref { ref subpattern } => {
                let place = match_pair.place.deref();
                candidate.match_pairs.push(MatchPair::new(place, subpattern));
                Ok(())
            }
        }
    }
}
<|endoftext|>