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

//! Per-node data used in style calculation.

use context::SharedStyleContext;
use dom::TElement;
use invalidation::element::restyle_hints::RestyleHint;
use properties::ComputedValues;
use properties::longhands::display::computed_value as display;
use rule_tree::StrongRuleNode;
use selector_parser::{EAGER_PSEUDO_COUNT, PseudoElement, RestyleDamage};
use shared_lock::StylesheetGuards;
use std::ops::{Deref, DerefMut};
use stylearc::Arc;

bitflags! {
    flags RestyleFlags: u8 {
        /// Whether the styles changed for this restyle.
        const WAS_RESTYLED = 1 << 0,
        /// Whether we reframed/reconstructed any ancestor or self.
        const ANCESTOR_WAS_RECONSTRUCTED = 1 << 1,
    }
}

/// Transient data used by the restyle algorithm. This structure is instantiated
/// either before or during restyle traversal, and is cleared at the end of node
/// processing.
#[derive(Debug)]
pub struct RestyleData {
    /// The restyle hint, which indicates whether selectors need to be rematched
    /// for this element, its children, and its descendants.
    pub hint: RestyleHint,

    /// A few flags to have in mind.
    flags: RestyleFlags,

    /// The restyle damage, indicating what kind of layout changes are required
    /// afte restyling.
    pub damage: RestyleDamage,
}

impl Default for RestyleData {
    fn default() -> Self {
        Self::new()
    }
}

impl RestyleData {
    fn new() -> Self {
        Self {
            hint: RestyleHint::empty(),
            flags: RestyleFlags::empty(),
            damage: RestyleDamage::empty(),
        }
    }

    /// Clear all the restyle state associated with this element.
    fn clear(&mut self) {
        *self = Self::new();
    }

    /// Clear restyle flags and damage.
    fn clear_flags_and_damage(&mut self) {
        self.damage = RestyleDamage::empty();
        self.flags = RestyleFlags::empty();
    }

    /// Returns whether this element or any ancestor is going to be
    /// reconstructed.
    pub fn reconstructed_self_or_ancestor(&self) -> bool {
        self.reconstructed_ancestor() || self.reconstructed_self()
    }

    /// Returns whether this element is going to be reconstructed.
    pub fn reconstructed_self(&self) -> bool {
        self.damage.contains(RestyleDamage::reconstruct())
    }

    /// Returns whether any ancestor of this element is going to be
    /// reconstructed.
    fn reconstructed_ancestor(&self) -> bool {
        self.flags.contains(ANCESTOR_WAS_RECONSTRUCTED)
    }

    /// Sets the flag that tells us whether we've reconstructed an ancestor.
    pub fn set_reconstructed_ancestor(&mut self) {
        // If it weren't for animation-only traversals, we could assert
        // `!self.reconstructed_ancestor()` here.
        self.flags.insert(ANCESTOR_WAS_RECONSTRUCTED);
    }

    /// Mark this element as restyled, which is useful to know whether we need
    /// to do a post-traversal.
    pub fn set_restyled(&mut self) {
        self.flags.insert(WAS_RESTYLED);
    }

    /// Mark this element as restyled, which is useful to know whether we need
    /// to do a post-traversal.
    pub fn is_restyle(&self) -> bool {
        self.flags.contains(WAS_RESTYLED)
    }

    /// Returns whether this element has been part of a restyle.
    pub fn contains_restyle_data(&self) -> bool {
        self.is_restyle() || !self.hint.is_empty() || !self.damage.is_empty()
    }
}

/// A lazily-allocated list of styles for eagerly-cascaded pseudo-elements.
///
/// We use an Arc so that sharing these styles via the style sharing cache does
/// not require duplicate allocations. We leverage the copy-on-write semantics of
/// Arc::make_mut(), which is free (i.e. does not require atomic RMU operations)
/// in servo_arc.
#[derive(Clone, Debug, Default)]
pub struct EagerPseudoStyles(Option<Arc<EagerPseudoArray>>);

#[derive(Debug, Default)]
struct EagerPseudoArray(EagerPseudoArrayInner);
type EagerPseudoArrayInner = [Option<Arc<ComputedValues>>; EAGER_PSEUDO_COUNT];

impl Deref for EagerPseudoArray {
    type Target = EagerPseudoArrayInner;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for EagerPseudoArray {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

// Manually implement `Clone` here because the derived impl of `Clone` for
// array types assumes the value inside is `Copy`.
impl Clone for EagerPseudoArray {
    fn clone(&self) -> Self {
        let mut clone = Self::default();
        for i in 0..EAGER_PSEUDO_COUNT {
            clone[i] = self.0[i].clone();
        }
        clone
    }
}

impl EagerPseudoStyles {
    /// Returns whether there are any pseudo styles.
    pub fn is_empty(&self) -> bool {
        self.0.is_none()
    }

    /// Grabs a reference to the list of styles, if they exist.
    pub fn as_array(&self) -> Option<&EagerPseudoArrayInner> {
        match self.0 {
            None => None,
            Some(ref x) => Some(&x.0),
        }
    }

    /// Returns a reference to the style for a given eager pseudo, if it exists.
    pub fn get(&self, pseudo: &PseudoElement) -> Option<&Arc<ComputedValues>> {
        debug_assert!(pseudo.is_eager());
        self.0.as_ref().and_then(|p| p[pseudo.eager_index()].as_ref())
    }

    /// Sets the style for the eager pseudo.
    pub fn set(&mut self, pseudo: &PseudoElement, value: Arc<ComputedValues>) {
        if self.0.is_none() {
            self.0 = Some(Arc::new(Default::default()));
        }
        let arr = Arc::make_mut(self.0.as_mut().unwrap());
        arr[pseudo.eager_index()] = Some(value);
    }
}

/// The styles associated with a node, including the styles for any
/// pseudo-elements.
#[derive(Clone, Debug, Default)]
pub struct ElementStyles {
    /// The element's style.
    pub primary: Option<Arc<ComputedValues>>,
    /// A list of the styles for the element's eagerly-cascaded pseudo-elements.
    pub pseudos: EagerPseudoStyles,
}

impl ElementStyles {
    /// Returns the primary style.
    pub fn get_primary(&self) -> Option<&Arc<ComputedValues>> {
        self.primary.as_ref()
    }

    /// Returns the primary style.  Panic if no style available.
    pub fn primary(&self) -> &Arc<ComputedValues> {
        self.primary.as_ref().unwrap()
    }

    /// Whether this element `display` value is `none`.
    pub fn is_display_none(&self) -> bool {
        self.primary().get_box().clone_display() == display::T::none
    }
}

/// Style system data associated with an Element.
///
/// In Gecko, this hangs directly off the Element. Servo, this is embedded
/// inside of layout data, which itself hangs directly off the Element. In
/// both cases, it is wrapped inside an AtomicRefCell to ensure thread safety.
#[derive(Debug, Default)]
pub struct ElementData {
    /// The styles for the element and its pseudo-elements.
    pub styles: ElementStyles,

    /// Restyle state.
    pub restyle: RestyleData,
}

/// The kind of restyle that a single element should do.
#[derive(Debug)]
pub enum RestyleKind {
    /// We need to run selector matching plus re-cascade, that is, a full
    /// restyle.
    MatchAndCascade,
    /// We need to recascade with some replacement rule, such as the style
    /// attribute, or animation rules.
    CascadeWithReplacements(RestyleHint),
    /// We only need to recascade, for example, because only inherited
    /// properties in the parent changed.
    CascadeOnly,
}

impl ElementData {
    /// Invalidates style for this element, its descendants, and later siblings,
    /// based on the snapshot of the element that we took when attributes or
    /// state changed.
    pub fn invalidate_style_if_needed<'a, E: TElement>(
        &mut self,
        element: E,
        shared_context: &SharedStyleContext)
    {
        use invalidation::element::invalidator::TreeStyleInvalidator;

        debug!("invalidate_style_if_needed: {:?}, flags: {:?}, has_snapshot: {}, \
                handled_snapshot: {}, pseudo: {:?}",
                element,
                shared_context.traversal_flags,
                element.has_snapshot(),
                element.handled_snapshot(),
                element.implemented_pseudo_element());

        if element.has_snapshot() && !element.handled_snapshot() {
            let invalidator = TreeStyleInvalidator::new(
                element,
                Some(self),
                shared_context,
            );
            invalidator.invalidate();
            unsafe { element.set_handled_snapshot() }
            debug_assert!(element.handled_snapshot());
        }
    }

    /// Returns true if this element has styles.
    pub fn has_styles(&self) -> bool {
        self.styles.primary.is_some()
    }

    /// Returns whether we have any outstanding style invalidation.
    pub fn has_invalidations(&self) -> bool {
        self.restyle.hint.has_self_invalidations()
    }

    /// Returns the kind of restyling that we're going to need to do on this
    /// element, based of the stored restyle hint.
    pub fn restyle_kind(&self,
                        shared_context: &SharedStyleContext)
                        -> RestyleKind {
        debug_assert!(!self.has_styles() || self.has_invalidations(),
                      "Should've stopped earlier");
        if !self.has_styles() {
            debug_assert!(!shared_context.traversal_flags.for_animation_only(),
                          "Unstyled element shouldn't be traversed during \
                           animation-only traversal");
            return RestyleKind::MatchAndCascade;
        }

        let hint = self.restyle.hint;
        if shared_context.traversal_flags.for_animation_only() {
            // return either CascadeWithReplacements or CascadeOnly in case of
            // animation-only restyle.
            if hint.has_animation_hint() {
                return RestyleKind::CascadeWithReplacements(hint & RestyleHint::for_animations());
            }
            return RestyleKind::CascadeOnly;
        }

        if hint.match_self() {
            return RestyleKind::MatchAndCascade;
        }

        if hint.has_replacements() {
            debug_assert!(!hint.has_animation_hint(),
                          "Animation only restyle hint should have already processed");
            return RestyleKind::CascadeWithReplacements(hint & RestyleHint::replacements());
        }

        debug_assert!(hint.has_recascade_self(),
                      "We definitely need to do something!");
        return RestyleKind::CascadeOnly;
    }

    /// Return true if important rules are different.
    /// We use this to make sure the cascade of off-main thread animations is correct.
    /// Note: Ignore custom properties for now because we only support opacity and transform
    ///       properties for animations running on compositor. Actually, we only care about opacity
    ///       and transform for now, but it's fine to compare all properties and let the user
    ///       the check which properties do they want.
    ///       If it costs too much, get_properties_overriding_animations() should return a set
    ///       containing only opacity and transform properties.
    pub fn important_rules_are_different(&self,
                                         rules: &StrongRuleNode,
                                         guards: &StylesheetGuards) -> bool {
        debug_assert!(self.has_styles());
        let (important_rules, _custom) =
            self.styles.primary().rules().get_properties_overriding_animations(&guards);
        let (other_important_rules, _custom) = rules.get_properties_overriding_animations(&guards);
        important_rules != other_important_rules
    }

    /// Drops any restyle state from the element.
    pub fn clear_restyle_state(&mut self) {
        self.restyle.clear();
    }

    /// Drops restyle flags and damage from the element.
    pub fn clear_restyle_flags_and_damage(&mut self) {
        self.restyle.clear_flags_and_damage();
    }
}
<commit_msg>Factor out restyle_kind_for_animation.<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/. */

//! Per-node data used in style calculation.

use context::SharedStyleContext;
use dom::TElement;
use invalidation::element::restyle_hints::RestyleHint;
use properties::ComputedValues;
use properties::longhands::display::computed_value as display;
use rule_tree::StrongRuleNode;
use selector_parser::{EAGER_PSEUDO_COUNT, PseudoElement, RestyleDamage};
use shared_lock::StylesheetGuards;
use std::ops::{Deref, DerefMut};
use stylearc::Arc;

bitflags! {
    flags RestyleFlags: u8 {
        /// Whether the styles changed for this restyle.
        const WAS_RESTYLED = 1 << 0,
        /// Whether we reframed/reconstructed any ancestor or self.
        const ANCESTOR_WAS_RECONSTRUCTED = 1 << 1,
    }
}

/// Transient data used by the restyle algorithm. This structure is instantiated
/// either before or during restyle traversal, and is cleared at the end of node
/// processing.
#[derive(Debug)]
pub struct RestyleData {
    /// The restyle hint, which indicates whether selectors need to be rematched
    /// for this element, its children, and its descendants.
    pub hint: RestyleHint,

    /// A few flags to have in mind.
    flags: RestyleFlags,

    /// The restyle damage, indicating what kind of layout changes are required
    /// afte restyling.
    pub damage: RestyleDamage,
}

impl Default for RestyleData {
    fn default() -> Self {
        Self::new()
    }
}

impl RestyleData {
    fn new() -> Self {
        Self {
            hint: RestyleHint::empty(),
            flags: RestyleFlags::empty(),
            damage: RestyleDamage::empty(),
        }
    }

    /// Clear all the restyle state associated with this element.
    fn clear(&mut self) {
        *self = Self::new();
    }

    /// Clear restyle flags and damage.
    fn clear_flags_and_damage(&mut self) {
        self.damage = RestyleDamage::empty();
        self.flags = RestyleFlags::empty();
    }

    /// Returns whether this element or any ancestor is going to be
    /// reconstructed.
    pub fn reconstructed_self_or_ancestor(&self) -> bool {
        self.reconstructed_ancestor() || self.reconstructed_self()
    }

    /// Returns whether this element is going to be reconstructed.
    pub fn reconstructed_self(&self) -> bool {
        self.damage.contains(RestyleDamage::reconstruct())
    }

    /// Returns whether any ancestor of this element is going to be
    /// reconstructed.
    fn reconstructed_ancestor(&self) -> bool {
        self.flags.contains(ANCESTOR_WAS_RECONSTRUCTED)
    }

    /// Sets the flag that tells us whether we've reconstructed an ancestor.
    pub fn set_reconstructed_ancestor(&mut self) {
        // If it weren't for animation-only traversals, we could assert
        // `!self.reconstructed_ancestor()` here.
        self.flags.insert(ANCESTOR_WAS_RECONSTRUCTED);
    }

    /// Mark this element as restyled, which is useful to know whether we need
    /// to do a post-traversal.
    pub fn set_restyled(&mut self) {
        self.flags.insert(WAS_RESTYLED);
    }

    /// Mark this element as restyled, which is useful to know whether we need
    /// to do a post-traversal.
    pub fn is_restyle(&self) -> bool {
        self.flags.contains(WAS_RESTYLED)
    }

    /// Returns whether this element has been part of a restyle.
    pub fn contains_restyle_data(&self) -> bool {
        self.is_restyle() || !self.hint.is_empty() || !self.damage.is_empty()
    }
}

/// A lazily-allocated list of styles for eagerly-cascaded pseudo-elements.
///
/// We use an Arc so that sharing these styles via the style sharing cache does
/// not require duplicate allocations. We leverage the copy-on-write semantics of
/// Arc::make_mut(), which is free (i.e. does not require atomic RMU operations)
/// in servo_arc.
#[derive(Clone, Debug, Default)]
pub struct EagerPseudoStyles(Option<Arc<EagerPseudoArray>>);

#[derive(Debug, Default)]
struct EagerPseudoArray(EagerPseudoArrayInner);
type EagerPseudoArrayInner = [Option<Arc<ComputedValues>>; EAGER_PSEUDO_COUNT];

impl Deref for EagerPseudoArray {
    type Target = EagerPseudoArrayInner;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for EagerPseudoArray {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

// Manually implement `Clone` here because the derived impl of `Clone` for
// array types assumes the value inside is `Copy`.
impl Clone for EagerPseudoArray {
    fn clone(&self) -> Self {
        let mut clone = Self::default();
        for i in 0..EAGER_PSEUDO_COUNT {
            clone[i] = self.0[i].clone();
        }
        clone
    }
}

impl EagerPseudoStyles {
    /// Returns whether there are any pseudo styles.
    pub fn is_empty(&self) -> bool {
        self.0.is_none()
    }

    /// Grabs a reference to the list of styles, if they exist.
    pub fn as_array(&self) -> Option<&EagerPseudoArrayInner> {
        match self.0 {
            None => None,
            Some(ref x) => Some(&x.0),
        }
    }

    /// Returns a reference to the style for a given eager pseudo, if it exists.
    pub fn get(&self, pseudo: &PseudoElement) -> Option<&Arc<ComputedValues>> {
        debug_assert!(pseudo.is_eager());
        self.0.as_ref().and_then(|p| p[pseudo.eager_index()].as_ref())
    }

    /// Sets the style for the eager pseudo.
    pub fn set(&mut self, pseudo: &PseudoElement, value: Arc<ComputedValues>) {
        if self.0.is_none() {
            self.0 = Some(Arc::new(Default::default()));
        }
        let arr = Arc::make_mut(self.0.as_mut().unwrap());
        arr[pseudo.eager_index()] = Some(value);
    }
}

/// The styles associated with a node, including the styles for any
/// pseudo-elements.
#[derive(Clone, Debug, Default)]
pub struct ElementStyles {
    /// The element's style.
    pub primary: Option<Arc<ComputedValues>>,
    /// A list of the styles for the element's eagerly-cascaded pseudo-elements.
    pub pseudos: EagerPseudoStyles,
}

impl ElementStyles {
    /// Returns the primary style.
    pub fn get_primary(&self) -> Option<&Arc<ComputedValues>> {
        self.primary.as_ref()
    }

    /// Returns the primary style.  Panic if no style available.
    pub fn primary(&self) -> &Arc<ComputedValues> {
        self.primary.as_ref().unwrap()
    }

    /// Whether this element `display` value is `none`.
    pub fn is_display_none(&self) -> bool {
        self.primary().get_box().clone_display() == display::T::none
    }
}

/// Style system data associated with an Element.
///
/// In Gecko, this hangs directly off the Element. Servo, this is embedded
/// inside of layout data, which itself hangs directly off the Element. In
/// both cases, it is wrapped inside an AtomicRefCell to ensure thread safety.
#[derive(Debug, Default)]
pub struct ElementData {
    /// The styles for the element and its pseudo-elements.
    pub styles: ElementStyles,

    /// Restyle state.
    pub restyle: RestyleData,
}

/// The kind of restyle that a single element should do.
#[derive(Debug)]
pub enum RestyleKind {
    /// We need to run selector matching plus re-cascade, that is, a full
    /// restyle.
    MatchAndCascade,
    /// We need to recascade with some replacement rule, such as the style
    /// attribute, or animation rules.
    CascadeWithReplacements(RestyleHint),
    /// We only need to recascade, for example, because only inherited
    /// properties in the parent changed.
    CascadeOnly,
}

impl ElementData {
    /// Invalidates style for this element, its descendants, and later siblings,
    /// based on the snapshot of the element that we took when attributes or
    /// state changed.
    pub fn invalidate_style_if_needed<'a, E: TElement>(
        &mut self,
        element: E,
        shared_context: &SharedStyleContext)
    {
        use invalidation::element::invalidator::TreeStyleInvalidator;

        debug!("invalidate_style_if_needed: {:?}, flags: {:?}, has_snapshot: {}, \
                handled_snapshot: {}, pseudo: {:?}",
                element,
                shared_context.traversal_flags,
                element.has_snapshot(),
                element.handled_snapshot(),
                element.implemented_pseudo_element());

        if element.has_snapshot() && !element.handled_snapshot() {
            let invalidator = TreeStyleInvalidator::new(
                element,
                Some(self),
                shared_context,
            );
            invalidator.invalidate();
            unsafe { element.set_handled_snapshot() }
            debug_assert!(element.handled_snapshot());
        }
    }

    /// Returns true if this element has styles.
    pub fn has_styles(&self) -> bool {
        self.styles.primary.is_some()
    }

    /// Returns whether we have any outstanding style invalidation.
    pub fn has_invalidations(&self) -> bool {
        self.restyle.hint.has_self_invalidations()
    }

    /// Returns the kind of restyling that we're going to need to do on this
    /// element, based of the stored restyle hint.
    pub fn restyle_kind(&self,
                        shared_context: &SharedStyleContext)
                        -> RestyleKind {
        if shared_context.traversal_flags.for_animation_only() {
            return self.restyle_kind_for_animation(shared_context);
        }

        debug_assert!(!self.has_styles() || self.has_invalidations(),
                      "Should've stopped earlier");
        if !self.has_styles() {
            return RestyleKind::MatchAndCascade;
        }

        let hint = self.restyle.hint;
        if hint.match_self() {
            return RestyleKind::MatchAndCascade;
        }

        if hint.has_replacements() {
            debug_assert!(!hint.has_animation_hint(),
                          "Animation only restyle hint should have already processed");
            return RestyleKind::CascadeWithReplacements(hint & RestyleHint::replacements());
        }

        debug_assert!(hint.has_recascade_self(),
                      "We definitely need to do something!");
        return RestyleKind::CascadeOnly;
    }

    /// Returns the kind of restyling for animation-only restyle.
    pub fn restyle_kind_for_animation(&self,
                                      shared_context: &SharedStyleContext)
                                      -> RestyleKind {
        debug_assert!(shared_context.traversal_flags.for_animation_only());
        debug_assert!(self.has_styles(),
                      "Unstyled element shouldn't be traversed during \
                       animation-only traversal");

        // return either CascadeWithReplacements or CascadeOnly in case of
        // animation-only restyle. I.e. animation-only restyle never does
        // selector matching.
        let hint = self.restyle.hint;
        if hint.has_animation_hint() {
            return RestyleKind::CascadeWithReplacements(hint & RestyleHint::for_animations());
        }
        return RestyleKind::CascadeOnly;

    }

    /// Return true if important rules are different.
    /// We use this to make sure the cascade of off-main thread animations is correct.
    /// Note: Ignore custom properties for now because we only support opacity and transform
    ///       properties for animations running on compositor. Actually, we only care about opacity
    ///       and transform for now, but it's fine to compare all properties and let the user
    ///       the check which properties do they want.
    ///       If it costs too much, get_properties_overriding_animations() should return a set
    ///       containing only opacity and transform properties.
    pub fn important_rules_are_different(&self,
                                         rules: &StrongRuleNode,
                                         guards: &StylesheetGuards) -> bool {
        debug_assert!(self.has_styles());
        let (important_rules, _custom) =
            self.styles.primary().rules().get_properties_overriding_animations(&guards);
        let (other_important_rules, _custom) = rules.get_properties_overriding_animations(&guards);
        important_rules != other_important_rules
    }

    /// Drops any restyle state from the element.
    pub fn clear_restyle_state(&mut self) {
        self.restyle.clear();
    }

    /// Drops restyle flags and damage from the element.
    pub fn clear_restyle_flags_and_damage(&mut self) {
        self.restyle.clear_flags_and_damage();
    }
}
<|endoftext|>


<commit_before>// This file is part of libfringe, a low-level green threading library.
// Copyright (c) 2015, edef <edef@edef.eu>
// See the LICENSE file included in this distribution.
#![feature(asm, test)]
extern crate test;
use test::Bencher;

#[bench]
fn kernel_swap(b: &mut Bencher) {
  b.iter(|| unsafe {
    asm!("movq $$102, %rax\n\
          syscall"
         :
         :
         : "rax", "rcx"
         : "volatile");
  });
}
<commit_msg>only build benches/kernel_swap on Linux<commit_after>// This file is part of libfringe, a low-level green threading library.
// Copyright (c) 2015, edef <edef@edef.eu>
// See the LICENSE file included in this distribution.
#![cfg(target_os = "linux")]
#![feature(asm, test)]
extern crate test;
use test::Bencher;

#[bench]
fn kernel_swap(b: &mut Bencher) {
  b.iter(|| unsafe {
    asm!("movq $$102, %rax\n\
          syscall"
         :
         :
         : "rax", "rcx"
         : "volatile");
  });
}
<|endoftext|>


<commit_before>use super::{
    conversion_type::ConversionType, out_parameters::can_as_return,
    override_string_type::override_string_type_parameter, ref_mode::RefMode, rust_type::rust_type,
};
use crate::{
    config::{self, parameter_matchable::ParameterMatchable},
    env::Env,
    library::{self, ParameterScope, TypeId},
    nameutil,
    traits::IntoString,
};
use std::collections::HashMap;

//TODO: remove unused fields
#[derive(Clone, Debug)]
pub struct RustParameter {
    pub ind_c: usize, //index in `Vec<CParameter>`
    pub name: String,
    pub typ: TypeId,
    pub allow_none: bool,
}

#[derive(Clone, Debug)]
pub struct CParameter {
    pub name: String,
    pub typ: TypeId,
    pub c_type: String,
    pub instance_parameter: bool,
    pub direction: library::ParameterDirection,
    pub nullable: library::Nullable,
    pub transfer: library::Transfer,
    pub caller_allocates: bool,
    pub is_error: bool,
    pub scope: ParameterScope,
    /// Index of the user data parameter associated with the callback.
    pub user_data_index: Option<usize>,
    /// Index of the destroy notification parameter associated with the callback.
    pub destroy_index: Option<usize>,

    //analysis fields
    pub ref_mode: RefMode,
}

#[derive(Clone, Debug)]
pub enum TransformationType {
    ToGlibDirect {
        name: String,
    },
    ToGlibScalar {
        name: String,
        nullable: library::Nullable,
    },
    ToGlibPointer {
        name: String,
        instance_parameter: bool,
        transfer: library::Transfer,
        ref_mode: RefMode,
        //filled by functions
        to_glib_extra: String,
        explicit_target_type: String,
        pointer_cast: String,
        in_trait: bool,
        nullable: bool,
    },
    ToGlibBorrow,
    ToGlibUnknown {
        name: String,
    },
    Length {
        array_name: String,
        array_length_name: String,
        array_length_type: String,
    },
    IntoRaw(String),
    ToSome(String),
}

impl TransformationType {
    pub fn is_to_glib(&self) -> bool {
        use self::TransformationType::*;
        matches!(*self,
            ToGlibDirect { .. }
            | ToGlibScalar { .. }
            | ToGlibPointer { .. }
            | ToGlibBorrow
            | ToGlibUnknown { .. }
            | ToSome(_)
            | IntoRaw(_))
    }

    pub fn set_to_glib_extra(&mut self, to_glib_extra_: &str) {
        if let TransformationType::ToGlibPointer {
            ref mut to_glib_extra,
            ..
        } = *self
        {
            *to_glib_extra = to_glib_extra_.to_owned();
        }
    }
}

#[derive(Clone, Debug)]
pub struct Transformation {
    pub ind_c: usize,            //index in `Vec<CParameter>`
    pub ind_rust: Option<usize>, //index in `Vec<RustParameter>`
    pub transformation_type: TransformationType,
}

#[derive(Clone, Default, Debug)]
pub struct Parameters {
    pub rust_parameters: Vec<RustParameter>,
    pub c_parameters: Vec<CParameter>,
    pub transformations: Vec<Transformation>,
}

impl Parameters {
    fn new(capacity: usize) -> Parameters {
        Parameters {
            rust_parameters: Vec::with_capacity(capacity),
            c_parameters: Vec::with_capacity(capacity),
            transformations: Vec::with_capacity(capacity),
        }
    }

    pub fn analyze_return(&mut self, env: &Env, ret: &Option<library::Parameter>) {
        let array_length = if let Some(array_length) = ret.as_ref().and_then(|r| r.array_length) {
            array_length
        } else {
            return;
        };

        let ind_c = array_length as usize;

        let par = if let Some(par) = self.c_parameters.get(ind_c) {
            par
        } else {
            return;
        };

        let transformation = Transformation {
            ind_c,
            ind_rust: None,
            transformation_type: get_length_type(env, "", &par.name, par.typ),
        };
        self.transformations.push(transformation);
    }
}

#[allow(clippy::useless_let_if_seq)]
pub fn analyze(
    env: &Env,
    function_parameters: &[library::Parameter],
    configured_functions: &[&config::functions::Function],
    disable_length_detect: bool,
    async_func: bool,
    in_trait: bool,
) -> Parameters {
    let mut parameters = Parameters::new(function_parameters.len());

    // Map: length argument position => array name
    let array_lengths: HashMap<u32, String> = function_parameters
        .iter()
        .filter_map(|p| p.array_length.map(|pos| (pos, p.name.clone())))
        .collect();

    for (pos, par) in function_parameters.iter().enumerate() {
        let name = if par.instance_parameter {
            par.name.clone()
        } else {
            nameutil::mangle_keywords(&*par.name).into_owned()
        };

        let configured_parameters = configured_functions.matched_parameters(&name);

        let c_type = par.c_type.clone();
        let typ = override_string_type_parameter(env, par.typ, &configured_parameters);

        let ind_c = parameters.c_parameters.len();
        let mut ind_rust = Some(parameters.rust_parameters.len());

        let mut add_rust_parameter = match par.direction {
            library::ParameterDirection::In | library::ParameterDirection::InOut => true,
            library::ParameterDirection::Return => false,
            library::ParameterDirection::Out => !can_as_return(env, par) && !async_func,
        };

        if async_func && async_param_to_remove(&par.name) {
            add_rust_parameter = false;
        }

        let mut array_name = configured_parameters
            .iter()
            .filter_map(|p| p.length_of.as_ref())
            .next();
        if array_name.is_none() {
            array_name = array_lengths.get(&(pos as u32))
        }
        if array_name.is_none() && !disable_length_detect {
            array_name = detect_length(env, pos, par, function_parameters);
        }
        if let Some(array_name) = array_name {
            let array_name = nameutil::mangle_keywords(&array_name[..]);
            add_rust_parameter = false;

            let transformation = Transformation {
                ind_c,
                ind_rust: None,
                transformation_type: get_length_type(env, &array_name, &par.name, typ),
            };
            parameters.transformations.push(transformation);
        }

        let mut caller_allocates = par.caller_allocates;
        let mut transfer = par.transfer;
        let conversion = ConversionType::of(env, typ);
        if conversion == ConversionType::Direct || conversion == ConversionType::Scalar {
            //For simply types no reason to have these flags
            caller_allocates = false;
            transfer = library::Transfer::None;
        }

        let immutable = configured_parameters.iter().any(|p| p.constant);
        let ref_mode =
            RefMode::without_unneeded_mut(env, par, immutable, in_trait && par.instance_parameter);

        let nullable_override = configured_parameters
            .iter()
            .filter_map(|p| p.nullable)
            .next();
        let nullable = nullable_override.unwrap_or(par.nullable);

        let c_par = CParameter {
            name: name.clone(),
            typ,
            c_type,
            instance_parameter: par.instance_parameter,
            direction: par.direction,
            transfer,
            caller_allocates,
            nullable,
            ref_mode,
            is_error: par.is_error,
            scope: par.scope,
            user_data_index: par.closure,
            destroy_index: par.destroy,
        };
        parameters.c_parameters.push(c_par);

        let data_param_name = "user_data";
        let callback_param_name = "callback";

        if add_rust_parameter {
            let rust_par = RustParameter {
                name: name.clone(),
                typ,
                ind_c,
                allow_none: par.allow_none,
            };
            parameters.rust_parameters.push(rust_par);
        } else {
            ind_rust = None;
        }

        let mut trans_nullable = false;
        let type_ = env.type_(par.typ);
        let to_glib_extra =
            if par.instance_parameter || !*nullable || (!type_.is_interface() && !type_.is_class())
            {
                String::new()
            } else {
                trans_nullable = *nullable;
                if !type_.is_final_type() {
                    ".as_ref()".to_owned()
                } else {
                    String::new()
                }
            };

        let transformation_type = match ConversionType::of(env, typ) {
            ConversionType::Direct => {
                if par.c_type != "GLib.Pid" {
                    TransformationType::ToGlibDirect { name }
                } else {
                    TransformationType::ToGlibScalar { name, nullable }
                }
            }
            ConversionType::Scalar => TransformationType::ToGlibScalar { name, nullable },
            ConversionType::Pointer => TransformationType::ToGlibPointer {
                name,
                instance_parameter: par.instance_parameter,
                transfer,
                ref_mode,
                to_glib_extra,
                explicit_target_type: String::new(),
                pointer_cast: String::new(),
                in_trait,
                nullable: trans_nullable,
            },
            ConversionType::Borrow => TransformationType::ToGlibBorrow,
            ConversionType::Unknown => TransformationType::ToGlibUnknown { name },
        };

        let mut transformation = Transformation {
            ind_c,
            ind_rust,
            transformation_type,
        };
        let mut transformation_type = None;
        match transformation.transformation_type {
            TransformationType::ToGlibDirect { ref name, .. }
            | TransformationType::ToGlibUnknown { ref name, .. } => {
                if async_func && name == callback_param_name {
                    // Remove the conversion of callback for async functions.
                    transformation_type = Some(TransformationType::ToSome(name.clone()));
                }
            }
            TransformationType::ToGlibPointer { ref name, .. } => {
                if async_func && name == data_param_name {
                    // Do the conversion of user_data for async functions.
                    // In async functions, this argument is used to send the callback.
                    transformation_type = Some(TransformationType::IntoRaw(name.clone()));
                }
            }
            _ => (),
        }
        if let Some(transformation_type) = transformation_type {
            transformation.transformation_type = transformation_type;
        }
        parameters.transformations.push(transformation);
    }

    parameters
}

fn get_length_type(
    env: &Env,
    array_name: &str,
    length_name: &str,
    length_typ: TypeId,
) -> TransformationType {
    let array_length_type = rust_type(env, length_typ).into_string();
    TransformationType::Length {
        array_name: array_name.to_string(),
        array_length_name: length_name.to_string(),
        array_length_type,
    }
}

fn detect_length<'a>(
    env: &Env,
    pos: usize,
    par: &library::Parameter,
    parameters: &'a [library::Parameter],
) -> Option<&'a String> {
    if !is_length(par) {
        return None;
    }

    let array = parameters.get(pos - 1).and_then(|p| {
        if has_length(env, p.typ) {
            Some(p)
        } else {
            None
        }
    });
    array.map(|p| &p.name)
}

fn is_length(par: &library::Parameter) -> bool {
    if par.direction != library::ParameterDirection::In {
        return false;
    }

    let len = par.name.len();
    if len >= 3 && &par.name[len - 3..len] == "len" {
        return true;
    }

    par.name.contains("length")
}

fn has_length(env: &Env, typ: TypeId) -> bool {
    use crate::library::Type;
    let typ = env.library.type_(typ);
    match *typ {
        Type::Fundamental(fund) => {
            use crate::library::Fundamental::*;
            matches!(fund, Utf8 | Filename | OsString)
        }
        Type::CArray(..)
        | Type::FixedArray(..)
        | Type::Array(..)
        | Type::PtrArray(..)
        | Type::List(..)
        | Type::SList(..)
        | Type::HashTable(..) => true,
        Type::Alias(ref alias) => has_length(env, alias.typ),
        _ => false,
    }
}

pub fn async_param_to_remove(name: &str) -> bool {
    name == "user_data" || name.ends_with("data") // FIXME: use async indexes instead
}
<commit_msg>Update fmt<commit_after>use super::{
    conversion_type::ConversionType, out_parameters::can_as_return,
    override_string_type::override_string_type_parameter, ref_mode::RefMode, rust_type::rust_type,
};
use crate::{
    config::{self, parameter_matchable::ParameterMatchable},
    env::Env,
    library::{self, ParameterScope, TypeId},
    nameutil,
    traits::IntoString,
};
use std::collections::HashMap;

//TODO: remove unused fields
#[derive(Clone, Debug)]
pub struct RustParameter {
    pub ind_c: usize, //index in `Vec<CParameter>`
    pub name: String,
    pub typ: TypeId,
    pub allow_none: bool,
}

#[derive(Clone, Debug)]
pub struct CParameter {
    pub name: String,
    pub typ: TypeId,
    pub c_type: String,
    pub instance_parameter: bool,
    pub direction: library::ParameterDirection,
    pub nullable: library::Nullable,
    pub transfer: library::Transfer,
    pub caller_allocates: bool,
    pub is_error: bool,
    pub scope: ParameterScope,
    /// Index of the user data parameter associated with the callback.
    pub user_data_index: Option<usize>,
    /// Index of the destroy notification parameter associated with the callback.
    pub destroy_index: Option<usize>,

    //analysis fields
    pub ref_mode: RefMode,
}

#[derive(Clone, Debug)]
pub enum TransformationType {
    ToGlibDirect {
        name: String,
    },
    ToGlibScalar {
        name: String,
        nullable: library::Nullable,
    },
    ToGlibPointer {
        name: String,
        instance_parameter: bool,
        transfer: library::Transfer,
        ref_mode: RefMode,
        //filled by functions
        to_glib_extra: String,
        explicit_target_type: String,
        pointer_cast: String,
        in_trait: bool,
        nullable: bool,
    },
    ToGlibBorrow,
    ToGlibUnknown {
        name: String,
    },
    Length {
        array_name: String,
        array_length_name: String,
        array_length_type: String,
    },
    IntoRaw(String),
    ToSome(String),
}

impl TransformationType {
    pub fn is_to_glib(&self) -> bool {
        use self::TransformationType::*;
        matches!(
            *self,
            ToGlibDirect { .. }
                | ToGlibScalar { .. }
                | ToGlibPointer { .. }
                | ToGlibBorrow
                | ToGlibUnknown { .. }
                | ToSome(_)
                | IntoRaw(_)
        )
    }

    pub fn set_to_glib_extra(&mut self, to_glib_extra_: &str) {
        if let TransformationType::ToGlibPointer {
            ref mut to_glib_extra,
            ..
        } = *self
        {
            *to_glib_extra = to_glib_extra_.to_owned();
        }
    }
}

#[derive(Clone, Debug)]
pub struct Transformation {
    pub ind_c: usize,            //index in `Vec<CParameter>`
    pub ind_rust: Option<usize>, //index in `Vec<RustParameter>`
    pub transformation_type: TransformationType,
}

#[derive(Clone, Default, Debug)]
pub struct Parameters {
    pub rust_parameters: Vec<RustParameter>,
    pub c_parameters: Vec<CParameter>,
    pub transformations: Vec<Transformation>,
}

impl Parameters {
    fn new(capacity: usize) -> Parameters {
        Parameters {
            rust_parameters: Vec::with_capacity(capacity),
            c_parameters: Vec::with_capacity(capacity),
            transformations: Vec::with_capacity(capacity),
        }
    }

    pub fn analyze_return(&mut self, env: &Env, ret: &Option<library::Parameter>) {
        let array_length = if let Some(array_length) = ret.as_ref().and_then(|r| r.array_length) {
            array_length
        } else {
            return;
        };

        let ind_c = array_length as usize;

        let par = if let Some(par) = self.c_parameters.get(ind_c) {
            par
        } else {
            return;
        };

        let transformation = Transformation {
            ind_c,
            ind_rust: None,
            transformation_type: get_length_type(env, "", &par.name, par.typ),
        };
        self.transformations.push(transformation);
    }
}

#[allow(clippy::useless_let_if_seq)]
pub fn analyze(
    env: &Env,
    function_parameters: &[library::Parameter],
    configured_functions: &[&config::functions::Function],
    disable_length_detect: bool,
    async_func: bool,
    in_trait: bool,
) -> Parameters {
    let mut parameters = Parameters::new(function_parameters.len());

    // Map: length argument position => array name
    let array_lengths: HashMap<u32, String> = function_parameters
        .iter()
        .filter_map(|p| p.array_length.map(|pos| (pos, p.name.clone())))
        .collect();

    for (pos, par) in function_parameters.iter().enumerate() {
        let name = if par.instance_parameter {
            par.name.clone()
        } else {
            nameutil::mangle_keywords(&*par.name).into_owned()
        };

        let configured_parameters = configured_functions.matched_parameters(&name);

        let c_type = par.c_type.clone();
        let typ = override_string_type_parameter(env, par.typ, &configured_parameters);

        let ind_c = parameters.c_parameters.len();
        let mut ind_rust = Some(parameters.rust_parameters.len());

        let mut add_rust_parameter = match par.direction {
            library::ParameterDirection::In | library::ParameterDirection::InOut => true,
            library::ParameterDirection::Return => false,
            library::ParameterDirection::Out => !can_as_return(env, par) && !async_func,
        };

        if async_func && async_param_to_remove(&par.name) {
            add_rust_parameter = false;
        }

        let mut array_name = configured_parameters
            .iter()
            .filter_map(|p| p.length_of.as_ref())
            .next();
        if array_name.is_none() {
            array_name = array_lengths.get(&(pos as u32))
        }
        if array_name.is_none() && !disable_length_detect {
            array_name = detect_length(env, pos, par, function_parameters);
        }
        if let Some(array_name) = array_name {
            let array_name = nameutil::mangle_keywords(&array_name[..]);
            add_rust_parameter = false;

            let transformation = Transformation {
                ind_c,
                ind_rust: None,
                transformation_type: get_length_type(env, &array_name, &par.name, typ),
            };
            parameters.transformations.push(transformation);
        }

        let mut caller_allocates = par.caller_allocates;
        let mut transfer = par.transfer;
        let conversion = ConversionType::of(env, typ);
        if conversion == ConversionType::Direct || conversion == ConversionType::Scalar {
            //For simply types no reason to have these flags
            caller_allocates = false;
            transfer = library::Transfer::None;
        }

        let immutable = configured_parameters.iter().any(|p| p.constant);
        let ref_mode =
            RefMode::without_unneeded_mut(env, par, immutable, in_trait && par.instance_parameter);

        let nullable_override = configured_parameters
            .iter()
            .filter_map(|p| p.nullable)
            .next();
        let nullable = nullable_override.unwrap_or(par.nullable);

        let c_par = CParameter {
            name: name.clone(),
            typ,
            c_type,
            instance_parameter: par.instance_parameter,
            direction: par.direction,
            transfer,
            caller_allocates,
            nullable,
            ref_mode,
            is_error: par.is_error,
            scope: par.scope,
            user_data_index: par.closure,
            destroy_index: par.destroy,
        };
        parameters.c_parameters.push(c_par);

        let data_param_name = "user_data";
        let callback_param_name = "callback";

        if add_rust_parameter {
            let rust_par = RustParameter {
                name: name.clone(),
                typ,
                ind_c,
                allow_none: par.allow_none,
            };
            parameters.rust_parameters.push(rust_par);
        } else {
            ind_rust = None;
        }

        let mut trans_nullable = false;
        let type_ = env.type_(par.typ);
        let to_glib_extra =
            if par.instance_parameter || !*nullable || (!type_.is_interface() && !type_.is_class())
            {
                String::new()
            } else {
                trans_nullable = *nullable;
                if !type_.is_final_type() {
                    ".as_ref()".to_owned()
                } else {
                    String::new()
                }
            };

        let transformation_type = match ConversionType::of(env, typ) {
            ConversionType::Direct => {
                if par.c_type != "GLib.Pid" {
                    TransformationType::ToGlibDirect { name }
                } else {
                    TransformationType::ToGlibScalar { name, nullable }
                }
            }
            ConversionType::Scalar => TransformationType::ToGlibScalar { name, nullable },
            ConversionType::Pointer => TransformationType::ToGlibPointer {
                name,
                instance_parameter: par.instance_parameter,
                transfer,
                ref_mode,
                to_glib_extra,
                explicit_target_type: String::new(),
                pointer_cast: String::new(),
                in_trait,
                nullable: trans_nullable,
            },
            ConversionType::Borrow => TransformationType::ToGlibBorrow,
            ConversionType::Unknown => TransformationType::ToGlibUnknown { name },
        };

        let mut transformation = Transformation {
            ind_c,
            ind_rust,
            transformation_type,
        };
        let mut transformation_type = None;
        match transformation.transformation_type {
            TransformationType::ToGlibDirect { ref name, .. }
            | TransformationType::ToGlibUnknown { ref name, .. } => {
                if async_func && name == callback_param_name {
                    // Remove the conversion of callback for async functions.
                    transformation_type = Some(TransformationType::ToSome(name.clone()));
                }
            }
            TransformationType::ToGlibPointer { ref name, .. } => {
                if async_func && name == data_param_name {
                    // Do the conversion of user_data for async functions.
                    // In async functions, this argument is used to send the callback.
                    transformation_type = Some(TransformationType::IntoRaw(name.clone()));
                }
            }
            _ => (),
        }
        if let Some(transformation_type) = transformation_type {
            transformation.transformation_type = transformation_type;
        }
        parameters.transformations.push(transformation);
    }

    parameters
}

fn get_length_type(
    env: &Env,
    array_name: &str,
    length_name: &str,
    length_typ: TypeId,
) -> TransformationType {
    let array_length_type = rust_type(env, length_typ).into_string();
    TransformationType::Length {
        array_name: array_name.to_string(),
        array_length_name: length_name.to_string(),
        array_length_type,
    }
}

fn detect_length<'a>(
    env: &Env,
    pos: usize,
    par: &library::Parameter,
    parameters: &'a [library::Parameter],
) -> Option<&'a String> {
    if !is_length(par) {
        return None;
    }

    let array = parameters.get(pos - 1).and_then(|p| {
        if has_length(env, p.typ) {
            Some(p)
        } else {
            None
        }
    });
    array.map(|p| &p.name)
}

fn is_length(par: &library::Parameter) -> bool {
    if par.direction != library::ParameterDirection::In {
        return false;
    }

    let len = par.name.len();
    if len >= 3 && &par.name[len - 3..len] == "len" {
        return true;
    }

    par.name.contains("length")
}

fn has_length(env: &Env, typ: TypeId) -> bool {
    use crate::library::Type;
    let typ = env.library.type_(typ);
    match *typ {
        Type::Fundamental(fund) => {
            use crate::library::Fundamental::*;
            matches!(fund, Utf8 | Filename | OsString)
        }
        Type::CArray(..)
        | Type::FixedArray(..)
        | Type::Array(..)
        | Type::PtrArray(..)
        | Type::List(..)
        | Type::SList(..)
        | Type::HashTable(..) => true,
        Type::Alias(ref alias) => has_length(env, alias.typ),
        _ => false,
    }
}

pub fn async_param_to_remove(name: &str) -> bool {
    name == "user_data" || name.ends_with("data") // FIXME: use async indexes instead
}
<|endoftext|>


<commit_before>use crate::algorithm::{AlgorithmType, SigningAlgorithm, VerifyingAlgorithm};
use crate::error::Error;
use crate::SEPARATOR;
use openssl::bn::BigNum;
use openssl::ecdsa::EcdsaSig;
use openssl::hash::MessageDigest;
use openssl::nid::Nid;
use openssl::pkey::{Id, PKey, Private, Public};
use openssl::sign::{Signer, Verifier};

pub struct PKeyWithDigest<T> {
    pub digest: MessageDigest,
    pub key: PKey<T>,
}

impl<T> PKeyWithDigest<T> {
    fn algorithm_type(&self) -> AlgorithmType {
        match (self.key.id(), self.digest.type_()) {
            (Id::RSA, Nid::SHA256) => AlgorithmType::Rs256,
            (Id::EC, Nid::SHA256) => AlgorithmType::Es256,
            _ => panic!("Invalid algorithm type"),
        }
    }
}

impl SigningAlgorithm for PKeyWithDigest<Private> {
    fn algorithm_type(&self) -> AlgorithmType {
        PKeyWithDigest::algorithm_type(self)
    }

    fn sign(&self, header: &str, claims: &str) -> Result<String, Error> {
        let mut signer = Signer::new(self.digest.clone(), &self.key)?;
        signer.update(header.as_bytes())?;
        signer.update(SEPARATOR.as_bytes())?;
        signer.update(claims.as_bytes())?;
        let signer_signature = signer.sign_to_vec()?;

        let signature = if self.key.id() == Id::EC {
            let der_signature = signer_signature;

            let signature = EcdsaSig::from_der(&der_signature)?;
            let r = signature.r().to_vec();
            let s = signature.s().to_vec();
            [r, s].concat()
        } else {
            signer_signature
        };

        Ok(base64::encode_config(&signature, base64::URL_SAFE_NO_PAD))
    }
}

impl VerifyingAlgorithm for PKeyWithDigest<Public> {
    fn algorithm_type(&self) -> AlgorithmType {
        PKeyWithDigest::algorithm_type(self)
    }

    fn verify_bytes(&self, header: &str, claims: &str, signature: &[u8]) -> Result<bool, Error> {
        let mut verifier = Verifier::new(self.digest.clone(), &self.key)?;
        verifier.update(header.as_bytes())?;
        verifier.update(SEPARATOR.as_bytes())?;
        verifier.update(claims.as_bytes())?;

        let verified = if self.key.id() == Id::EC {
            let (r, s) = signature.split_at(signature.len() / 2);
            let ecdsa_signature =
                EcdsaSig::from_private_components(BigNum::from_slice(r)?, BigNum::from_slice(s)?)?;
            let der_signature = ecdsa_signature.to_der()?;
            verifier.verify(&der_signature)?
        } else {
            verifier.verify(signature)?
        };

        Ok(verified)
    }
}

#[cfg(test)]
mod tests {
    use crate::algorithm::openssl::PKeyWithDigest;
    use crate::algorithm::{SigningAlgorithm, VerifyingAlgorithm};
    use openssl::hash::MessageDigest;
    use openssl::pkey::PKey;

    // {"alg":"RS256","typ":"JWT"}
    const RS256_HEADER: &'static str = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9";
    // {"alg":"ES256","typ":"JWT"}
    const ES256_HEADER: &'static str = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9";
    // {"sub":"1234567890","name":"John Doe","admin":true}
    const CLAIMS: &'static str =
        "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9";

    const RS256_SIGNATURE: &'static str =
    "EkN-DOsnsuRjRO6BxXemmJDm3HbxrbRzXglbN2S4sOkopdU4IsDxTI8jO19W_A4K8ZPJijNLis4EZsHeY559a4DFOd50_OqgHGuERTqYZyuhtF39y\
    xJPAjUESwxk2J5k_4zM3O-vtd1Ghyo4IbqKKSy6J9mTniYJPenn5-HIirE";

    #[test]
    fn rs256_sign() {
        let pem = include_bytes!("../../test/rs256-private.pem");

        let algorithm = PKeyWithDigest {
            digest: MessageDigest::sha256(),
            key: PKey::private_key_from_pem(pem).unwrap(),
        };

        let result = algorithm.sign(RS256_HEADER, CLAIMS).unwrap();
        assert_eq!(result, RS256_SIGNATURE);
    }

    #[test]
    fn rs256_verify() {
        let pem = include_bytes!("../../test/rs256-public.pem");

        let algorithm = PKeyWithDigest {
            digest: MessageDigest::sha256(),
            key: PKey::public_key_from_pem(pem).unwrap(),
        };

        assert!(algorithm
            .verify(RS256_HEADER, CLAIMS, RS256_SIGNATURE)
            .unwrap_or(false));
    }

    #[test]
    fn es256() {
        let private_pem = include_bytes!("../../test/es256-private.pem");
        let private_key = PKeyWithDigest {
            digest: MessageDigest::sha256(),
            key: PKey::private_key_from_pem(private_pem).unwrap(),
        };

        let signature = private_key.sign(ES256_HEADER, CLAIMS).unwrap();

        let public_pem = include_bytes!("../../test/es256-public.pem");

        let public_key = PKeyWithDigest {
            digest: MessageDigest::sha256(),
            key: PKey::public_key_from_pem(public_pem).unwrap(),
        };

        assert!(public_key
            .verify(ES256_HEADER, CLAIMS, &*signature)
            .unwrap_or(false));
    }
}
<commit_msg>Factor out DER JOSE conversion methods<commit_after>use crate::algorithm::{AlgorithmType, SigningAlgorithm, VerifyingAlgorithm};
use crate::error::Error;
use crate::SEPARATOR;
use openssl::bn::BigNum;
use openssl::ecdsa::EcdsaSig;
use openssl::hash::MessageDigest;
use openssl::nid::Nid;
use openssl::pkey::{Id, PKey, Private, Public};
use openssl::sign::{Signer, Verifier};

pub struct PKeyWithDigest<T> {
    pub digest: MessageDigest,
    pub key: PKey<T>,
}

impl<T> PKeyWithDigest<T> {
    fn algorithm_type(&self) -> AlgorithmType {
        match (self.key.id(), self.digest.type_()) {
            (Id::RSA, Nid::SHA256) => AlgorithmType::Rs256,
            (Id::EC, Nid::SHA256) => AlgorithmType::Es256,
            _ => panic!("Invalid algorithm type"),
        }
    }
}

impl SigningAlgorithm for PKeyWithDigest<Private> {
    fn algorithm_type(&self) -> AlgorithmType {
        PKeyWithDigest::algorithm_type(self)
    }

    fn sign(&self, header: &str, claims: &str) -> Result<String, Error> {
        let mut signer = Signer::new(self.digest.clone(), &self.key)?;
        signer.update(header.as_bytes())?;
        signer.update(SEPARATOR.as_bytes())?;
        signer.update(claims.as_bytes())?;
        let signer_signature = signer.sign_to_vec()?;

        let signature = if self.key.id() == Id::EC {
            der_to_jose(&signer_signature)?
        } else {
            signer_signature
        };

        Ok(base64::encode_config(&signature, base64::URL_SAFE_NO_PAD))
    }
}

impl VerifyingAlgorithm for PKeyWithDigest<Public> {
    fn algorithm_type(&self) -> AlgorithmType {
        PKeyWithDigest::algorithm_type(self)
    }

    fn verify_bytes(&self, header: &str, claims: &str, signature: &[u8]) -> Result<bool, Error> {
        let mut verifier = Verifier::new(self.digest.clone(), &self.key)?;
        verifier.update(header.as_bytes())?;
        verifier.update(SEPARATOR.as_bytes())?;
        verifier.update(claims.as_bytes())?;

        let verified = if self.key.id() == Id::EC {
            let der = jose_to_der(signature)?;
            verifier.verify(&der)?
        } else {
            verifier.verify(signature)?
        };

        Ok(verified)
    }
}

/// OpenSSL by default signs ECDSA in DER, but JOSE expects them in a concatenated (R, S) format
fn der_to_jose(der: &[u8]) -> Result<Vec<u8>, Error> {
    let signature = EcdsaSig::from_der(&der)?;
    let r = signature.r().to_vec();
    let s = signature.s().to_vec();
    Ok([r, s].concat())
}

/// OpenSSL by default verifies ECDSA in DER, but JOSE parses out a concatenated (R, S) format
fn jose_to_der(jose: &[u8]) -> Result<Vec<u8>, Error> {
    let (r, s) = jose.split_at(jose.len() / 2);
    let ecdsa_signature =
        EcdsaSig::from_private_components(BigNum::from_slice(r)?, BigNum::from_slice(s)?)?;
    Ok(ecdsa_signature.to_der()?)
}

#[cfg(test)]
mod tests {
    use crate::algorithm::openssl::PKeyWithDigest;
    use crate::algorithm::{SigningAlgorithm, VerifyingAlgorithm};
    use openssl::hash::MessageDigest;
    use openssl::pkey::PKey;

    // {"alg":"RS256","typ":"JWT"}
    const RS256_HEADER: &'static str = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9";
    // {"alg":"ES256","typ":"JWT"}
    const ES256_HEADER: &'static str = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9";
    // {"sub":"1234567890","name":"John Doe","admin":true}
    const CLAIMS: &'static str =
        "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9";

    const RS256_SIGNATURE: &'static str =
    "EkN-DOsnsuRjRO6BxXemmJDm3HbxrbRzXglbN2S4sOkopdU4IsDxTI8jO19W_A4K8ZPJijNLis4EZsHeY559a4DFOd50_OqgHGuERTqYZyuhtF39y\
    xJPAjUESwxk2J5k_4zM3O-vtd1Ghyo4IbqKKSy6J9mTniYJPenn5-HIirE";

    #[test]
    fn rs256_sign() {
        let pem = include_bytes!("../../test/rs256-private.pem");

        let algorithm = PKeyWithDigest {
            digest: MessageDigest::sha256(),
            key: PKey::private_key_from_pem(pem).unwrap(),
        };

        let result = algorithm.sign(RS256_HEADER, CLAIMS).unwrap();
        assert_eq!(result, RS256_SIGNATURE);
    }

    #[test]
    fn rs256_verify() {
        let pem = include_bytes!("../../test/rs256-public.pem");

        let algorithm = PKeyWithDigest {
            digest: MessageDigest::sha256(),
            key: PKey::public_key_from_pem(pem).unwrap(),
        };

        assert!(algorithm
            .verify(RS256_HEADER, CLAIMS, RS256_SIGNATURE)
            .unwrap_or(false));
    }

    #[test]
    fn es256() {
        let private_pem = include_bytes!("../../test/es256-private.pem");
        let private_key = PKeyWithDigest {
            digest: MessageDigest::sha256(),
            key: PKey::private_key_from_pem(private_pem).unwrap(),
        };

        let signature = private_key.sign(ES256_HEADER, CLAIMS).unwrap();

        let public_pem = include_bytes!("../../test/es256-public.pem");

        let public_key = PKeyWithDigest {
            digest: MessageDigest::sha256(),
            key: PKey::public_key_from_pem(public_pem).unwrap(),
        };

        assert!(public_key
            .verify(ES256_HEADER, CLAIMS, &*signature)
            .unwrap_or(false));
    }
}
<|endoftext|>


<commit_before>//! Combine queries using a combinator like `UNION`, `INTERSECT` or `EXPECT`
//! with or without `ALL` rule for duplicates

use crate::backend::Backend;
use crate::expression::NonAggregate;
use crate::query_builder::insert_statement::InsertFromSelect;
use crate::query_builder::{AstPass, Query, QueryFragment, QueryId};
use crate::{Insertable, QueryResult, RunQueryDsl, Table};

#[derive(Debug, Clone, Copy, QueryId)]
pub struct NoCombinationClause;

impl<DB: Backend> QueryFragment<DB> for NoCombinationClause {
    fn walk_ast(&self, _: AstPass<DB>) -> QueryResult<()> {
        Ok(())
    }
}

#[derive(Debug, Copy, Clone, QueryId)]
#[must_use = "Queries are only executed when calling `load`, `get_result` or similar."]
/// Combine queries using a combinator like `UNION`, `INTERSECT` or `EXPECT`
/// with or without `ALL` rule for duplicates
pub struct CombinationClause<Combinator, Rule, Source, Rhs> {
    combinator: Combinator,
    duplicate_rule: Rule,
    source: Source,
    rhs: Rhs,
}

impl<Combinator, Rule, Source, Rhs> CombinationClause<Combinator, Rule, Source, Rhs> {
    /// Create a new combination
    pub(crate) fn new(
        combinator: Combinator,
        duplicate_rule: Rule,
        source: Source,
        rhs: Rhs,
    ) -> Self {
        CombinationClause {
            combinator,
            duplicate_rule,
            source,
            rhs,
        }
    }
}

impl<Combinator, Rule, Source, Rhs> Query for CombinationClause<Combinator, Rule, Source, Rhs>
where
    Source: Query,
    Rhs: Query<SqlType = Source::SqlType>,
{
    type SqlType = Source::SqlType;
}

impl<Combinator, Rule, Source, Rhs, Conn> RunQueryDsl<Conn>
    for CombinationClause<Combinator, Rule, Source, Rhs>
{
}

impl<Combinator, Rule, Source, Rhs, T> Insertable<T>
    for CombinationClause<Combinator, Rule, Source, Rhs>
where
    T: Table,
    T::AllColumns: NonAggregate,
    Self: Query,
{
    type Values = InsertFromSelect<Self, T::AllColumns>;

    fn values(self) -> Self::Values {
        InsertFromSelect::new(self)
    }
}

#[derive(Debug, Copy, Clone, QueryId)]
/// Computes the set union of the rows returned by the involved `SELECT` statements using SQL `UNION`
pub struct Union;

impl<DB: Backend> QueryFragment<DB> for Union {
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.push_sql(" UNION ");
        Ok(())
    }
}

#[derive(Debug, Copy, Clone, QueryId)]
/// Computes the set intersection of the rows returned by the involved `SELECT` statements using SQL `INTERSECT`
pub struct Intersect;
impl<DB: Backend> QueryFragment<DB> for Intersect {
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.push_sql(" INTERSECT ");
        Ok(())
    }
}

#[derive(Debug, Copy, Clone, QueryId)]
/// Computes the set difference of the rows returned by the involved `SELECT` statements using SQL `EXCEPT`
pub struct Except;
impl<DB: Backend> QueryFragment<DB> for Except {
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.push_sql(" EXCEPT ");
        Ok(())
    }
}

#[derive(Debug, Copy, Clone, QueryId)]
/// Remove duplicate rows in the result, this is the default behavior of `UNION`, `INTERSECT` and `EXCEPT`
pub struct Distinct;
impl<DB: Backend> QueryFragment<DB> for Distinct {
    fn walk_ast(&self, _out: AstPass<DB>) -> QueryResult<()> {
        Ok(())
    }
}

#[derive(Debug, Copy, Clone, QueryId)]
/// Keep duplicate rows in the result
pub struct All;
impl<DB: Backend> QueryFragment<DB> for All {
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.push_sql("ALL ");
        Ok(())
    }
}

/// Marker trait used to indicate whenever the combination is supported by given backend
pub trait CombinationSupportedBy<DB> {}

impl<Source, Rhs, DB> CombinationSupportedBy<DB>
    for CombinationClause<Union, Distinct, Source, Rhs>
{
}
impl<Source, Rhs, DB> CombinationSupportedBy<DB> for CombinationClause<Union, All, Source, Rhs> {}

#[cfg(feature = "postgres")]
mod postgres {
    use super::*;
    use crate::pg::Pg;
    use crate::query_builder::{AstPass, QueryFragment};
    use crate::QueryResult;

    impl<Source, Rhs> CombinationSupportedBy<Pg>
        for CombinationClause<Intersect, Distinct, Source, Rhs>
    {
    }
    impl<Source, Rhs> CombinationSupportedBy<Pg> for CombinationClause<Intersect, All, Source, Rhs> {}
    impl<Source, Rhs> CombinationSupportedBy<Pg> for CombinationClause<Except, Distinct, Source, Rhs> {}
    impl<Source, Rhs> CombinationSupportedBy<Pg> for CombinationClause<Except, All, Source, Rhs> {}

    impl<Combinator, Rule, Source, Rhs> QueryFragment<Pg>
        for CombinationClause<Combinator, Rule, Source, Rhs>
    where
        Combinator: QueryFragment<Pg>,
        Rule: QueryFragment<Pg>,
        Source: QueryFragment<Pg>,
        Rhs: QueryFragment<Pg>,
        Self: CombinationSupportedBy<Pg>,
    {
        fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> {
            self.source.walk_ast(out.reborrow())?;
            self.combinator.walk_ast(out.reborrow())?;
            self.duplicate_rule.walk_ast(out.reborrow())?;
            out.push_sql("(");
            self.rhs.walk_ast(out.reborrow())?;
            out.push_sql(")");
            Ok(())
        }
    }
}

#[cfg(feature = "mysql")]
mod mysql {
    use super::*;
    use crate::mysql::Mysql;
    use crate::query_builder::{AstPass, QueryFragment};
    use crate::QueryResult;

    impl<Combinator, Rule, Source, Rhs> QueryFragment<Mysql>
        for CombinationClause<Combinator, Rule, Source, Rhs>
    where
        Combinator: QueryFragment<Mysql>,
        Rule: QueryFragment<Mysql>,
        Source: QueryFragment<Mysql>,
        Rhs: QueryFragment<Mysql>,
        Self: CombinationSupportedBy<Mysql>,
    {
        fn walk_ast(&self, mut out: AstPass<Mysql>) -> QueryResult<()> {
            self.source.walk_ast(out.reborrow())?;
            self.combinator.walk_ast(out.reborrow())?;
            self.duplicate_rule.walk_ast(out.reborrow())?;
            out.push_sql("(");
            self.rhs.walk_ast(out.reborrow())?;
            out.push_sql(")");
            Ok(())
        }
    }
}

#[cfg(feature = "sqlite")]
mod sqlite {
    use super::*;
    use crate::query_builder::{AstPass, QueryFragment};
    use crate::sqlite::Sqlite;
    use crate::QueryResult;

    impl<Source, Rhs> CombinationSupportedBy<Sqlite>
        for CombinationClause<Intersect, Distinct, Source, Rhs>
    {
    }
    impl<Source, Rhs> CombinationSupportedBy<Sqlite>
        for CombinationClause<Except, Distinct, Source, Rhs>
    {
    }

    impl<Combinator, Rule, Source, Rhs> QueryFragment<Sqlite>
        for CombinationClause<Combinator, Rule, Source, Rhs>
    where
        Combinator: QueryFragment<Sqlite>,
        Rule: QueryFragment<Sqlite>,
        Source: QueryFragment<Sqlite>,
        Rhs: QueryFragment<Sqlite>,
        Self: CombinationSupportedBy<Sqlite>,
    {
        fn walk_ast(&self, mut out: AstPass<Sqlite>) -> QueryResult<()> {
            self.source.walk_ast(out.reborrow())?;
            self.combinator.walk_ast(out.reborrow())?;
            self.duplicate_rule.walk_ast(out.reborrow())?;
            self.rhs.walk_ast(out.reborrow())?;
            Ok(())
        }
    }
}
<commit_msg>Apply suggestions from code review<commit_after>//! Combine queries using a combinator like `UNION`, `INTERSECT` or `EXPECT`
//! with or without `ALL` rule for duplicates

use crate::backend::Backend;
use crate::expression::NonAggregate;
use crate::query_builder::insert_statement::InsertFromSelect;
use crate::query_builder::{AstPass, Query, QueryFragment, QueryId};
use crate::{Insertable, QueryResult, RunQueryDsl, Table};

#[derive(Debug, Clone, Copy, QueryId)]
pub struct NoCombinationClause;

impl<DB: Backend> QueryFragment<DB> for NoCombinationClause {
    fn walk_ast(&self, _: AstPass<DB>) -> QueryResult<()> {
        Ok(())
    }
}

#[derive(Debug, Copy, Clone, QueryId)]
#[must_use = "Queries are only executed when calling `load`, `get_result` or similar."]
/// Combine queries using a combinator like `UNION`, `INTERSECT` or `EXPECT`
/// with or without `ALL` rule for duplicates
pub struct CombinationClause<Combinator, Rule, Source, Rhs> {
    combinator: Combinator,
    duplicate_rule: Rule,
    source: Source,
    rhs: Rhs,
}

impl<Combinator, Rule, Source, Rhs> CombinationClause<Combinator, Rule, Source, Rhs> {
    /// Create a new combination
    pub(crate) fn new(
        combinator: Combinator,
        duplicate_rule: Rule,
        source: Source,
        rhs: Rhs,
    ) -> Self {
        CombinationClause {
            combinator,
            duplicate_rule,
            source,
            rhs,
        }
    }
}

impl<Combinator, Rule, Source, Rhs> Query for CombinationClause<Combinator, Rule, Source, Rhs>
where
    Source: Query,
    Rhs: Query<SqlType = Source::SqlType>,
{
    type SqlType = Source::SqlType;
}

impl<Combinator, Rule, Source, Rhs, Conn> RunQueryDsl<Conn>
    for CombinationClause<Combinator, Rule, Source, Rhs>
{
}

impl<Combinator, Rule, Source, Rhs, T> Insertable<T>
    for CombinationClause<Combinator, Rule, Source, Rhs>
where
    T: Table,
    T::AllColumns: NonAggregate,
    Self: Query,
{
    type Values = InsertFromSelect<Self, T::AllColumns>;

    fn values(self) -> Self::Values {
        InsertFromSelect::new(self)
    }
}

#[derive(Debug, Copy, Clone, QueryId)]
/// Computes the set union of the rows returned by the involved `SELECT` statements using SQL `UNION`
pub struct Union;

impl<DB: Backend> QueryFragment<DB> for Union {
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.push_sql(" UNION ");
        Ok(())
    }
}

#[derive(Debug, Copy, Clone, QueryId)]
/// Computes the set intersection of the rows returned by the involved `SELECT` statements using SQL `INTERSECT`
pub struct Intersect;

impl<DB: Backend> QueryFragment<DB> for Intersect {
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.push_sql(" INTERSECT ");
        Ok(())
    }
}

#[derive(Debug, Copy, Clone, QueryId)]
/// Computes the set difference of the rows returned by the involved `SELECT` statements using SQL `EXCEPT`
pub struct Except;

impl<DB: Backend> QueryFragment<DB> for Except {
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.push_sql(" EXCEPT ");
        Ok(())
    }
}

#[derive(Debug, Copy, Clone, QueryId)]
/// Remove duplicate rows in the result, this is the default behavior of `UNION`, `INTERSECT` and `EXCEPT`
pub struct Distinct;

impl<DB: Backend> QueryFragment<DB> for Distinct {
    fn walk_ast(&self, _out: AstPass<DB>) -> QueryResult<()> {
        Ok(())
    }
}

#[derive(Debug, Copy, Clone, QueryId)]
/// Keep duplicate rows in the result
pub struct All;

impl<DB: Backend> QueryFragment<DB> for All {
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.push_sql("ALL ");
        Ok(())
    }
}

/// Marker trait used to indicate whenever the combination is supported by given backend
pub trait CombinationSupportedBy<DB> {}

impl<Source, Rhs, DB> CombinationSupportedBy<DB>
    for CombinationClause<Union, Distinct, Source, Rhs>
{
}
impl<Source, Rhs, DB> CombinationSupportedBy<DB> for CombinationClause<Union, All, Source, Rhs> {}

#[cfg(feature = "postgres")]
mod postgres {
    use super::*;
    use crate::pg::Pg;
    use crate::query_builder::{AstPass, QueryFragment};
    use crate::QueryResult;

    impl<Source, Rhs> CombinationSupportedBy<Pg>
        for CombinationClause<Intersect, Distinct, Source, Rhs>
    {
    }
    impl<Source, Rhs> CombinationSupportedBy<Pg> for CombinationClause<Intersect, All, Source, Rhs> {}
    impl<Source, Rhs> CombinationSupportedBy<Pg> for CombinationClause<Except, Distinct, Source, Rhs> {}
    impl<Source, Rhs> CombinationSupportedBy<Pg> for CombinationClause<Except, All, Source, Rhs> {}

    impl<Combinator, Rule, Source, Rhs> QueryFragment<Pg>
        for CombinationClause<Combinator, Rule, Source, Rhs>
    where
        Combinator: QueryFragment<Pg>,
        Rule: QueryFragment<Pg>,
        Source: QueryFragment<Pg>,
        Rhs: QueryFragment<Pg>,
        Self: CombinationSupportedBy<Pg>,
    {
        fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> {
            self.source.walk_ast(out.reborrow())?;
            self.combinator.walk_ast(out.reborrow())?;
            self.duplicate_rule.walk_ast(out.reborrow())?;
            out.push_sql("(");
            self.rhs.walk_ast(out.reborrow())?;
            out.push_sql(")");
            Ok(())
        }
    }
}

#[cfg(feature = "mysql")]
mod mysql {
    use super::*;
    use crate::mysql::Mysql;
    use crate::query_builder::{AstPass, QueryFragment};
    use crate::QueryResult;

    impl<Combinator, Rule, Source, Rhs> QueryFragment<Mysql>
        for CombinationClause<Combinator, Rule, Source, Rhs>
    where
        Combinator: QueryFragment<Mysql>,
        Rule: QueryFragment<Mysql>,
        Source: QueryFragment<Mysql>,
        Rhs: QueryFragment<Mysql>,
        Self: CombinationSupportedBy<Mysql>,
    {
        fn walk_ast(&self, mut out: AstPass<Mysql>) -> QueryResult<()> {
            self.source.walk_ast(out.reborrow())?;
            self.combinator.walk_ast(out.reborrow())?;
            self.duplicate_rule.walk_ast(out.reborrow())?;
            out.push_sql("(");
            self.rhs.walk_ast(out.reborrow())?;
            out.push_sql(")");
            Ok(())
        }
    }
}

#[cfg(feature = "sqlite")]
mod sqlite {
    use super::*;
    use crate::query_builder::{AstPass, QueryFragment};
    use crate::sqlite::Sqlite;
    use crate::QueryResult;

    impl<Source, Rhs> CombinationSupportedBy<Sqlite>
        for CombinationClause<Intersect, Distinct, Source, Rhs>
    {
    }
    impl<Source, Rhs> CombinationSupportedBy<Sqlite>
        for CombinationClause<Except, Distinct, Source, Rhs>
    {
    }

    impl<Combinator, Rule, Source, Rhs> QueryFragment<Sqlite>
        for CombinationClause<Combinator, Rule, Source, Rhs>
    where
        Combinator: QueryFragment<Sqlite>,
        Rule: QueryFragment<Sqlite>,
        Source: QueryFragment<Sqlite>,
        Rhs: QueryFragment<Sqlite>,
        Self: CombinationSupportedBy<Sqlite>,
    {
        fn walk_ast(&self, mut out: AstPass<Sqlite>) -> QueryResult<()> {
            self.source.walk_ast(out.reborrow())?;
            self.combinator.walk_ast(out.reborrow())?;
            self.duplicate_rule.walk_ast(out.reborrow())?;
            self.rhs.walk_ast(out.reborrow())?;
            Ok(())
        }
    }
}
<|endoftext|>


<commit_before>#![feature(ascii_ctype)]
use std::ascii::AsciiExt;

fn check_countrycode(mut phone: Vec<u8>) -> Option<String> {
    println!("{:?}", phone);

    if phone[0] != b'1' {
        return None;
    }

    String::from_utf8(phone.drain(1..).collect()).ok()
}

pub fn number(phone: &str) -> Option<String> {
    let result = phone
        .chars()
        .filter(|x| x.is_ascii_digit())
        .map(|x| x as u8)
        .collect::<Vec<u8>>();

    match result.len() {
        11 => check_countrycode(result),
        10 => String::from_utf8(result).ok(),
        _ => None,
    }
}

pub fn area_code(phone: &str) -> Option<String> {
    number(phone).map(|r| r[..3].to_string())
}

pub fn pretty_print(phone: &str) -> String {
    let v = number(phone);

    if v.is_none() {
        return "invalid".to_string();
    }

    let r = v.unwrap();

    format!("({}) {}-{}", &r[..3], &r[3..6], &r[6..])
}
<commit_msg>Improve rust code for phone-number<commit_after>#![feature(ascii_ctype)]
use std::ascii::AsciiExt;

pub fn number<S>(phone: S) -> Option<String> where S: Into<String> {
    let result = phone
        .into()
        .chars()
        .filter(|x| x.is_ascii_digit())
        .collect::<String>();

    match result.len() {
        11 if result.starts_with('1') => Some(result[1..].to_string()),
        10 => Some(result),
        _ => None,
    }
}

pub fn area_code<S>(phone: S) -> Option<String> where S: Into<String> {
    number(phone).map(|r| r[..3].to_string())
}

pub fn pretty_print<S>(phone: S) -> String where S: Into<String> {
    number(phone).map_or("invalid".to_string(), |r| {
        format!("({}) {}-{}", &r[..3], &r[3..6], &r[6..])
    })
}
<|endoftext|>


<commit_before>/// Problem 4
///
/// A palindromic number reads the same both ways. The largest palindrome made
/// from the product of two 2-digit numbers is 9009 = 91 × 99.
///
/// Find the largest palindrome made from the product of two 3-digit numbers.
fn main() {
	println!("Problem 4");
	let mut largest: u64 = 0;
	for i in 1..999 {
		for j in 1..999 {
			let n = i*j;
			if is_palindromic(n) {
				if n > largest {
					largest = n;
				}
			}
		}
	}
	println!("{}", largest);
}

fn is_palindromic(num: u64) -> bool {
	let s: String = format!("{}", num);
	let r: String = s.chars().rev().collect();
	return s == r;
}
<commit_msg>Removes `return`<commit_after>/// Problem 4
///
/// A palindromic number reads the same both ways. The largest palindrome made
/// from the product of two 2-digit numbers is 9009 = 91 × 99.
///
/// Find the largest palindrome made from the product of two 3-digit numbers.
fn main() {
	println!("Problem 4");
	let mut largest: u64 = 0;
	for i in 1..999 {
		for j in 1..999 {
			let n = i*j;
			if is_palindromic(n) {
				if n > largest {
					largest = n;
				}
			}
		}
	}
	println!("{}", largest);
}

fn is_palindromic(num: u64) -> bool {
	let s: String = format!("{}", num);
	let r: String = s.chars().rev().collect();
	s == r
}
<|endoftext|>


<commit_before>extern crate glium;
#[macro_use]
extern crate korome;

use korome::{Game, Draw, GameLogic, LogicArgs, RenderArgs, Vector2};
use korome::draw::{Drawable, Texture};

fn main() {
    let draw = Draw::new("glium works!", 800, 600);

    let planet = draw.load_texture_from_bytes(include_bytes!("planet.png"), 64, 64).unwrap();

    let mut logic = Logic::new();

    logic.add_object(Object::new(&planet, (-400., 300.), 0.));

    let game = Game::new(logic, draw);

    game.run_until_closed();
}

struct Object<'a>{
    pos: Vector2,
    theta: f32,
    tex: &'a Texture
}

impl<'a> Object<'a>{
    fn new<V: Into<Vector2>>(tex: &'a Texture, pos: V, theta: f32) -> Self{
        Object{
            tex: tex,
            pos: pos.into(),
            theta: theta,
        }
    }
}

impl<'a> Drawable for Object<'a>{
    fn get_pos(&self) -> (f32, f32){
        self.pos.get_x_y()
    }

    fn get_rotation(&self) -> f32{
        self.theta
    }

    fn get_texture(&self) -> &Texture{
        self.tex
    }
}

struct Logic<'a> {
    objects: Vec<Object<'a>>,
}

impl<'a> Logic<'a>{
    pub fn new() -> Self{
        Logic{
            objects: Vec::new(),
        }
    }

    pub fn add_object(&mut self, obj: Object<'a>){
        self.objects.push(obj)
    }
}

impl<'a> GameLogic for Logic<'a> {
    fn logic (&mut self, l_args: LogicArgs){
        let ref mut planet = self.objects[0];

        let delta = l_args.delta() as f32;

        let vel = 200.0 * delta;
        let pos = &mut planet.pos;
        // (17, 30, 31, 32) == (W, A, S, D)
        is_down!{
            l_args;

            75, 30 => {
                pos.x -= vel
            },
            77, 32 => {
                pos.x += vel
            },
            80, 31 => {
                pos.y -= vel
            },
            72, 17 => {
                pos.y += vel
            },
            18 => {
                planet.theta += delta
            },
            16 => {
                planet.theta -= delta
            }
        }

        for &(b, k) in l_args.keyevents(){
            if !b {println!("{}", k)}
        }
    }

    fn render(&self, mut r_args: RenderArgs){
        //.rotate() doesn't actually work properly right now
        r_args.draw_drawables()
            .append(&self.objects)
            .draw()
            .unwrap_or_else(|e| panic!("{}", e))
    }
}
<commit_msg>Fix example<commit_after>extern crate glium;
#[macro_use]
extern crate korome;

use korome::{Game, Draw, GameLogic, LogicArgs, RenderArgs, Vector2};
use korome::draw::{Drawable, Texture};

fn main() {
    let draw = Draw::new("glium works!", 800, 600);

    let planet = draw.load_texture_from_bytes(include_bytes!("planet.png"), 64, 64).unwrap();

    let mut logic = Logic::new();

    logic.add_object(Object::new(&planet, (-400., 300.), 0.));

    let game = Game::new(logic, draw);

    game.run_until_closed();
}

struct Object<'a>{
    pos: Vector2,
    theta: f32,
    tex: &'a Texture
}

impl<'a> Object<'a>{
    fn new<V: Into<Vector2>>(tex: &'a Texture, pos: V, theta: f32) -> Self{
        Object{
            tex: tex,
            pos: pos.into(),
            theta: theta,
        }
    }
}

impl<'a> Drawable for Object<'a>{
    fn get_pos(&self) -> (f32, f32){
        self.pos.get_x_y()
    }

    fn get_rotation(&self) -> f32{
        self.theta
    }

    fn get_texture(&self) -> &Texture{
        self.tex
    }
}

struct Logic<'a> {
    objects: Vec<Object<'a>>,
}

impl<'a> Logic<'a>{
    pub fn new() -> Self{
        Logic{
            objects: Vec::new(),
        }
    }

    pub fn add_object(&mut self, obj: Object<'a>){
        self.objects.push(obj)
    }
}

impl<'a> GameLogic for Logic<'a> {
    fn logic (&mut self, l_args: LogicArgs){
        let ref mut planet = self.objects[0];

        let delta = l_args.delta() as f32;

        let vel = 200.0 * delta;
        let pos = &mut planet.pos;
        // (17, 30, 31, 32) == (W, A, S, D)
        is_down!{
            l_args;

            75, 30 => {
                pos.x -= vel
            },
            77, 32 => {
                pos.x += vel
            },
            80, 31 => {
                pos.y -= vel
            },
            72, 17 => {
                pos.y += vel
            },
            18 => {
                planet.theta += delta
            },
            16 => {
                planet.theta -= delta
            }
        }

        for &(b, k) in l_args.keyevents(){
            if !b {println!("{}", k)}
        }
    }

    fn render(&self, mut r_args: RenderArgs){
        //.rotate() doesn't actually work properly right now
        r_args.draw_drawables()
            .add_vec(&self.objects)
            .draw()
            .unwrap_or_else(|e| panic!("{}", e))
    }
}
<|endoftext|>