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

// For lazy_static
#![allow(unsafe_code)]

use dom::TElement;
use element_state::*;
use error_reporting::{ParseErrorReporter, StdoutErrorReporter};
use media_queries::{Device, MediaType};
use properties::{PropertyDeclaration, PropertyDeclarationBlock};
use restyle_hints::{ElementSnapshot, RestyleHint, DependencySet};
use selector_impl::{SelectorImplExt, ServoSelectorImpl};
use selectors::Element;
use selectors::bloom::BloomFilter;
use selectors::matching::DeclarationBlock as GenericDeclarationBlock;
use selectors::matching::{Rule, SelectorMap};
use selectors::parser::SelectorImpl;
use smallvec::VecLike;
use std::collections::HashMap;
use std::hash::BuildHasherDefault;
use std::process;
use std::sync::Arc;
use style_traits::viewport::ViewportConstraints;
use stylesheets::{CSSRuleIteratorExt, Origin, Stylesheet};
use url::Url;
use util::opts;
use util::resource_files::read_resource_file;
use viewport::{MaybeNew, ViewportRuleCascade};

pub type DeclarationBlock = GenericDeclarationBlock<Vec<PropertyDeclaration>>;

lazy_static! {
    pub static ref USER_OR_USER_AGENT_STYLESHEETS: Vec<Stylesheet<ServoSelectorImpl>> = {
        let mut stylesheets = vec!();
        // FIXME: presentational-hints.css should be at author origin with zero specificity.
        //        (Does it make a difference?)
        for &filename in &["user-agent.css", "servo.css", "presentational-hints.css"] {
            match read_resource_file(&[filename]) {
                Ok(res) => {
                    let ua_stylesheet = Stylesheet::from_bytes(
                        &res,
                        Url::parse(&format!("chrome:///{:?}", filename)).unwrap(),
                        None,
                        None,
                        Origin::UserAgent,
                        box StdoutErrorReporter);
                    stylesheets.push(ua_stylesheet);
                }
                Err(..) => {
                    error!("Failed to load UA stylesheet {}!", filename);
                    process::exit(1);
                }
            }
        }
        for &(ref contents, ref url) in &opts::get().user_stylesheets {
            stylesheets.push(Stylesheet::from_bytes(
                &contents, url.clone(), None, None, Origin::User, box StdoutErrorReporter));
        }
        stylesheets
    };
}

lazy_static! {
    pub static ref QUIRKS_MODE_STYLESHEET: Stylesheet<ServoSelectorImpl> = {
        match read_resource_file(&["quirks-mode.css"]) {
            Ok(res) => {
                Stylesheet::from_bytes(
                    &res,
                    url!("chrome:///quirks-mode.css"),
                    None,
                    None,
                    Origin::UserAgent,
                    box StdoutErrorReporter)
            },
            Err(..) => {
                error!("Stylist failed to load 'quirks-mode.css'!");
                process::exit(1);
            }
        }
    };
}

pub struct Stylist<Impl: SelectorImplExt> {
    // Device that the stylist is currently evaluating against.
    pub device: Device,

    // Viewport constraints based on the current device.
    viewport_constraints: Option<ViewportConstraints>,

    // If true, the quirks-mode stylesheet is applied.
    quirks_mode: bool,

    // If true, the device has changed, and the stylist needs to be updated.
    is_device_dirty: bool,

    // The current selector maps, after evaluating media
    // rules against the current device.
    element_map: PerPseudoElementSelectorMap<Impl>,
    pseudos_map: HashMap<Impl::PseudoElement, PerPseudoElementSelectorMap<Impl>, BuildHasherDefault<::fnv::FnvHasher>>,
    rules_source_order: usize,

    // Selector dependencies used to compute restyle hints.
    state_deps: DependencySet<Impl>,
}

impl<Impl: SelectorImplExt> Stylist<Impl> {
    #[inline]
    pub fn new(device: Device) -> Stylist<Impl> {
        let mut stylist = Stylist {
            viewport_constraints: None,
            device: device,
            is_device_dirty: true,
            quirks_mode: false,

            element_map: PerPseudoElementSelectorMap::new(),
            pseudos_map: HashMap::with_hasher(Default::default()),
            rules_source_order: 0,
            state_deps: DependencySet::new(),
        };

        Impl::each_eagerly_cascaded_pseudo_element(|pseudo| {
            stylist.pseudos_map.insert(pseudo, PerPseudoElementSelectorMap::new());
        });

        // FIXME: Add iso-8859-9.css when the document’s encoding is ISO-8859-8.

        stylist
    }

    pub fn update(&mut self, doc_stylesheets: &[Arc<Stylesheet<Impl>>],
                  stylesheets_changed: bool) -> bool
                  where Impl: 'static {
        if !(self.is_device_dirty || stylesheets_changed) {
            return false;
        }
        self.element_map = PerPseudoElementSelectorMap::new();
        self.pseudos_map = HashMap::with_hasher(Default::default());
        self.rules_source_order = 0;
        self.state_deps.clear();

        for ref stylesheet in Impl::get_user_or_user_agent_stylesheets().iter() {
            self.add_stylesheet(&stylesheet);
        }

        if self.quirks_mode {
            self.add_stylesheet(&Impl::get_quirks_mode_stylesheet());
        }

        for ref stylesheet in doc_stylesheets.iter() {
            self.add_stylesheet(stylesheet);
        }

        self.is_device_dirty = false;
        true
    }

    fn add_stylesheet(&mut self, stylesheet: &Stylesheet<Impl>) {
        let device = &self.device;
        if !stylesheet.is_effective_for_device(device) {
            return;
        }

        let mut rules_source_order = self.rules_source_order;

        // Take apart the StyleRule into individual Rules and insert
        // them into the SelectorMap of that priority.
        macro_rules! append(
            ($style_rule: ident, $priority: ident) => {
                if $style_rule.declarations.$priority.len() > 0 {
                    for selector in &$style_rule.selectors {
                        let map = if let Some(ref pseudo) = selector.pseudo_element {
                            self.pseudos_map.entry(pseudo.clone())
                                            .or_insert_with(PerPseudoElementSelectorMap::new)
                                            .borrow_for_origin(&stylesheet.origin)
                        } else {
                            self.element_map.borrow_for_origin(&stylesheet.origin)
                        };

                        map.$priority.insert(Rule {
                                selector: selector.compound_selectors.clone(),
                                declarations: DeclarationBlock {
                                    specificity: selector.specificity,
                                    declarations: $style_rule.declarations.$priority.clone(),
                                    source_order: rules_source_order,
                                },
                        });
                    }
                }
            };
        );

        for style_rule in stylesheet.effective_rules(&self.device).style() {
            append!(style_rule, normal);
            append!(style_rule, important);
            rules_source_order += 1;
            for selector in &style_rule.selectors {
                self.state_deps.note_selector(selector.compound_selectors.clone());
            }
        }
        self.rules_source_order = rules_source_order;
    }

    pub fn compute_restyle_hint<E>(&self, element: &E,
                                   snapshot: &ElementSnapshot,
                                   // NB: We need to pass current_state as an argument because
                                   // selectors::Element doesn't provide access to ElementState
                                   // directly, and computing it from the ElementState would be
                                   // more expensive than getting it directly from the caller.
                                   current_state: ElementState)
                                   -> RestyleHint
                                   where E: Element<Impl=Impl> + Clone {
        self.state_deps.compute_hint(element, snapshot, current_state)
    }

    pub fn set_device(&mut self, mut device: Device, stylesheets: &[Arc<Stylesheet<Impl>>]) {
        let cascaded_rule = stylesheets.iter()
            .flat_map(|s| s.effective_rules(&self.device).viewport())
            .cascade();

        self.viewport_constraints = ViewportConstraints::maybe_new(self.device.viewport_size, &cascaded_rule);
        if let Some(ref constraints) = self.viewport_constraints {
            device = Device::new(MediaType::Screen, constraints.size);
        }
        let is_device_dirty = self.is_device_dirty || stylesheets.iter()
            .flat_map(|stylesheet| stylesheet.rules().media())
            .any(|media_rule| media_rule.evaluate(&self.device) != media_rule.evaluate(&device));

        self.device = device;
        self.is_device_dirty |= is_device_dirty;
    }

    pub fn viewport_constraints(&self) -> &Option<ViewportConstraints> {
        &self.viewport_constraints
    }

    pub fn set_quirks_mode(&mut self, enabled: bool) {
        self.quirks_mode = enabled;
    }

    /// Returns the applicable CSS declarations for the given element. This corresponds to
    /// `ElementRuleCollector` in WebKit.
    ///
    /// The returned boolean indicates whether the style is *shareable*; that is, whether the
    /// matched selectors are simple enough to allow the matching logic to be reduced to the logic
    /// in `css::matching::PrivateMatchMethods::candidate_element_allows_for_style_sharing`.
    pub fn push_applicable_declarations<'le, E, V>(
                                        &self,
                                        element: &E,
                                        parent_bf: Option<&BloomFilter>,
                                        style_attribute: Option<&PropertyDeclarationBlock>,
                                        pseudo_element: Option<Impl::PseudoElement>,
                                        applicable_declarations: &mut V)
                                        -> bool
                                        where E: Element<Impl=Impl> + TElement<'le>,
                                              V: VecLike<DeclarationBlock> {
        assert!(!self.is_device_dirty);
        assert!(style_attribute.is_none() || pseudo_element.is_none(),
                "Style attributes do not apply to pseudo-elements");

        let map = match pseudo_element {
            Some(ref pseudo) => self.pseudos_map.get(pseudo).unwrap(),
            None => &self.element_map,
        };

        let mut shareable = true;

        // Step 1: Normal user-agent rules.
        map.user_agent.normal.get_all_matching_rules(element,
                                                     parent_bf,
                                                     applicable_declarations,
                                                     &mut shareable);

        // Step 2: Presentational hints.
        let length = applicable_declarations.len();
        element.synthesize_presentational_hints_for_legacy_attributes(applicable_declarations);
        if applicable_declarations.len() != length {
            // Never share style for elements with preshints
            shareable = false;
        }

        // Step 3: User and author normal rules.
        map.user.normal.get_all_matching_rules(element,
                                               parent_bf,
                                               applicable_declarations,
                                               &mut shareable);
        map.author.normal.get_all_matching_rules(element,
                                                 parent_bf,
                                                 applicable_declarations,
                                                 &mut shareable);

        // Step 4: Normal style attributes.
        style_attribute.map(|sa| {
            shareable = false;
            applicable_declarations.push(
                GenericDeclarationBlock::from_declarations(sa.normal.clone()))
        });

        // Step 5: Author-supplied `!important` rules.
        map.author.important.get_all_matching_rules(element,
                                                    parent_bf,
                                                    applicable_declarations,
                                                    &mut shareable);

        // Step 6: `!important` style attributes.
        style_attribute.map(|sa| {
            shareable = false;
            applicable_declarations.push(
                GenericDeclarationBlock::from_declarations(sa.important.clone()))
        });

        // Step 7: User and UA `!important` rules.
        map.user.important.get_all_matching_rules(element,
                                                  parent_bf,
                                                  applicable_declarations,
                                                  &mut shareable);
        map.user_agent.important.get_all_matching_rules(element,
                                                        parent_bf,
                                                        applicable_declarations,
                                                        &mut shareable);

        shareable
    }

    pub fn is_device_dirty(&self) -> bool {
        self.is_device_dirty
    }
}

struct PerOriginSelectorMap<Impl: SelectorImpl> {
    normal: SelectorMap<Vec<PropertyDeclaration>, Impl>,
    important: SelectorMap<Vec<PropertyDeclaration>, Impl>,
}

impl<Impl: SelectorImpl> PerOriginSelectorMap<Impl> {
    #[inline]
    fn new() -> PerOriginSelectorMap<Impl> {
        PerOriginSelectorMap {
            normal: SelectorMap::new(),
            important: SelectorMap::new(),
        }
    }
}

struct PerPseudoElementSelectorMap<Impl: SelectorImpl> {
    user_agent: PerOriginSelectorMap<Impl>,
    author: PerOriginSelectorMap<Impl>,
    user: PerOriginSelectorMap<Impl>,
}

impl<Impl: SelectorImpl> PerPseudoElementSelectorMap<Impl> {
    #[inline]
    fn new() -> PerPseudoElementSelectorMap<Impl> {
        PerPseudoElementSelectorMap {
            user_agent: PerOriginSelectorMap::new(),
            author: PerOriginSelectorMap::new(),
            user: PerOriginSelectorMap::new(),
        }
    }

    #[inline]
    fn borrow_for_origin(&mut self, origin: &Origin) -> &mut PerOriginSelectorMap<Impl> {
        match *origin {
            Origin::UserAgent => &mut self.user_agent,
            Origin::Author => &mut self.author,
            Origin::User => &mut self.user,
        }
    }
}
<commit_msg>style: Prevent a crash when push_applicable_declarations is called with a non eagerly-cascaded pseudo-element<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/. */

// For lazy_static
#![allow(unsafe_code)]

use dom::TElement;
use element_state::*;
use error_reporting::{ParseErrorReporter, StdoutErrorReporter};
use media_queries::{Device, MediaType};
use properties::{PropertyDeclaration, PropertyDeclarationBlock};
use restyle_hints::{ElementSnapshot, RestyleHint, DependencySet};
use selector_impl::{SelectorImplExt, ServoSelectorImpl};
use selectors::Element;
use selectors::bloom::BloomFilter;
use selectors::matching::DeclarationBlock as GenericDeclarationBlock;
use selectors::matching::{Rule, SelectorMap};
use selectors::parser::SelectorImpl;
use smallvec::VecLike;
use std::collections::HashMap;
use std::hash::BuildHasherDefault;
use std::process;
use std::sync::Arc;
use style_traits::viewport::ViewportConstraints;
use stylesheets::{CSSRuleIteratorExt, Origin, Stylesheet};
use url::Url;
use util::opts;
use util::resource_files::read_resource_file;
use viewport::{MaybeNew, ViewportRuleCascade};

pub type DeclarationBlock = GenericDeclarationBlock<Vec<PropertyDeclaration>>;

lazy_static! {
    pub static ref USER_OR_USER_AGENT_STYLESHEETS: Vec<Stylesheet<ServoSelectorImpl>> = {
        let mut stylesheets = vec!();
        // FIXME: presentational-hints.css should be at author origin with zero specificity.
        //        (Does it make a difference?)
        for &filename in &["user-agent.css", "servo.css", "presentational-hints.css"] {
            match read_resource_file(&[filename]) {
                Ok(res) => {
                    let ua_stylesheet = Stylesheet::from_bytes(
                        &res,
                        Url::parse(&format!("chrome:///{:?}", filename)).unwrap(),
                        None,
                        None,
                        Origin::UserAgent,
                        box StdoutErrorReporter);
                    stylesheets.push(ua_stylesheet);
                }
                Err(..) => {
                    error!("Failed to load UA stylesheet {}!", filename);
                    process::exit(1);
                }
            }
        }
        for &(ref contents, ref url) in &opts::get().user_stylesheets {
            stylesheets.push(Stylesheet::from_bytes(
                &contents, url.clone(), None, None, Origin::User, box StdoutErrorReporter));
        }
        stylesheets
    };
}

lazy_static! {
    pub static ref QUIRKS_MODE_STYLESHEET: Stylesheet<ServoSelectorImpl> = {
        match read_resource_file(&["quirks-mode.css"]) {
            Ok(res) => {
                Stylesheet::from_bytes(
                    &res,
                    url!("chrome:///quirks-mode.css"),
                    None,
                    None,
                    Origin::UserAgent,
                    box StdoutErrorReporter)
            },
            Err(..) => {
                error!("Stylist failed to load 'quirks-mode.css'!");
                process::exit(1);
            }
        }
    };
}

pub struct Stylist<Impl: SelectorImplExt> {
    // Device that the stylist is currently evaluating against.
    pub device: Device,

    // Viewport constraints based on the current device.
    viewport_constraints: Option<ViewportConstraints>,

    // If true, the quirks-mode stylesheet is applied.
    quirks_mode: bool,

    // If true, the device has changed, and the stylist needs to be updated.
    is_device_dirty: bool,

    // The current selector maps, after evaluating media
    // rules against the current device.
    element_map: PerPseudoElementSelectorMap<Impl>,
    pseudos_map: HashMap<Impl::PseudoElement, PerPseudoElementSelectorMap<Impl>, BuildHasherDefault<::fnv::FnvHasher>>,
    rules_source_order: usize,

    // Selector dependencies used to compute restyle hints.
    state_deps: DependencySet<Impl>,
}

impl<Impl: SelectorImplExt> Stylist<Impl> {
    #[inline]
    pub fn new(device: Device) -> Stylist<Impl> {
        let mut stylist = Stylist {
            viewport_constraints: None,
            device: device,
            is_device_dirty: true,
            quirks_mode: false,

            element_map: PerPseudoElementSelectorMap::new(),
            pseudos_map: HashMap::with_hasher(Default::default()),
            rules_source_order: 0,
            state_deps: DependencySet::new(),
        };

        Impl::each_eagerly_cascaded_pseudo_element(|pseudo| {
            stylist.pseudos_map.insert(pseudo, PerPseudoElementSelectorMap::new());
        });

        // FIXME: Add iso-8859-9.css when the document’s encoding is ISO-8859-8.

        stylist
    }

    pub fn update(&mut self, doc_stylesheets: &[Arc<Stylesheet<Impl>>],
                  stylesheets_changed: bool) -> bool
                  where Impl: 'static {
        if !(self.is_device_dirty || stylesheets_changed) {
            return false;
        }
        self.element_map = PerPseudoElementSelectorMap::new();
        self.pseudos_map = HashMap::with_hasher(Default::default());
        self.rules_source_order = 0;
        self.state_deps.clear();

        for ref stylesheet in Impl::get_user_or_user_agent_stylesheets().iter() {
            self.add_stylesheet(&stylesheet);
        }

        if self.quirks_mode {
            self.add_stylesheet(&Impl::get_quirks_mode_stylesheet());
        }

        for ref stylesheet in doc_stylesheets.iter() {
            self.add_stylesheet(stylesheet);
        }

        self.is_device_dirty = false;
        true
    }

    fn add_stylesheet(&mut self, stylesheet: &Stylesheet<Impl>) {
        let device = &self.device;
        if !stylesheet.is_effective_for_device(device) {
            return;
        }

        let mut rules_source_order = self.rules_source_order;

        // Take apart the StyleRule into individual Rules and insert
        // them into the SelectorMap of that priority.
        macro_rules! append(
            ($style_rule: ident, $priority: ident) => {
                if $style_rule.declarations.$priority.len() > 0 {
                    for selector in &$style_rule.selectors {
                        let map = if let Some(ref pseudo) = selector.pseudo_element {
                            self.pseudos_map.entry(pseudo.clone())
                                            .or_insert_with(PerPseudoElementSelectorMap::new)
                                            .borrow_for_origin(&stylesheet.origin)
                        } else {
                            self.element_map.borrow_for_origin(&stylesheet.origin)
                        };

                        map.$priority.insert(Rule {
                                selector: selector.compound_selectors.clone(),
                                declarations: DeclarationBlock {
                                    specificity: selector.specificity,
                                    declarations: $style_rule.declarations.$priority.clone(),
                                    source_order: rules_source_order,
                                },
                        });
                    }
                }
            };
        );

        for style_rule in stylesheet.effective_rules(&self.device).style() {
            append!(style_rule, normal);
            append!(style_rule, important);
            rules_source_order += 1;
            for selector in &style_rule.selectors {
                self.state_deps.note_selector(selector.compound_selectors.clone());
            }
        }
        self.rules_source_order = rules_source_order;
    }

    pub fn compute_restyle_hint<E>(&self, element: &E,
                                   snapshot: &ElementSnapshot,
                                   // NB: We need to pass current_state as an argument because
                                   // selectors::Element doesn't provide access to ElementState
                                   // directly, and computing it from the ElementState would be
                                   // more expensive than getting it directly from the caller.
                                   current_state: ElementState)
                                   -> RestyleHint
                                   where E: Element<Impl=Impl> + Clone {
        self.state_deps.compute_hint(element, snapshot, current_state)
    }

    pub fn set_device(&mut self, mut device: Device, stylesheets: &[Arc<Stylesheet<Impl>>]) {
        let cascaded_rule = stylesheets.iter()
            .flat_map(|s| s.effective_rules(&self.device).viewport())
            .cascade();

        self.viewport_constraints = ViewportConstraints::maybe_new(self.device.viewport_size, &cascaded_rule);
        if let Some(ref constraints) = self.viewport_constraints {
            device = Device::new(MediaType::Screen, constraints.size);
        }
        let is_device_dirty = self.is_device_dirty || stylesheets.iter()
            .flat_map(|stylesheet| stylesheet.rules().media())
            .any(|media_rule| media_rule.evaluate(&self.device) != media_rule.evaluate(&device));

        self.device = device;
        self.is_device_dirty |= is_device_dirty;
    }

    pub fn viewport_constraints(&self) -> &Option<ViewportConstraints> {
        &self.viewport_constraints
    }

    pub fn set_quirks_mode(&mut self, enabled: bool) {
        self.quirks_mode = enabled;
    }

    /// Returns the applicable CSS declarations for the given element. This corresponds to
    /// `ElementRuleCollector` in WebKit.
    ///
    /// The returned boolean indicates whether the style is *shareable*; that is, whether the
    /// matched selectors are simple enough to allow the matching logic to be reduced to the logic
    /// in `css::matching::PrivateMatchMethods::candidate_element_allows_for_style_sharing`.
    pub fn push_applicable_declarations<'le, E, V>(
                                        &self,
                                        element: &E,
                                        parent_bf: Option<&BloomFilter>,
                                        style_attribute: Option<&PropertyDeclarationBlock>,
                                        pseudo_element: Option<Impl::PseudoElement>,
                                        applicable_declarations: &mut V)
                                        -> bool
                                        where E: Element<Impl=Impl> + TElement<'le>,
                                              V: VecLike<DeclarationBlock> {
        assert!(!self.is_device_dirty);
        assert!(style_attribute.is_none() || pseudo_element.is_none(),
                "Style attributes do not apply to pseudo-elements");

        let map = match pseudo_element {
            Some(ref pseudo) => match self.pseudos_map.get(pseudo) {
                Some(map) => map,
                // TODO(ecoal95): get non eagerly-cascaded pseudo-element rules here.
                // Actually assume there are no rules applicable.
                None => return true,
            },
            None => &self.element_map,
        };

        let mut shareable = true;

        // Step 1: Normal user-agent rules.
        map.user_agent.normal.get_all_matching_rules(element,
                                                     parent_bf,
                                                     applicable_declarations,
                                                     &mut shareable);

        // Step 2: Presentational hints.
        let length = applicable_declarations.len();
        element.synthesize_presentational_hints_for_legacy_attributes(applicable_declarations);
        if applicable_declarations.len() != length {
            // Never share style for elements with preshints
            shareable = false;
        }

        // Step 3: User and author normal rules.
        map.user.normal.get_all_matching_rules(element,
                                               parent_bf,
                                               applicable_declarations,
                                               &mut shareable);
        map.author.normal.get_all_matching_rules(element,
                                                 parent_bf,
                                                 applicable_declarations,
                                                 &mut shareable);

        // Step 4: Normal style attributes.
        style_attribute.map(|sa| {
            shareable = false;
            applicable_declarations.push(
                GenericDeclarationBlock::from_declarations(sa.normal.clone()))
        });

        // Step 5: Author-supplied `!important` rules.
        map.author.important.get_all_matching_rules(element,
                                                    parent_bf,
                                                    applicable_declarations,
                                                    &mut shareable);

        // Step 6: `!important` style attributes.
        style_attribute.map(|sa| {
            shareable = false;
            applicable_declarations.push(
                GenericDeclarationBlock::from_declarations(sa.important.clone()))
        });

        // Step 7: User and UA `!important` rules.
        map.user.important.get_all_matching_rules(element,
                                                  parent_bf,
                                                  applicable_declarations,
                                                  &mut shareable);
        map.user_agent.important.get_all_matching_rules(element,
                                                        parent_bf,
                                                        applicable_declarations,
                                                        &mut shareable);

        shareable
    }

    pub fn is_device_dirty(&self) -> bool {
        self.is_device_dirty
    }
}

struct PerOriginSelectorMap<Impl: SelectorImpl> {
    normal: SelectorMap<Vec<PropertyDeclaration>, Impl>,
    important: SelectorMap<Vec<PropertyDeclaration>, Impl>,
}

impl<Impl: SelectorImpl> PerOriginSelectorMap<Impl> {
    #[inline]
    fn new() -> PerOriginSelectorMap<Impl> {
        PerOriginSelectorMap {
            normal: SelectorMap::new(),
            important: SelectorMap::new(),
        }
    }
}

struct PerPseudoElementSelectorMap<Impl: SelectorImpl> {
    user_agent: PerOriginSelectorMap<Impl>,
    author: PerOriginSelectorMap<Impl>,
    user: PerOriginSelectorMap<Impl>,
}

impl<Impl: SelectorImpl> PerPseudoElementSelectorMap<Impl> {
    #[inline]
    fn new() -> PerPseudoElementSelectorMap<Impl> {
        PerPseudoElementSelectorMap {
            user_agent: PerOriginSelectorMap::new(),
            author: PerOriginSelectorMap::new(),
            user: PerOriginSelectorMap::new(),
        }
    }

    #[inline]
    fn borrow_for_origin(&mut self, origin: &Origin) -> &mut PerOriginSelectorMap<Impl> {
        match *origin {
            Origin::UserAgent => &mut self.user_agent,
            Origin::Author => &mut self.author,
            Origin::User => &mut self.user,
        }
    }
}
<|endoftext|>


<commit_before>use std::{
  net::TcpListener,
  process,
  sync::mpsc,
  thread,
  time::Duration
};
use std::convert::Infallible;
use std::net::{IpAddr, SocketAddr};

use futures::channel::oneshot::channel;
use hyper::server::Server;
use hyper::service::make_service_fn;
use log::*;
use maplit::*;
use serde_json::{self, json, Value};
use uuid::Uuid;
use webmachine_rust::*;
use webmachine_rust::context::*;
use webmachine_rust::headers::*;

use pact_matching::models::load_pact_from_json;
use pact_mock_server::mock_server::MockServerConfig;
use pact_mock_server::tls::TlsConfigBuilder;

use crate::{SERVER_MANAGER, SERVER_OPTIONS, ServerOpts};
use crate::verify;

fn json_error(error: String) -> String {
    let json_response = json!({ "error" : json!(error) });
    json_response.to_string()
}

fn get_next_port(base_port: Option<u16>) -> u16 {
  match base_port {
    None => 0,
    Some(p) => if p > 0 {
      let mut port = p;
      let mut listener = TcpListener::bind(("127.0.0.1", port));
      while listener.is_err() && port < p + 1000 {
        port += 1;
        listener = TcpListener::bind(("127.0.0.1", port));
      }
      match listener {
        Ok(listener) => listener.local_addr().unwrap().port(),
        Err(_) => 0
      }
    } else {
      0
    }
  }
}

fn start_provider(context: &mut WebmachineContext, options: ServerOpts) -> Result<bool, u16> {
  debug!("start_provider => {}", context.request.request_path);
  match context.request.body {
    Some(ref body) if !body.is_empty() => {
      match serde_json::from_slice(body) {
        Ok(ref json) => {
          let pact = load_pact_from_json(&context.request.request_path, json)
            .map_err(|err| {
              error!("Failed to parse Pact JSON - {}", err);
              422_u16
            })?;
          debug!("Loaded pact = {:?}", pact);
          let mock_server_id = Uuid::new_v4().to_string();
          let config = MockServerConfig {
            cors_preflight: query_param_set(context, "cors")
          };
          debug!("Mock server config = {:?}", config);

          let mut guard = SERVER_MANAGER.lock().unwrap();
          let result = if query_param_set(context, "tls") {
            debug!("Starting TLS mock server with id {}", &mock_server_id);
            let key = include_str!("self-signed.key");
            let cert = include_str!("self-signed.cert");
            TlsConfigBuilder::new()
              .key(key.as_bytes())
              .cert(cert.as_bytes())
              .build()
              .map_err(|err| {
                format!("Failed to setup TLS using self-signed certificate - {}", err)
              })
              .and_then(|tls_config| {
                guard.start_tls_mock_server(mock_server_id.clone(), pact, get_next_port(options.base_port), &tls_config, config)
              })
          } else {
            debug!("Starting mock server with id {}", &mock_server_id);
            guard.start_mock_server(mock_server_id.clone(), pact, get_next_port(options.base_port), config)
          };
          match result {
            Ok(mock_server) => {
              debug!("mock server started on port {}", mock_server);
              let mock_server_json = json!({
                "id" : json!(mock_server_id),
                "port" : json!(mock_server as i64),
              });
              let json_response = json!({ "mockServer" : mock_server_json });
              context.response.body = Some(json_response.to_string().into_bytes());
              context.response.add_header("Location",
                vec![HeaderValue::basic(format!("/mockserver/{}", mock_server_id).as_str())]);
              Ok(true)
            },
            Err(msg) => {
              context.response.body = Some(json_error(format!("Failed to start mock server - {}", msg)).into_bytes());
              Err(422)
            }
          }
        },
        Err(err) => {
            log::error!("Failed to parse json body - {}", err);
            context.response.body = Some(json_error(format!("Failed to parse json body - {}", err)).into_bytes());
            Err(422)
        }
      }
    },
    _ => {
      log::error!("No pact json was supplied");
      context.response.body = Some(json_error("No pact json was supplied".to_string()).into_bytes());
      Err(422)
    }
  }
}

fn query_param_set(context: &mut WebmachineContext, name: &str) -> bool {
  context.request.query.get(name)
    .unwrap_or(&vec![]).first().unwrap_or(&String::default())
    .eq("true")
}

pub fn verify_mock_server_request(context: &mut WebmachineContext) -> Result<bool, u16> {
  let id = context.metadata.get("id").cloned().unwrap_or_default();
  match verify::validate_id(&id, &SERVER_MANAGER) {
    Ok(ms) => {
      let mut map = btreemap!{ "mockServer" => ms.to_json() };
      let mismatches = ms.mismatches();
      if !mismatches.is_empty() {
        map.insert("mismatches", json!(mismatches.iter()
          .map(|m| m.to_json()).collect::<Vec<Value>>()));
        context.response.body = Some(json!(map).to_string().into_bytes());
        Err(422)
      } else {
        let inner = SERVER_OPTIONS.lock().unwrap();
        let options = inner.borrow();
        match ms.write_pact(&options.output_path, false) {
          Ok(_) => Ok(true),
          Err(err) => {
            map.insert("error", json!(format!("Failed to write pact to file - {}", err)));
            context.response.body = Some(json!(map).to_string().into_bytes());
            Err(422)
          }
        }
      }
    },
    Err(_) => Err(422)
  }
}

fn shutdown_resource<'a>() -> WebmachineResource<'a> {
  WebmachineResource {
    allowed_methods: vec!["POST"],
    forbidden: callback(&|context, _| {
      let options = SERVER_OPTIONS.lock().unwrap();
      !context.request.has_header_value(&"Authorization".to_owned(), &format!("Bearer {}", options.borrow().server_key))
    }),
    process_post: callback(&|context, _| {
      let shutdown_period = match context.request.body {
        Some(ref body) if !body.is_empty() => {
          match serde_json::from_slice::<Value>(body) {
            Ok(ref json) => match json.get("period") {
              Some(val) => match val.clone() {
                Value::Number(n) => Ok(n.as_u64().unwrap_or(100)),
                _ => Ok(100)
              },
              None => Ok(100)
            },
            Err(err) => {
              error!("Failed to parse json body - {}", err);
              context.response.body = Some(json_error(format!("Failed to parse json body - {}", err)).into_bytes());
              Err(422)
            }
          }
        }
        _ => Ok(100)
      };

      match shutdown_period {
        Ok(period) => {
          // Need to work out how to do this as the webmachine has to have a static lifetime
          // shutdown.send(()).unwrap_or_default();
          thread::spawn(move || {
            info!("Scheduling master server to shutdown in {}ms", period);
            thread::sleep(Duration::from_millis(period));
            info!("Shutting down");
            process::exit(0);
          });
          Ok(true)
        }
        Err(err) => Err(err)
      }
    }),
    ..WebmachineResource::default()
  }
}

fn mock_server_resource<'a>() -> WebmachineResource<'a> {
  WebmachineResource {
    allowed_methods: vec!["OPTIONS", "GET", "HEAD", "POST", "DELETE"],
    resource_exists: callback(&|context, _| {
      debug!("mock_server_resource -> resource_exists");
      let paths: Vec<String> = context.request.request_path
        .split('/')
        .filter(|p| !p.is_empty())
        .map(|p| p.to_string())
        .collect();
      if !paths.is_empty() && paths.len() <= 2 {
        match verify::validate_id(&paths[0].clone(), &SERVER_MANAGER) {
          Ok(ms) => {
            context.metadata.insert("id".to_string(), ms.id.clone());
            context.metadata.insert("port".to_string(), ms.port.unwrap_or_default().to_string());
            if paths.len() > 1 {
              context.metadata.insert("subpath".to_string(), paths[1].clone());
              paths[1] == "verify"
            } else {
              true
            }
          }
          Err(_) => false
        }
      } else {
        false
      }
    }),
    render_response: callback(&|context, _| {
      debug!("mock_server_resource -> render_response");
      match context.metadata.get("subpath") {
        None => {
          let id = context.metadata.get("id").unwrap().clone();
          SERVER_MANAGER.lock().unwrap().find_mock_server_by_id(&id, &|ms| ms.to_json())
            .map(|json| json.to_string())
        }
        Some(_) => {
          context.response.status = 405;
          None
        }
      }
    }),
    process_post: callback(&|context, _| {
      debug!("mock_server_resource -> process_post");
      let subpath = context.metadata.get("subpath").unwrap().clone();
      if subpath == "verify" {
        verify_mock_server_request(context)
      } else {
        Err(422)
      }
    }),
    delete_resource: callback(&|context, _| {
      debug!("mock_server_resource -> delete_resource");
      match context.metadata.get("subpath") {
        None => {
          let id = context.metadata.get("id").unwrap().clone();
          thread::spawn(move || {
            if SERVER_MANAGER.lock().unwrap().shutdown_mock_server_by_id(id) {
              Ok(true)
            } else {
              Err(404)
            }
          }).join().expect("Could not spawn thread to shut down mock server")
        }
        Some(_) => Err(405)
      }
    }),
    ..WebmachineResource::default()
  }
}

fn dispatcher() -> WebmachineDispatcher<'static>  {
  WebmachineDispatcher {
    routes: btreemap! {
      "/" => WebmachineResource {
        allowed_methods: vec!["OPTIONS", "GET", "HEAD", "POST"],
        resource_exists: callback(&|context, _| {
          debug!("main_resource -> resource_exists");
          context.request.request_path == "/"
        }),
        render_response: callback(&|_, _| {
          debug!("main_resource -> render_response");
          let mock_servers = SERVER_MANAGER.lock().unwrap().map_mock_servers(&|ms| {
            ms.to_json()
          });
          let json_response = json!({ "mockServers" : json!(mock_servers) });
          Some(json_response.to_string())
        }),
        process_post: callback(&|context, _| {
          debug!("main_resource -> process_post");
          let (tx, rx) = mpsc::channel();
          let (tx2, rx2) = mpsc::channel();

          if let Err(err) = tx.send(context.clone()) {
            error!("Failed to send context to start new mock server - {:?}", err);
            return Err(500)
          }
          let start_fn = move || {
            let handle = thread::current();
            debug!("starting mock server on thread {}", handle.name().unwrap_or("<unknown>"));
            let inner = SERVER_OPTIONS.lock().unwrap();
            let options = inner.borrow().clone();
            let mut ctx = rx.recv().unwrap();
            let result = start_provider(&mut ctx, options);
            debug!("Result of starting mock server: {:?}", result.clone());
            match tx2.send(ctx) {
              Ok(_) => result,
              Err(err) => {
                error!("Failed to send result back to main resource - {:?}", err);
                Err(500)
              }
            }
          };

          match thread::spawn(start_fn).join() {
            Ok(res) => {
              debug!("Result of thread: {:?}", res);
              let ctx = rx2.recv().unwrap();
              context.response = ctx.response;
              res
            },
            Err(err) => {
              error!("Failed to spawn new thread to start new mock server - {:?}", err);
              Err(500)
            }
          }
        }),
        .. WebmachineResource::default()
      },
      "/mockserver" => mock_server_resource(),
      "/shutdown" => shutdown_resource()
    }
  }
}

pub async fn start_server(port: u16) -> Result<(), i32> {
  let addr = SocketAddr::new(IpAddr::from([0, 0, 0, 0]), port);
  let (_, shutdown_rx) = channel::<()>();

  let make_svc = make_service_fn(|_| async {
    Ok::<_, Infallible>(dispatcher())
  });
  match Server::try_bind(&addr) {
    Ok(server) => {
      let server = server.serve(make_svc);
      {
        let inner = SERVER_OPTIONS.lock().unwrap();
        let options = inner.borrow();
        info!("Master server started on port {}", server.local_addr().port());
        info!("Server key: '{}'", options.server_key);
      }
      server.with_graceful_shutdown(async { shutdown_rx.await.unwrap_or_default() }).await.map_err(|err| {
        error!("Received an error starting master server: {}", err);
        2
      })
    },
    Err(err) => {
      error!("could not start master server: {}", err);
      Err(1)
    }
  }
}
<commit_msg>Revert "chore: remove unused imports"<commit_after>use std::{
  net::TcpListener,
  process,
  sync::mpsc,
  thread,
  time::Duration
};
use std::convert::Infallible;
use std::net::{IpAddr, SocketAddr};

use futures::channel::oneshot::channel;
use hyper::server::Server;
use hyper::service::make_service_fn;
use log::*;
use maplit::*;
use serde_json::{self, json, Value};
use uuid::Uuid;
use webmachine_rust::*;
use webmachine_rust::context::*;
use webmachine_rust::headers::*;

use pact_matching::models::load_pact_from_json;
use pact_mock_server::mock_server::MockServerConfig;
use pact_mock_server::tls::TlsConfigBuilder;

use crate::{SERVER_MANAGER, SERVER_OPTIONS, ServerOpts};
use crate::verify;

fn json_error(error: String) -> String {
    let json_response = json!({ "error" : json!(error) });
    json_response.to_string()
}

fn get_next_port(base_port: Option<u16>) -> u16 {
  match base_port {
    None => 0,
    Some(p) => if p > 0 {
      let mut port = p;
      let mut listener = TcpListener::bind(("127.0.0.1", port));
      while listener.is_err() && port < p + 1000 {
        port += 1;
        listener = TcpListener::bind(("127.0.0.1", port));
      }
      match listener {
        Ok(listener) => listener.local_addr().unwrap().port(),
        Err(_) => 0
      }
    } else {
      0
    }
  }
}

fn start_provider(context: &mut WebmachineContext, options: ServerOpts) -> Result<bool, u16> {
  debug!("start_provider => {}", context.request.request_path);
  match context.request.body {
    Some(ref body) if !body.is_empty() => {
      match serde_json::from_slice(body) {
        Ok(ref json) => {
          let pact = load_pact_from_json(&context.request.request_path, json)
            .map_err(|err| {
              error!("Failed to parse Pact JSON - {}", err);
              422_u16
            })?;
          debug!("Loaded pact = {:?}", pact);
          let mock_server_id = Uuid::new_v4().to_string();
          let config = MockServerConfig {
            cors_preflight: query_param_set(context, "cors")
          };
          debug!("Mock server config = {:?}", config);

          let mut guard = SERVER_MANAGER.lock().unwrap();
          let result = if query_param_set(context, "tls") {
            debug!("Starting TLS mock server with id {}", &mock_server_id);
            let key = include_str!("self-signed.key");
            let cert = include_str!("self-signed.cert");
            TlsConfigBuilder::new()
              .key(key.as_bytes())
              .cert(cert.as_bytes())
              .build()
              .map_err(|err| {
                format!("Failed to setup TLS using self-signed certificate - {}", err)
              })
              .and_then(|tls_config| {
                guard.start_tls_mock_server(mock_server_id.clone(), pact, get_next_port(options.base_port), &tls_config, config)
              })
          } else {
            debug!("Starting mock server with id {}", &mock_server_id);
            guard.start_mock_server(mock_server_id.clone(), pact, get_next_port(options.base_port), config)
          };
          match result {
            Ok(mock_server) => {
              debug!("mock server started on port {}", mock_server);
              let mock_server_json = json!({
                "id" : json!(mock_server_id),
                "port" : json!(mock_server as i64),
              });
              let json_response = json!({ "mockServer" : mock_server_json });
              context.response.body = Some(json_response.to_string().into_bytes());
              context.response.add_header("Location",
                vec![HeaderValue::basic(format!("/mockserver/{}", mock_server_id).as_str())]);
              Ok(true)
            },
            Err(msg) => {
              context.response.body = Some(json_error(format!("Failed to start mock server - {}", msg)).into_bytes());
              Err(422)
            }
          }
        },
        Err(err) => {
            log::error!("Failed to parse json body - {}", err);
            context.response.body = Some(json_error(format!("Failed to parse json body - {}", err)).into_bytes());
            Err(422)
        }
      }
    },
    _ => {
      log::error!("No pact json was supplied");
      context.response.body = Some(json_error("No pact json was supplied".to_string()).into_bytes());
      Err(422)
    }
  }
}

fn query_param_set(context: &mut WebmachineContext, name: &str) -> bool {
  context.request.query.get(name)
    .unwrap_or(&vec![]).first().unwrap_or(&String::default())
    .eq("true")
}

pub fn verify_mock_server_request(context: &mut WebmachineContext) -> Result<bool, u16> {
  let id = context.metadata.get("id").cloned().unwrap_or_default();
  match verify::validate_id(&id, &SERVER_MANAGER) {
    Ok(ms) => {
      let mut map = btreemap!{ "mockServer" => ms.to_json() };
      let mismatches = ms.mismatches();
      if !mismatches.is_empty() {
        map.insert("mismatches", json!(mismatches.iter()
          .map(|m| m.to_json()).collect::<Vec<Value>>()));
        context.response.body = Some(json!(map).to_string().into_bytes());
        Err(422)
      } else {
        let inner = SERVER_OPTIONS.lock().unwrap();
        let options = inner.borrow();
        match ms.write_pact(&options.output_path, false) {
          Ok(_) => Ok(true),
          Err(err) => {
            map.insert("error", json!(format!("Failed to write pact to file - {}", err)));
            context.response.body = Some(json!(map).to_string().into_bytes());
            Err(422)
          }
        }
      }
    },
    Err(_) => Err(422)
  }
}

fn shutdown_resource<'a>() -> WebmachineResource<'a> {
  WebmachineResource {
    allowed_methods: vec!["POST"],
    forbidden: callback(&|context, _| {
      let options = SERVER_OPTIONS.lock().unwrap();
      !context.request.has_header_value(&"Authorization".to_owned(), &format!("Bearer {}", options.borrow().server_key))
    }),
    process_post: callback(&|context, _| {
      let shutdown_period = match context.request.body {
        Some(ref body) if !body.is_empty() => {
          match serde_json::from_slice::<Value>(body) {
            Ok(ref json) => match json.get("period") {
              Some(val) => match val.clone() {
                Value::Number(n) => Ok(n.as_u64().unwrap_or(100)),
                _ => Ok(100)
              },
              None => Ok(100)
            },
            Err(err) => {
              error!("Failed to parse json body - {}", err);
              context.response.body = Some(json_error(format!("Failed to parse json body - {}", err)).into_bytes());
              Err(422)
            }
          }
        }
        _ => Ok(100)
      };

      match shutdown_period {
        Ok(period) => {
          // Need to work out how to do this as the webmachine has to have a static lifetime
          // shutdown.send(()).unwrap_or_default();
          thread::spawn(move || {
            info!("Scheduling master server to shutdown in {}ms", period);
            thread::sleep(Duration::from_millis(period));
            info!("Shutting down");
            process::exit(0);
          });
          Ok(true)
        }
        Err(err) => Err(err)
      }
    }),
    ..WebmachineResource::default()
  }
}

fn mock_server_resource<'a>() -> WebmachineResource<'a> {
  WebmachineResource {
    allowed_methods: vec!["OPTIONS", "GET", "HEAD", "POST", "DELETE"],
    resource_exists: callback(&|context, _| {
      debug!("mock_server_resource -> resource_exists");
      let paths: Vec<String> = context.request.request_path
        .split('/')
        .filter(|p| !p.is_empty())
        .map(|p| p.to_string())
        .collect();
      if !paths.is_empty() && paths.len() <= 2 {
        match verify::validate_id(&paths[0].clone(), &SERVER_MANAGER) {
          Ok(ms) => {
            context.metadata.insert("id".to_string(), ms.id.clone());
            context.metadata.insert("port".to_string(), ms.port.unwrap_or_default().to_string());
            if paths.len() > 1 {
              context.metadata.insert("subpath".to_string(), paths[1].clone());
              paths[1] == "verify"
            } else {
              true
            }
          }
          Err(_) => false
        }
      } else {
        false
      }
    }),
    render_response: callback(&|context, _| {
      debug!("mock_server_resource -> render_response");
      match context.metadata.get("subpath") {
        None => {
          let id = context.metadata.get("id").unwrap().clone();
          SERVER_MANAGER.lock().unwrap().find_mock_server_by_id(&id, &|ms| ms.to_json())
            .map(|json| json.to_string())
        }
        Some(_) => {
          context.response.status = 405;
          None
        }
      }
    }),
    process_post: callback(&|context, _| {
      debug!("mock_server_resource -> process_post");
      let subpath = context.metadata.get("subpath").unwrap().clone();
      if subpath == "verify" {
        verify_mock_server_request(context)
      } else {
        Err(422)
      }
    }),
    delete_resource: callback(&|context, _| {
      debug!("mock_server_resource -> delete_resource");
      match context.metadata.get("subpath") {
        None => {
          let id = context.metadata.get("id").unwrap().clone();
          thread::spawn(move || {
            if SERVER_MANAGER.lock().unwrap().shutdown_mock_server_by_id(id) {
              Ok(true)
            } else {
              Err(404)
            }
          }).join().expect("Could not spawn thread to shut down mock server")
        }
        Some(_) => Err(405)
      }
    }),
    ..WebmachineResource::default()
  }
}

fn dispatcher() -> WebmachineDispatcher<'static>  {
  WebmachineDispatcher {
    routes: btreemap! {
      "/" => WebmachineResource {
        allowed_methods: vec!["OPTIONS", "GET", "HEAD", "POST"],
        resource_exists: callback(&|context, _| {
          debug!("main_resource -> resource_exists");
          context.request.request_path == "/"
        }),
        render_response: callback(&|_, _| {
          debug!("main_resource -> render_response");
          let mock_servers = SERVER_MANAGER.lock().unwrap().map_mock_servers(&|ms| {
            ms.to_json()
          });
          let json_response = json!({ "mockServers" : json!(mock_servers) });
          Some(json_response.to_string())
        }),
        process_post: callback(&|context, _| {
          debug!("main_resource -> process_post");
          let (tx, rx) = mpsc::channel();
          let (tx2, rx2) = mpsc::channel();

          if let Err(err) = tx.send(context.clone()) {
            error!("Failed to send context to start new mock server - {:?}", err);
            return Err(500)
          }
          let start_fn = move || {
            let handle = thread::current();
            debug!("starting mock server on thread {}", handle.name().unwrap_or("<unknown>"));
            let inner = SERVER_OPTIONS.lock().unwrap();
            let options = inner.borrow().clone();
            let mut ctx = rx.recv().unwrap();
            let result = start_provider(&mut ctx, options);
            debug!("Result of starting mock server: {:?}", result.clone());
            match tx2.send(ctx) {
              Ok(_) => result,
              Err(err) => {
                error!("Failed to send result back to main resource - {:?}", err);
                Err(500)
              }
            }
          };

          match thread::spawn(start_fn).join() {
            Ok(res) => {
              debug!("Result of thread: {:?}", res);
              let ctx = rx2.recv().unwrap();
              context.response = ctx.response;
              res
            },
            Err(err) => {
              error!("Failed to spawn new thread to start new mock server - {:?}", err);
              Err(500)
            }
          }
        }),
        .. WebmachineResource::default()
      },
      "/mockserver" => mock_server_resource(),
      "/shutdown" => shutdown_resource()
    }
  }
}

pub async fn start_server(port: u16) -> Result<(), i32> {
  let addr = SocketAddr::new(IpAddr::from([0, 0, 0, 0]), port);
  let (shutdown_tx, shutdown_rx) = channel::<()>();

  let make_svc = make_service_fn(|_| async {
    Ok::<_, Infallible>(dispatcher())
  });
  match Server::try_bind(&addr) {
    Ok(server) => {
      let server = server.serve(make_svc);
      {
        let inner = SERVER_OPTIONS.lock().unwrap();
        let options = inner.borrow();
        info!("Master server started on port {}", server.local_addr().port());
        info!("Server key: '{}'", options.server_key);
      }
      server.with_graceful_shutdown(async { shutdown_rx.await.unwrap_or_default() }).await.map_err(|err| {
        error!("Received an error starting master server: {}", err);
        2
      })
    },
    Err(err) => {
      error!("could not start master server: {}", err);
      Err(1)
    }
  }
}
<|endoftext|>


<commit_before>#[macro_use]
pub mod types;

use self::types::*;
use common::combinator::Parser;

pub fn tokenize<T: Iterator<Item = char>>(input: T) -> Result<Vec<Token>> {
    let mut l = Lexer::new(input);
    // FIXME
    l.atom('h').and_then(|c| Ok(Vec::default()))
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::fmt::Debug;

    fn lex(input: &str) -> Vec<Token> {
        tokenize(String::from(input).chars()).unwrap()
    }

    fn vec_eq<T: PartialEq + Debug>(xs: &Vec<T>, ys: &Vec<T>) {
        if xs.len() != ys.len() {
            panic!("{:?} != {:?}", xs, ys);
        }
        for i in 0..xs.len() {
            if xs[i] != ys[i] {
                panic!("{:?} != {:?}", xs, ys);
            }
        }
    }

    #[test]
    fn special_chars() {
        vec_eq(&lex("=+(){},;"),
               &vec![token!(Assign, 1, 1, '='),
                     token!(Plus, 1, 2, '+'),
                     token!(LParen, 1, 3, '('),
                     token!(RParen, 1, 4, ')'),
                     token!(LBrace, 1, 5, '{'),
                     token!(RBrace, 1, 6, '}'),
                     token!(Comma, 1, 7, ','),
                     token!(SemiColon, 1, 8, ';')]);
    }

    #[test]
    fn complex_code() {
        vec_eq(&lex("
let five = 5;
let ten = 10;
let add = fn(x, y) {
    x + y;
};
let result = add(five, ten);
               "),
               &vec![token!(Let, 2, 1, "let"),
                     token!(Ident, 2, 5, "five"),
                     token!(Assign, 2, 10, "="),
                     token!(IntLiteral, 2, 12, "5"),
                     token!(SemiColon, 2, 13, ";"),
                     token!(Let, 3, 1, "let"),
                     token!(Ident, 3, 5, "ten"),
                     token!(Assign, 3, 9, "="),
                     token!(IntLiteral, 3, 11, "10"),
                     token!(SemiColon, 3, 13, ";"),
                     token!(Let, 4, 1, "let"),
                     token!(Ident, 4, 5, "add"),
                     token!(Assign, 4, 9, "="),
                     token!(Function, 4, 11, "fn"),
                     token!(LParen, 4, 13, "("),
                     token!(Ident, 4, 14, "x"),
                     token!(Comma, 4, 15, ","),
                     token!(Ident, 4, 17, "y"),
                     token!(RParen, 4, 18, ")"),
                     token!(LBrace, 4, 20, "{"),
                     token!(Ident, 5, 5, "x"),
                     token!(Plus, 5, 7, "+"),
                     token!(Ident, 5, 9, "y"),
                     token!(SemiColon, 5, 10, ";"),
                     token!(RBrace, 6, 1, "}"),
                     token!(SemiColon, 6, 2, ";"),
                     token!(Let, 7, 1, "let"),
                     token!(Ident, 7, 5, "result"),
                     token!(Assign, 7, 12, "="),
                     token!(Ident, 7, 14, "add"),
                     token!(LParen, 7, 17, "("),
                     token!(Ident, 7, 18, "five"),
                     token!(Comma, 7, 22, ","),
                     token!(Ident, 7, 24, "ten"),
                     token!(RParen, 7, 27, ")"),
                     token!(SemiColon, 7, 28, ";")]);
    }
}
<commit_msg>Add more lexer tests<commit_after>#[macro_use]
pub mod types;

use self::types::*;
use common::combinator::Parser;

pub fn tokenize<T: Iterator<Item = char>>(input: T) -> Result<Vec<Token>> {
    let mut l = Lexer::new(input);
    // FIXME
    l.atom('h').and_then(|c| Ok(Vec::default()))
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::fmt::Debug;

    fn lex(input: &str) -> Vec<Token> {
        tokenize(String::from(input).chars()).unwrap()
    }

    fn vec_eq<T: PartialEq + Debug>(xs: &Vec<T>, ys: &Vec<T>) {
        if xs.len() != ys.len() {
            panic!("{:?} != {:?}", xs, ys);
        }
        for i in 0..xs.len() {
            if xs[i] != ys[i] {
                panic!("{:?} != {:?}", xs, ys);
            }
        }
    }

    #[test]
    fn special_chars() {
        vec_eq(&lex("=+(){},;"),
               &vec![token!(Assign, 1, 1, '='),
                     token!(Plus, 1, 2, '+'),
                     token!(LParen, 1, 3, '('),
                     token!(RParen, 1, 4, ')'),
                     token!(LBrace, 1, 5, '{'),
                     token!(RBrace, 1, 6, '}'),
                     token!(Comma, 1, 7, ','),
                     token!(SemiColon, 1, 8, ';')]);
    }

    #[test]
    fn complex_code() {
        vec_eq(&lex("
let five = 5;
let ten = 10;
let add = fn(x, y) {
    x + y;
};
let result = add(five, ten);
               "),
               &vec![token!(Let, 2, 1, "let"),
                     token!(Ident, 2, 5, "five"),
                     token!(Assign, 2, 10, "="),
                     token!(IntLiteral, 2, 12, "5"),
                     token!(SemiColon, 2, 13, ";"),
                     token!(Let, 3, 1, "let"),
                     token!(Ident, 3, 5, "ten"),
                     token!(Assign, 3, 9, "="),
                     token!(IntLiteral, 3, 11, "10"),
                     token!(SemiColon, 3, 13, ";"),
                     token!(Let, 4, 1, "let"),
                     token!(Ident, 4, 5, "add"),
                     token!(Assign, 4, 9, "="),
                     token!(Function, 4, 11, "fn"),
                     token!(LParen, 4, 13, "("),
                     token!(Ident, 4, 14, "x"),
                     token!(Comma, 4, 15, ","),
                     token!(Ident, 4, 17, "y"),
                     token!(RParen, 4, 18, ")"),
                     token!(LBrace, 4, 20, "{"),
                     token!(Ident, 5, 5, "x"),
                     token!(Plus, 5, 7, "+"),
                     token!(Ident, 5, 9, "y"),
                     token!(SemiColon, 5, 10, ";"),
                     token!(RBrace, 6, 1, "}"),
                     token!(SemiColon, 6, 2, ";"),
                     token!(Let, 7, 1, "let"),
                     token!(Ident, 7, 5, "result"),
                     token!(Assign, 7, 12, "="),
                     token!(Ident, 7, 14, "add"),
                     token!(LParen, 7, 17, "("),
                     token!(Ident, 7, 18, "five"),
                     token!(Comma, 7, 22, ","),
                     token!(Ident, 7, 24, "ten"),
                     token!(RParen, 7, 27, ")"),
                     token!(SemiColon, 7, 28, ";")]);
    }

    #[test]
    fn complex_code2() {
        vec_eq(&lex("
if (a == 10) {
  return a;
} else if (a != 20) {
  return !a;
} else if (a > 20) {
  return -30 / 40 * 50;
} else if (a < 30) {
  return true;
}
return false;
                    "),
               &vec![token!(If, 2, 1, "if"),
                     token!(LParen, 2, 3, "("),
                     token!(Ident, 2, 4, "a"),
                     token!(Eq, 2, 6, "=="),
                     token!(IntLiteral, 2, 9, "10"),
                     token!(RParen, 2, 11, ")"),
                     token!(LBrace, 2, 13, "{"),
                     token!(Return, 3, 3, "return"),
                     token!(Ident, 3, 10, "a"),
                     token!(SemiColon, 3, 11, ";"),
                     token!(RBrace, 4, 1, "}"),
                     token!(Else, 4, 3, "else"),
                     token!(If, 4, 8, "if"),
                     token!(LParen, 4, 11, "("),
                     token!(Ident, 4, 12, "a"),
                     token!(NotEq, 4, 14, "!="),
                     token!(IntLiteral, 4, 17, "20"),
                     token!(RParen, 4, 19, ")"),
                     token!(LBrace, 4, 21, "{"),
                     token!(Return, 5, 3, "return"),
                     token!(Not, 5, 10, "!"),
                     token!(Ident, 5, 11, "a"),
                     token!(SemiColon, 5, 13, ";"),
                     token!(RBrace, 6, 1, "}"),
                     token!(Else, 6, 3, "else"),
                     token!(If, 6, 8, "if"),
                     token!(LParen, 6, 11, "("),
                     token!(Ident, 6, 12, "a"),
                     token!(GreaterThan, 6, 14, ">"),
                     token!(IntLiteral, 6, 16, "20"),
                     token!(RParen, 6, 18, ")"),
                     token!(LBrace, 6, 20, "{"),
                     token!(Return, 7, 3, "return"),
                     token!(Minus, 7, 10, "-"),
                     token!(IntLiteral, 7, 11, "30"),
                     token!(Divide, 7, 14, "/"),
                     token!(IntLiteral, 7, 16, "40"),
                     token!(Multiply, 7, 19, "*"),
                     token!(IntLiteral, 7, 21, "50"),
                     token!(SemiColon, 7, 23, ";"),
                     token!(RBrace, 8, 1, "}"),
                     token!(Else, 8, 3, "else"),
                     token!(If, 8, 8, "if"),
                     token!(LParen, 8, 11, "("),
                     token!(Ident, 8, 12, "a"),
                     token!(LessThan, 8, 14, "<"),
                     token!(IntLiteral, 8, 16, "30"),
                     token!(RParen, 8, 18, ")"),
                     token!(LBrace, 8, 20, "{"),
                     token!(Return, 9, 3, "return"),
                     token!(BoolLiteral, 9, 10, "true"),
                     token!(SemiColon, 9, 14, ";"),
                     token!(RBrace, 10, 1, "}"),
                     token!(Return, 11, 1, "return"),
                     token!(BoolLiteral, 11, 8, "false"),
                     token!(SemiColon, 11, 13, ";")]);
    }

    #[test]
    fn id_with_numbers() {
        vec_eq(&lex("hello2 hel301oo120"),
               &vec![token!(Ident, 1, 1, "hello2"),
                     token!(Ident, 1, 8, "hel301oo120")]);
    }

    #[test]
    fn string_literals() {
        vec_eq(&lex("\"foobar\""),
               &vec![token!(StringLiteral, 1, 1, "\"foobar\"")]);
        vec_eq(&lex("\"foo bar\""),
               &vec![token!(StringLiteral, 1, 1, "\"foo bar\"")]);
        vec_eq(&lex("\"foo\\nbar\""),
               &vec![token!(StringLiteral, 1, 1, "\"foo\\nbar\"")]);
        vec_eq(&lex("\"foo\\tbar\""),
               &vec![token!(StringLiteral, 1, 1, "\"foo\\tbar\"")]);
        vec_eq(&lex("\"foo\\\"bar\""),
               &vec![token!(StringLiteral, 1, 1, "\"foo\\\"bar\"")]);
    }

    #[test]
    fn array_tokens() {
        vec_eq(&lex("[1, 2];"),
               &vec![token!(LBracket, 1, 1, "["),
                     token!(IntLiteral, 1, 2, "1"),
                     token!(Comma, 1, 3, ","),
                     token!(IntLiteral, 1, 5, "2"),
                     token!(RBracket, 1, 6, "]"),
                     token!(SemiColon, 1, 7, ";")]);
    }

    #[test]
    fn hash_tokens() {
        vec_eq(&lex("{\"hello\": \"world\"}"),
               &vec![token!(LBrace, 1, 1, "{"),
                     token!(StringLiteral, 1, 2, "\"hello\""),
                     token!(Colon, 1, 9, ":"),
                     token!(StringLiteral, 1, 11, "\"world\""),
                     token!(RBrace, 1, 18, "}")]);
    }
}
<|endoftext|>


<commit_before>use num;
use num::traits::NumCast;
use std::str::FromStr;

/// A data table consisting of varying column types and headers.
pub struct DataTable {
    pub data_cols: Vec<Box<ColumnData>>,
}

impl DataTable {
    pub fn empty() -> DataTable {
        DataTable { data_cols: Vec::new() }
    }

    pub fn cols(&self) -> usize {
        self.data_cols.len()
    }

    pub fn rows(&self) -> usize {
        if self.data_cols.len() > 0 {
            return self.data_cols[0].len();
        }

        0usize
    }
}

pub trait ColumnData {
    fn len(&self) -> usize;

    fn push(&mut self, val: &str) -> Result<DataType, DataType>;
}

#[derive(PartialEq)]
pub enum DataType {
    Float,
    Integer,
    String,
}

/// A data column with a consistent data type.
pub struct ColumnBase<T> {
    pub data: Vec<T>,
    // field for 'highest' type possible
    top_type: DataType,
}

impl<T> ColumnBase<T> {
    pub fn empty() -> ColumnBase<T> {
        ColumnBase {
            data: Vec::new(),
            top_type: DataType::Float,
        }
    }
}

impl<T: NumCast> ColumnData for ColumnBase<T> {
    fn len(&self) -> usize {
        self.data.len()
    }

    fn push(&mut self, val: &str) -> Result<DataType, DataType> {
        match self.top_type {

            DataType::Integer => {
                match i64::from_str(val) {
                    Ok(x) => {
                        self.data.push(num::cast(x).unwrap());
                        Ok(DataType::Integer)
                    }
                    Err(_) => Err(DataType::Float)
                }
            }

            DataType::Float => {
                match f64::from_str(val) {
                    Ok(x) => {
                        self.data.push(num::cast(x).unwrap());
                        Ok(DataType::Float)
                    }
                    Err(_) => Err(DataType::String)
                }
            }

            _ => Err(DataType::String)
        }
    }
}
<commit_msg>Removing DataType from Ok result.<commit_after>use num;
use num::traits::NumCast;
use std::str::FromStr;

/// A data table consisting of varying column types and headers.
pub struct DataTable {
    pub data_cols: Vec<Box<ColumnData>>,
}

impl DataTable {
    pub fn empty() -> DataTable {
        DataTable { data_cols: Vec::new() }
    }

    pub fn cols(&self) -> usize {
        self.data_cols.len()
    }

    pub fn rows(&self) -> usize {
        if self.data_cols.len() > 0 {
            return self.data_cols[0].len();
        }

        0usize
    }
}

pub trait ColumnData {
    fn len(&self) -> usize;

    fn push(&mut self, val: &str) -> Result<(), DataType>;
}

#[derive(PartialEq)]
pub enum DataType {
    Float,
    Integer,
    String,
}

/// A data column with a consistent data type.
pub struct ColumnBase<T> {
    pub data: Vec<T>,
    // field for 'highest' type possible
    top_type: DataType,
}

impl<T> ColumnBase<T> {
    pub fn empty() -> ColumnBase<T> {
        ColumnBase {
            data: Vec::new(),
            top_type: DataType::Float,
        }
    }
}

impl<T: NumCast> ColumnData for ColumnBase<T> {
    fn len(&self) -> usize {
        self.data.len()
    }

    fn push(&mut self, val: &str) -> Result<(), DataType> {
        match self.top_type {

            DataType::Integer => {
                match i64::from_str(val) {
                    Ok(x) => {
                        self.data.push(num::cast(x).unwrap());
                        Ok(())
                    }
                    Err(_) => Err(DataType::Float)
                }
            }

            DataType::Float => {
                match f64::from_str(val) {
                    Ok(x) => {
                        self.data.push(num::cast(x).unwrap());
                        Ok(())
                    }
                    Err(_) => Err(DataType::String)
                }
            }

            _ => Err(DataType::String)
        }
    }
}
<|endoftext|>


<commit_before>use std::{fmt, ops::Bound};

use pagecache::Lazy;

use super::*;

#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub(crate) struct Node {
    pub(crate) data: Data,
    pub(crate) next: Option<PageId>,
    pub(crate) lo: IVec,
    pub(crate) hi: IVec,
    pub(crate) merging_child: Option<PageId>,
    pub(crate) merging: bool,
}

impl fmt::Debug for Node {
    fn fmt(
        &self,
        f: &mut fmt::Formatter<'_>,
    ) -> std::result::Result<(), fmt::Error> {
        let data = self.data.fmt_keys(&self.lo);

        write!(
            f,
            "Node {{ \
             lo: {:?} \
             hi: {:?} \
             next: {:?} \
             merging_child: {:?} \
             merging: {} \
             data: {:?} }}",
            self.lo, self.hi, self.next, self.merging_child, self.merging, data
        )
    }
}

impl Node {
    pub(crate) fn apply(&mut self, frag: &Frag) {
        use self::Frag::*;

        assert!(
            !self.merging,
            "somehow a frag was applied to a node after it was merged"
        );

        match *frag {
            Set(ref k, ref v) => {
                // (when hi is empty, it means it's unbounded)
                if self.hi.is_empty()
                    || prefix_cmp_encoded(k, &self.hi, &self.lo)
                        == std::cmp::Ordering::Less
                {
                    self.set_leaf(k.clone(), v.clone());
                } else {
                    panic!(
                        "tried to consolidate set at key <= hi.\
                         Set({:?}, {:?}) to node {:?}",
                        k, v, self
                    )
                }
            }
            Del(ref k) => {
                // (when hi is empty, it means it's unbounded)
                if self.hi.is_empty()
                    || prefix_cmp_encoded(k, &self.hi, &self.lo)
                        == std::cmp::Ordering::Less
                {
                    self.del_leaf(k);
                } else {
                    panic!("tried to consolidate del at key <= hi")
                }
            }
            Base(_) => panic!("trying to apply a Base to frag {:?}", self),
            ParentMergeIntention(pid) => {
                assert!(
                    self.merging_child.is_none(),
                    "trying to merge {:?} into node {:?} which \
                     is already merging another child",
                    frag,
                    self
                );
                self.merging_child = Some(pid);
            }
            ParentMergeConfirm => {
                assert!(self.merging_child.is_some());
                let merged_child = self.merging_child.take().expect(
                    "we should have a specific \
                     child that was merged if this \
                     frag appears here",
                );
                self.data.parent_merge_confirm(merged_child);
            }
            ChildMergeCap => {
                self.merging = true;
            }
        }
    }

    pub(crate) fn set_leaf(&mut self, key: IVec, val: IVec) {
        if let Data::Leaf(ref mut records) = self.data {
            let search = records.binary_search_by(|(k, _)| prefix_cmp(k, &key));
            match search {
                Ok(idx) => records[idx] = (key, val),
                Err(idx) => records.insert(idx, (key, val)),
            }
        } else {
            panic!("tried to Set a value to an index");
        }
    }

    pub(crate) fn parent_split(&mut self, at: &[u8], to: PageId) -> bool {
        if let Data::Index(ref mut ptrs) = self.data {
            let encoded_sep = prefix_encode(&self.lo, at);
            match ptrs.binary_search_by(|a| prefix_cmp(&a.0, &encoded_sep)) {
                Ok(_) => {
                    debug!(
                        "parent_split skipped because \
                         parent already contains child at split point \
                         due to deep race"
                    );
                    return false;
                }
                Err(idx) => ptrs.insert(idx, (encoded_sep, to)),
            }
        } else {
            panic!("tried to attach a ParentSplit to a Leaf chain");
        }

        true
    }

    pub(crate) fn del_leaf(&mut self, key: &IVec) {
        if let Data::Leaf(ref mut records) = self.data {
            let search = records
                .binary_search_by(|&(ref k, ref _v)| prefix_cmp(k, &*key));
            if let Ok(idx) = search {
                records.remove(idx);
            }
        } else {
            panic!("tried to attach a Del to an Index chain");
        }
    }

    pub(crate) fn split(mut self) -> (Self, Self) {
        let (split, right_data) = self.data.split(&self.lo);
        let rhs = Self {
            data: right_data,
            next: self.next,
            lo: split,
            hi: self.hi.clone(),
            merging_child: None,
            merging: false,
        };

        self.data.drop_gte(&rhs.lo, &self.lo);
        self.hi = rhs.lo.clone();

        // intentionally make this the end to make
        // any issues pop out with setting it
        // correctly after the split.
        self.next = None;

        (self, rhs)
    }

    pub(crate) fn receive_merge(&self, rhs: &Self) -> Self {
        let mut merged = self.clone();
        merged.hi = rhs.hi.clone();
        merged.data.receive_merge(
            rhs.lo.as_ref(),
            merged.lo.as_ref(),
            &rhs.data,
        );
        merged.next = rhs.next;
        merged
    }

    pub(crate) fn contains_upper_bound(&self, bound: &Bound<IVec>) -> bool {
        match bound {
            Bound::Excluded(bound) if self.hi >= *bound => true,
            Bound::Included(bound) if self.hi > *bound => true,
            _ => self.hi.is_empty(),
        }
    }

    pub(crate) fn contains_lower_bound(
        &self,
        bound: &Bound<IVec>,
        is_forward: bool,
    ) -> bool {
        match bound {
            Bound::Excluded(bound)
                if self.lo < *bound || (is_forward && *bound == self.lo) =>
            {
                true
            }
            Bound::Included(bound) if self.lo <= *bound => true,
            Bound::Unbounded if !is_forward => self.hi.is_empty(),
            _ => self.lo.is_empty(),
        }
    }

    pub(crate) fn successor(
        &self,
        bound: &Bound<IVec>,
    ) -> Option<(IVec, IVec)> {
        assert!(!self.data.is_index());

        // This encoding happens this way because
        // keys cannot be lower than the node's lo key.
        let predecessor_key = match bound {
            Bound::Unbounded => prefix_encode(&self.lo, &self.lo),
            Bound::Included(b) => {
                let max = std::cmp::max(b, &self.lo);
                prefix_encode(&self.lo, max)
            }
            Bound::Excluded(b) => {
                let max = std::cmp::max(b, &self.lo);
                prefix_encode(&self.lo, max)
            }
        };

        let records = self.data.leaf_ref().unwrap();
        let search =
            records.binary_search_by(|(k, _)| prefix_cmp(k, &predecessor_key));

        let idx = match search {
            Ok(idx) | Err(idx) => idx,
        };

        for (k, v) in &records[idx..] {
            match bound {
                Bound::Excluded(b)
                    if prefix_cmp_encoded(k, b, &self.lo)
                        == std::cmp::Ordering::Equal =>
                {
                    // keep going because we wanted to exclude
                    // this key.
                    continue;
                }
                _ => {}
            }
            let decoded_key = prefix_decode(&self.lo, &k);
            return Some((IVec::from(decoded_key), v.clone()));
        }

        None
    }

    pub(crate) fn predecessor(
        &self,
        bound: &Bound<IVec>,
    ) -> Option<(IVec, IVec)> {
        static MAX_IVEC: Lazy<IVec, fn() -> IVec> = Lazy::new(init_max_ivec);

        fn init_max_ivec() -> IVec {
            let mut base = vec![255; 1024 * 1024];
            base[0] = 0;
            IVec::from(base)
        }

        assert!(!self.data.is_index());

        // This encoding happens this way because
        // the rightmost (unbounded) node has
        // a hi key represented by the empty slice
        let successor_key = match bound {
            Bound::Unbounded => {
                if self.hi.is_empty() {
                    MAX_IVEC.clone()
                } else {
                    prefix_encode(&self.lo, &self.hi)
                }
            }
            Bound::Included(b) => {
                let min = if self.hi.is_empty() {
                    b
                } else {
                    std::cmp::min(b, &self.hi)
                };
                prefix_encode(&self.lo, min)
            }
            Bound::Excluded(b) => {
                let min = if self.hi.is_empty() {
                    b
                } else {
                    std::cmp::min(b, &self.hi)
                };
                prefix_encode(&self.lo, min)
            }
        };

        let records = self.data.leaf_ref().unwrap();
        let search =
            records.binary_search_by(|(k, _)| prefix_cmp(k, &successor_key));

        let idx = match search {
            Ok(idx) => idx,
            Err(idx) if idx > 0 => idx - 1,
            _ => return None,
        };

        for (k, v) in records[0..=idx].iter().rev() {
            match bound {
                Bound::Excluded(b)
                    if prefix_cmp_encoded(k, b, &self.lo)
                        == std::cmp::Ordering::Equal =>
                {
                    // keep going because we wanted to exclude
                    // this key.
                    continue;
                }
                _ => {}
            }
            let decoded_key = prefix_decode(&self.lo, &k);
            return Some((IVec::from(decoded_key), v.clone()));
        }
        None
    }

    pub(crate) fn leaf_pair_for_key(
        &self,
        key: &[u8],
    ) -> Option<(&IVec, &IVec)> {
        assert!(!self.data.is_index());

        let records = self.data.leaf_ref().unwrap();
        let search = records
            .binary_search_by(|&(ref k, ref _v)| {
                prefix_cmp_encoded(k, key, &self.lo)
            })
            .ok();

        search.map(|idx| (&records[idx].0, &records[idx].1))
    }

    pub(crate) fn should_split(&self) -> bool {
        let threshold = if cfg!(feature = "lock_free_delays") {
            2
        } else if self.data.is_index() {
            256
        } else {
            16
        };

        let size_checks = self.data.len() > threshold;
        let safety_checks = self.merging_child.is_none() && !self.merging;

        size_checks && safety_checks
    }

    pub(crate) fn should_merge(&self) -> bool {
        let threshold = if cfg!(feature = "lock_free_delays") {
            1
        } else if self.data.is_index() {
            64
        } else {
            4
        };

        let size_checks = self.data.len() < threshold;
        let safety_checks = self.merging_child.is_none() && !self.merging;

        size_checks && safety_checks
    }

    pub(crate) fn can_merge_child(&self) -> bool {
        self.merging_child.is_none() && !self.merging
    }

    pub(crate) fn index_next_node(&self, key: &[u8]) -> (usize, PageId) {
        assert!(self.data.is_index());

        let records = self.data.index_ref().unwrap();

        let search = binary_search_lub(records, |&(ref k, ref _v)| {
            prefix_cmp_encoded(k, key, &self.lo)
        });

        // This might be none if ord is Less and we're
        // searching for the empty key
        let index = search.expect("failed to traverse index");

        (index, records[index].1)
    }
}
<commit_msg>small optimization for node iteration<commit_after>use std::{fmt, ops::Bound};

use pagecache::Lazy;

use super::*;

#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub(crate) struct Node {
    pub(crate) data: Data,
    pub(crate) next: Option<PageId>,
    pub(crate) lo: IVec,
    pub(crate) hi: IVec,
    pub(crate) merging_child: Option<PageId>,
    pub(crate) merging: bool,
}

impl fmt::Debug for Node {
    fn fmt(
        &self,
        f: &mut fmt::Formatter<'_>,
    ) -> std::result::Result<(), fmt::Error> {
        let data = self.data.fmt_keys(&self.lo);

        write!(
            f,
            "Node {{ \
             lo: {:?} \
             hi: {:?} \
             next: {:?} \
             merging_child: {:?} \
             merging: {} \
             data: {:?} }}",
            self.lo, self.hi, self.next, self.merging_child, self.merging, data
        )
    }
}

impl Node {
    pub(crate) fn apply(&mut self, frag: &Frag) {
        use self::Frag::*;

        assert!(
            !self.merging,
            "somehow a frag was applied to a node after it was merged"
        );

        match *frag {
            Set(ref k, ref v) => {
                // (when hi is empty, it means it's unbounded)
                if self.hi.is_empty()
                    || prefix_cmp_encoded(k, &self.hi, &self.lo)
                        == std::cmp::Ordering::Less
                {
                    self.set_leaf(k.clone(), v.clone());
                } else {
                    panic!(
                        "tried to consolidate set at key <= hi.\
                         Set({:?}, {:?}) to node {:?}",
                        k, v, self
                    )
                }
            }
            Del(ref k) => {
                // (when hi is empty, it means it's unbounded)
                if self.hi.is_empty()
                    || prefix_cmp_encoded(k, &self.hi, &self.lo)
                        == std::cmp::Ordering::Less
                {
                    self.del_leaf(k);
                } else {
                    panic!("tried to consolidate del at key <= hi")
                }
            }
            Base(_) => panic!("trying to apply a Base to frag {:?}", self),
            ParentMergeIntention(pid) => {
                assert!(
                    self.merging_child.is_none(),
                    "trying to merge {:?} into node {:?} which \
                     is already merging another child",
                    frag,
                    self
                );
                self.merging_child = Some(pid);
            }
            ParentMergeConfirm => {
                assert!(self.merging_child.is_some());
                let merged_child = self.merging_child.take().expect(
                    "we should have a specific \
                     child that was merged if this \
                     frag appears here",
                );
                self.data.parent_merge_confirm(merged_child);
            }
            ChildMergeCap => {
                self.merging = true;
            }
        }
    }

    pub(crate) fn set_leaf(&mut self, key: IVec, val: IVec) {
        if let Data::Leaf(ref mut records) = self.data {
            let search = records.binary_search_by(|(k, _)| prefix_cmp(k, &key));
            match search {
                Ok(idx) => records[idx] = (key, val),
                Err(idx) => records.insert(idx, (key, val)),
            }
        } else {
            panic!("tried to Set a value to an index");
        }
    }

    pub(crate) fn parent_split(&mut self, at: &[u8], to: PageId) -> bool {
        if let Data::Index(ref mut ptrs) = self.data {
            let encoded_sep = prefix_encode(&self.lo, at);
            match ptrs.binary_search_by(|a| prefix_cmp(&a.0, &encoded_sep)) {
                Ok(_) => {
                    debug!(
                        "parent_split skipped because \
                         parent already contains child at split point \
                         due to deep race"
                    );
                    return false;
                }
                Err(idx) => ptrs.insert(idx, (encoded_sep, to)),
            }
        } else {
            panic!("tried to attach a ParentSplit to a Leaf chain");
        }

        true
    }

    pub(crate) fn del_leaf(&mut self, key: &IVec) {
        if let Data::Leaf(ref mut records) = self.data {
            let search = records
                .binary_search_by(|&(ref k, ref _v)| prefix_cmp(k, &*key));
            if let Ok(idx) = search {
                records.remove(idx);
            }
        } else {
            panic!("tried to attach a Del to an Index chain");
        }
    }

    pub(crate) fn split(mut self) -> (Self, Self) {
        let (split, right_data) = self.data.split(&self.lo);
        let rhs = Self {
            data: right_data,
            next: self.next,
            lo: split,
            hi: self.hi.clone(),
            merging_child: None,
            merging: false,
        };

        self.data.drop_gte(&rhs.lo, &self.lo);
        self.hi = rhs.lo.clone();

        // intentionally make this the end to make
        // any issues pop out with setting it
        // correctly after the split.
        self.next = None;

        (self, rhs)
    }

    pub(crate) fn receive_merge(&self, rhs: &Self) -> Self {
        let mut merged = self.clone();
        merged.hi = rhs.hi.clone();
        merged.data.receive_merge(
            rhs.lo.as_ref(),
            merged.lo.as_ref(),
            &rhs.data,
        );
        merged.next = rhs.next;
        merged
    }

    pub(crate) fn contains_upper_bound(&self, bound: &Bound<IVec>) -> bool {
        match bound {
            Bound::Excluded(bound) if self.hi >= *bound => true,
            Bound::Included(bound) if self.hi > *bound => true,
            _ => self.hi.is_empty(),
        }
    }

    pub(crate) fn contains_lower_bound(
        &self,
        bound: &Bound<IVec>,
        is_forward: bool,
    ) -> bool {
        match bound {
            Bound::Excluded(bound)
                if self.lo < *bound || (is_forward && *bound == self.lo) =>
            {
                true
            }
            Bound::Included(bound) if self.lo <= *bound => true,
            Bound::Unbounded if !is_forward => self.hi.is_empty(),
            _ => self.lo.is_empty(),
        }
    }

    pub(crate) fn successor(
        &self,
        bound: &Bound<IVec>,
    ) -> Option<(IVec, IVec)> {
        assert!(!self.data.is_index());

        // This encoding happens this way because
        // keys cannot be lower than the node's lo key.
        let predecessor_key = match bound {
            Bound::Unbounded => prefix_encode(&self.lo, &self.lo),
            Bound::Included(b) => {
                let max = std::cmp::max(b, &self.lo);
                prefix_encode(&self.lo, max)
            }
            Bound::Excluded(b) => {
                let max = std::cmp::max(b, &self.lo);
                prefix_encode(&self.lo, max)
            }
        };

        let records = self.data.leaf_ref().unwrap();
        let search =
            records.binary_search_by(|(k, _)| prefix_cmp(k, &predecessor_key));

        let idx = match search {
            Ok(idx) => idx,
            Err(idx) if idx < records.len() => idx,
            _ => return None,
        };

        for (k, v) in &records[idx..] {
            match bound {
                Bound::Excluded(b)
                    if prefix_cmp_encoded(k, b, &self.lo)
                        == std::cmp::Ordering::Equal =>
                {
                    // keep going because we wanted to exclude
                    // this key.
                    continue;
                }
                _ => {}
            }
            let decoded_key = prefix_decode(&self.lo, &k);
            return Some((IVec::from(decoded_key), v.clone()));
        }

        None
    }

    pub(crate) fn predecessor(
        &self,
        bound: &Bound<IVec>,
    ) -> Option<(IVec, IVec)> {
        static MAX_IVEC: Lazy<IVec, fn() -> IVec> = Lazy::new(init_max_ivec);

        fn init_max_ivec() -> IVec {
            let mut base = vec![255; 1024 * 1024];
            base[0] = 0;
            IVec::from(base)
        }

        assert!(!self.data.is_index());

        // This encoding happens this way because
        // the rightmost (unbounded) node has
        // a hi key represented by the empty slice
        let successor_key = match bound {
            Bound::Unbounded => {
                if self.hi.is_empty() {
                    MAX_IVEC.clone()
                } else {
                    prefix_encode(&self.lo, &self.hi)
                }
            }
            Bound::Included(b) => {
                let min = if self.hi.is_empty() {
                    b
                } else {
                    std::cmp::min(b, &self.hi)
                };
                prefix_encode(&self.lo, min)
            }
            Bound::Excluded(b) => {
                let min = if self.hi.is_empty() {
                    b
                } else {
                    std::cmp::min(b, &self.hi)
                };
                prefix_encode(&self.lo, min)
            }
        };

        let records = self.data.leaf_ref().unwrap();
        let search =
            records.binary_search_by(|(k, _)| prefix_cmp(k, &successor_key));

        let idx = match search {
            Ok(idx) => idx,
            Err(idx) if idx > 0 => idx - 1,
            _ => return None,
        };

        for (k, v) in records[0..=idx].iter().rev() {
            match bound {
                Bound::Excluded(b)
                    if prefix_cmp_encoded(k, b, &self.lo)
                        == std::cmp::Ordering::Equal =>
                {
                    // keep going because we wanted to exclude
                    // this key.
                    continue;
                }
                _ => {}
            }
            let decoded_key = prefix_decode(&self.lo, &k);
            return Some((IVec::from(decoded_key), v.clone()));
        }
        None
    }

    pub(crate) fn leaf_pair_for_key(
        &self,
        key: &[u8],
    ) -> Option<(&IVec, &IVec)> {
        assert!(!self.data.is_index());

        let records = self.data.leaf_ref().unwrap();
        let search = records
            .binary_search_by(|&(ref k, ref _v)| {
                prefix_cmp_encoded(k, key, &self.lo)
            })
            .ok();

        search.map(|idx| (&records[idx].0, &records[idx].1))
    }

    pub(crate) fn should_split(&self) -> bool {
        let threshold = if cfg!(feature = "lock_free_delays") {
            2
        } else if self.data.is_index() {
            256
        } else {
            16
        };

        let size_checks = self.data.len() > threshold;
        let safety_checks = self.merging_child.is_none() && !self.merging;

        size_checks && safety_checks
    }

    pub(crate) fn should_merge(&self) -> bool {
        let threshold = if cfg!(feature = "lock_free_delays") {
            1
        } else if self.data.is_index() {
            64
        } else {
            4
        };

        let size_checks = self.data.len() < threshold;
        let safety_checks = self.merging_child.is_none() && !self.merging;

        size_checks && safety_checks
    }

    pub(crate) fn can_merge_child(&self) -> bool {
        self.merging_child.is_none() && !self.merging
    }

    pub(crate) fn index_next_node(&self, key: &[u8]) -> (usize, PageId) {
        assert!(self.data.is_index());

        let records = self.data.index_ref().unwrap();

        let search = binary_search_lub(records, |&(ref k, ref _v)| {
            prefix_cmp_encoded(k, key, &self.lo)
        });

        // This might be none if ord is Less and we're
        // searching for the empty key
        let index = search.expect("failed to traverse index");

        (index, records[index].1)
    }
}
<|endoftext|>


<commit_before><commit_msg>AcquireError: Add a MaxReferencesExceeded variant<commit_after><|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 Erik Nordstrøm <erik@nordstroem.no>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

use std::fmt;

use cards::Color;
use cards::Color::*;
use cards::Rank;
use cards::Rank::*;

impl fmt::Display for Color
{
    // https://stackoverflow.com/a/45893535
    fn fmt (&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        match *self
        {
            Spades => write!(f, "♠"),
            Hearts => write!(f, "♥"),
            Diamonds => write!(f, "♦"),
            Clubs => write!(f, "♣"),
        }
    }
}

impl fmt::Display for Rank
{
    fn fmt (&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        match *self
        {
            A     => write!(f, "{:-2}", "A"),
            Two   => write!(f, "{:-2}", "2"),
            Three => write!(f, "{:-2}", "3"),
            Four  => write!(f, "{:-2}", "4"),
            Five  => write!(f, "{:-2}", "5"),
            Six   => write!(f, "{:-2}", "6"),
            Seven => write!(f, "{:-2}", "7"),
            Eight => write!(f, "{:-2}", "8"),
            Nine  => write!(f, "{:-2}", "9"),
            Ten   => write!(f, "{:-2}", "10"),
            J     => write!(f, "{:-2}", "J"),
            Q     => write!(f, "{:-2}", "Q"),
            K     => write!(f, "{:-2}", "K"),
        }
    }
}
<commit_msg>Move a comment.<commit_after>/*
 * Copyright (c) 2017 Erik Nordstrøm <erik@nordstroem.no>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

use std::fmt;

use cards::Color;
use cards::Color::*;
use cards::Rank;
use cards::Rank::*;

// https://stackoverflow.com/a/45893535

impl fmt::Display for Color
{
    fn fmt (&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        match *self
        {
            Spades => write!(f, "♠"),
            Hearts => write!(f, "♥"),
            Diamonds => write!(f, "♦"),
            Clubs => write!(f, "♣"),
        }
    }
}

impl fmt::Display for Rank
{
    fn fmt (&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        match *self
        {
            A     => write!(f, "{:-2}", "A"),
            Two   => write!(f, "{:-2}", "2"),
            Three => write!(f, "{:-2}", "3"),
            Four  => write!(f, "{:-2}", "4"),
            Five  => write!(f, "{:-2}", "5"),
            Six   => write!(f, "{:-2}", "6"),
            Seven => write!(f, "{:-2}", "7"),
            Eight => write!(f, "{:-2}", "8"),
            Nine  => write!(f, "{:-2}", "9"),
            Ten   => write!(f, "{:-2}", "10"),
            J     => write!(f, "{:-2}", "J"),
            Q     => write!(f, "{:-2}", "Q"),
            K     => write!(f, "{:-2}", "K"),
        }
    }
}
<|endoftext|>