<commit_before>use truetype::{Result, Tape, Value};

use glyph_transformation::{Coverage, Device};

table! {
    #[doc = "A glyph attachment."]
    pub Attachment { // AttachPoint
        index_count (u16), // PointCount

        indices (Vec<u16>) |this, tape| { // PointIndex
            tape.take_given(this.index_count as usize)
        },
    }
}

table! {
    @position
    #[doc = "A set of glyph attachments."]
    pub Attachments { // AttachList
        coverage_offset (u16), // Coverage
        count           (u16), // GlyphCount

        offsets (Vec<u16>) |this, tape, _| { // AttachPoint
            tape.take_given(this.count as usize)
        },

        coverage (Coverage) |this, tape, position| {
            jump_take!(tape, position, this.coverage_offset)
        },

        records (Vec<Attachment>) |this, tape, position| {
            jump_take!(tape, position, this.count, this.offsets)
        },
    }
}

/// A ligature-caret value.
#[derive(Clone, Debug)]
pub enum Caret {
    /// Format 1.
    Format1(Caret1),
    /// Format 2.
    Format2(Caret2),
    /// Format 3.
    Format3(Caret3),
}

table! {
    /// A ligature caret in format 1.
    #[derive(Copy)]
    pub Caret1 {
        format     (u16) = { 1 }, // CaretValueFormat
        coordinate (i16), // Coordinate
    }
}

table! {
    /// A ligature caret in format 2.
    #[derive(Copy)]
    pub Caret2 {
        format (u16) = { 2 }, // CaretValueFormat
        index  (u16), // CaretValuePoint
    }
}

table! {
    @position
    /// A ligature caret in format 3.
    pub Caret3 {
        format        (u16) = { 3 }, // CaretValueFormat
        coordinate    (i16), // Coordinate
        device_offset (u16), // DeviceTable

        device (Device) |this, tape, position| {
            jump_take!(tape, position, this.device_offset)
        },
    }
}

table! {
    @position
    #[doc = "A ligature."]
    pub Ligature { // LigGlyph
        caret_count (u16), // CaretCount

        caret_offsets (Vec<u16>) |this, tape, _| { // CaretValue
            tape.take_given(this.caret_count as usize)
        },

        carets (Vec<Caret>) |this, tape, position| {
            jump_take!(tape, position, this.caret_count, this.caret_offsets)
        },
    }
}

table! {
    @position
    #[doc = "A set of ligatures."]
    pub Ligatures { // LigatureCaretList
        coverage_offset (u16), // Coverage
        count           (u16), // LigGlyphCount

        offsets (Vec<u16>) |this, tape, _| { // LigGlyph
            tape.take_given(this.count as usize)
        },

        coverage (Coverage) |this, tape, position| {
            jump_take!(tape, position, this.coverage_offset)
        },

        records (Vec<Ligature>) |this, tape, position| {
            jump_take!(tape, position, this.count, this.offsets)
        },
    }
}

table! {
    @position
    #[doc = "A set of marks."]
    pub Marks { // MarkGlyphSetsTable
        format (u16) = { 1 }, // MarkSetTableFormat
        count  (u16), // MarkSetCount

        coverage_offsets (Vec<u32>) |this, tape, _| { // Coverage
            tape.take_given(this.count as usize)
        },

        coverages (Vec<Coverage>) |this, tape, position| {
            jump_take!(tape, position, this.count, this.coverage_offsets)
        },
    }
}

impl Value for Caret {
    fn read<T: Tape>(tape: &mut T) -> Result<Self> {
        Ok(match try!(tape.peek::<u32>()) {
            1 => Caret::Format1(try!(tape.take())),
            2 => Caret::Format2(try!(tape.take())),
            3 => Caret::Format3(try!(tape.take())),
            _ => raise!("found an unknown format of the caret-value table"),
        })
    }
}
<commit_msg>Fix a description<commit_after>use truetype::{Result, Tape, Value};

use glyph_transformation::{Coverage, Device};

table! {
    #[doc = "A glyph attachment."]
    pub Attachment { // AttachPoint
        index_count (u16), // PointCount

        indices (Vec<u16>) |this, tape| { // PointIndex
            tape.take_given(this.index_count as usize)
        },
    }
}

table! {
    @position
    #[doc = "A set of glyph attachments."]
    pub Attachments { // AttachList
        coverage_offset (u16), // Coverage
        count           (u16), // GlyphCount

        offsets (Vec<u16>) |this, tape, _| { // AttachPoint
            tape.take_given(this.count as usize)
        },

        coverage (Coverage) |this, tape, position| {
            jump_take!(tape, position, this.coverage_offset)
        },

        records (Vec<Attachment>) |this, tape, position| {
            jump_take!(tape, position, this.count, this.offsets)
        },
    }
}

/// A ligature caret.
#[derive(Clone, Debug)]
pub enum Caret {
    /// Format 1.
    Format1(Caret1),
    /// Format 2.
    Format2(Caret2),
    /// Format 3.
    Format3(Caret3),
}

table! {
    /// A ligature caret in format 1.
    #[derive(Copy)]
    pub Caret1 {
        format     (u16) = { 1 }, // CaretValueFormat
        coordinate (i16), // Coordinate
    }
}

table! {
    /// A ligature caret in format 2.
    #[derive(Copy)]
    pub Caret2 {
        format (u16) = { 2 }, // CaretValueFormat
        index  (u16), // CaretValuePoint
    }
}

table! {
    @position
    /// A ligature caret in format 3.
    pub Caret3 {
        format        (u16) = { 3 }, // CaretValueFormat
        coordinate    (i16), // Coordinate
        device_offset (u16), // DeviceTable

        device (Device) |this, tape, position| {
            jump_take!(tape, position, this.device_offset)
        },
    }
}

table! {
    @position
    #[doc = "A ligature."]
    pub Ligature { // LigGlyph
        caret_count (u16), // CaretCount

        caret_offsets (Vec<u16>) |this, tape, _| { // CaretValue
            tape.take_given(this.caret_count as usize)
        },

        carets (Vec<Caret>) |this, tape, position| {
            jump_take!(tape, position, this.caret_count, this.caret_offsets)
        },
    }
}

table! {
    @position
    #[doc = "A set of ligatures."]
    pub Ligatures { // LigatureCaretList
        coverage_offset (u16), // Coverage
        count           (u16), // LigGlyphCount

        offsets (Vec<u16>) |this, tape, _| { // LigGlyph
            tape.take_given(this.count as usize)
        },

        coverage (Coverage) |this, tape, position| {
            jump_take!(tape, position, this.coverage_offset)
        },

        records (Vec<Ligature>) |this, tape, position| {
            jump_take!(tape, position, this.count, this.offsets)
        },
    }
}

table! {
    @position
    #[doc = "A set of marks."]
    pub Marks { // MarkGlyphSetsTable
        format (u16) = { 1 }, // MarkSetTableFormat
        count  (u16), // MarkSetCount

        coverage_offsets (Vec<u32>) |this, tape, _| { // Coverage
            tape.take_given(this.count as usize)
        },

        coverages (Vec<Coverage>) |this, tape, position| {
            jump_take!(tape, position, this.count, this.coverage_offsets)
        },
    }
}

impl Value for Caret {
    fn read<T: Tape>(tape: &mut T) -> Result<Self> {
        Ok(match try!(tape.peek::<u32>()) {
            1 => Caret::Format1(try!(tape.take())),
            2 => Caret::Format2(try!(tape.take())),
            3 => Caret::Format3(try!(tape.take())),
            _ => raise!("found an unknown format of the caret-value table"),
        })
    }
}
<|endoftext|>


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

use std::gc::Gc;
use syntax::ast::TokenTree;
use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::{ToTokens, ExtParseUtils};

use node;
use super::PlatformContext;

pub fn process_nodes(pcx: &mut PlatformContext, ecx: &ExtCtxt, nodes: &Vec<Gc<node::Node>>) {
  for n in nodes.iter() {
    let path = n.path.path.get(0).as_slice();
    match path {
      "clock" => process_clock(pcx, ecx, n),
      other => ecx.span_err(
          n.path.span.unwrap(),
          format!("unknown subnode `{}` in lpc17xx mcu", other).as_slice()),
    }
  }
}

struct TokenSource {
  pub s: String,
}

impl ToTokens for TokenSource {
  fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
    (cx as &ExtParseUtils).parse_tts(self.s.clone())
  }
}

fn process_clock(pcx: &mut PlatformContext, ecx: &ExtCtxt, node: &Gc<node::Node>) {
  if node.path.path.len() != 1 {
    ecx.span_err(node.path.span.unwrap(), "node lpc17xx::clock is final");
    return
  }

  let some_source = node.unwrap_string(ecx, "source");
  let some_pll_m = node.unwrap_int(ecx, "pll_m");
  let some_pll_n = node.unwrap_int(ecx, "pll_n");
  let some_pll_divisor = node.unwrap_int(ecx, "pll_divisor");

  if some_source == None || some_pll_m == None || some_pll_m == None ||
      some_pll_divisor == None {
    return
  }

  let source = some_source.unwrap();
  let pll_m = some_pll_m.unwrap();
  let pll_n = some_pll_n.unwrap();
  let pll_divisor = some_pll_divisor.unwrap();

  let token_source = TokenSource { s: match source.as_slice() {
    "internal-oscillator" => "zinc::hal::lpc17xx::init::Internal".to_str(),
    "main-oscillator"     => {
      let source_frequency = node.unwrap_int(ecx, "source_frequency");
      if source_frequency == None {
        return
      }
      format!("zinc::hal::lpc17xx::init::Main({})", source_frequency)
    }
    "rtc-oscillator"      => "zinc::hal::lpc17xx::init::RTC".to_str(),
    other => {
      ecx.span_err(
          node.path.span.unwrap(), // TODO: span
          format!("unknown oscillator value `{}`", other).as_slice());
      return
    },
  }};

  let ex = quote_expr!(&*ecx,
      zinc::hal::lpc17xx::init::init_clock(
          zinc::hal::lpc17xx::init::Clock {
            source: $token_source,
            pll: zinc::hal::lpc17xx::init::PLL0 {
              enabled: true,
              m: $pll_m,
              n: $pll_n,
              divisor: $pll_divisor,
            }
          }
      );
  );
  pcx.add_main_statement(ecx.stmt_expr(ex));
}
<commit_msg>Added some comments on what’s going on.<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::gc::Gc;
use syntax::ast::TokenTree;
use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::{ToTokens, ExtParseUtils};

use node;
use super::PlatformContext;

/// Entry point for parsing an mcu node.
///
/// Arguments:
///   pcx:   PlatformContext, used to generate any static items in
///          mod platformtree
///   ecx:   ExtCtxt for building ASTs
///   nodes: a vector of nodes inside of the mcu node.
pub fn process_nodes(pcx: &mut PlatformContext, ecx: &ExtCtxt, nodes: &Vec<Gc<node::Node>>) {
  for n in nodes.iter() {
    let path = n.path.path.get(0).as_slice();
    match path {
      "clock" => process_clock(pcx, ecx, n),
      other => ecx.span_err(
          n.path.span.unwrap(),
          format!("unknown subnode `{}` in lpc17xx mcu", other).as_slice()),
    }
  }
}

/// A simple wrapper to allow custom tokenization of ClockSource
struct TokenSource {
  pub s: String,
}

impl ToTokens for TokenSource {
  fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
    (cx as &ExtParseUtils).parse_tts(self.s.clone())
  }
}

/// Parses @clock node into pll init code.
fn process_clock(pcx: &mut PlatformContext, ecx: &ExtCtxt, node: &Gc<node::Node>) {
  if node.path.path.len() != 1 {
    ecx.span_err(node.path.span.unwrap(), "node lpc17xx::clock is final");
    return
  }

  let some_source = node.unwrap_string(ecx, "source");
  let some_pll_m = node.unwrap_int(ecx, "pll_m");
  let some_pll_n = node.unwrap_int(ecx, "pll_n");
  let some_pll_divisor = node.unwrap_int(ecx, "pll_divisor");

  if some_source == None || some_pll_m == None || some_pll_m == None ||
      some_pll_divisor == None {
    return
  }

  let source = some_source.unwrap();
  let pll_m = some_pll_m.unwrap();
  let pll_n = some_pll_n.unwrap();
  let pll_divisor = some_pll_divisor.unwrap();

  let token_source = TokenSource { s: match source.as_slice() {
    "internal-oscillator" => "zinc::hal::lpc17xx::init::Internal".to_str(),
    "main-oscillator"     => {
      let source_frequency = node.unwrap_int(ecx, "source_frequency");
      if source_frequency == None {
        return
      }
      format!("zinc::hal::lpc17xx::init::Main({})", source_frequency)
    }
    "rtc-oscillator"      => "zinc::hal::lpc17xx::init::RTC".to_str(),
    other => {
      ecx.span_err(
          node.path.span.unwrap(), // TODO: span
          format!("unknown oscillator value `{}`", other).as_slice());
      return
    },
  }};

  let ex = quote_expr!(&*ecx,
      zinc::hal::lpc17xx::init::init_clock(
          zinc::hal::lpc17xx::init::Clock {
            source: $token_source,
            pll: zinc::hal::lpc17xx::init::PLL0 {
              enabled: true,
              m: $pll_m,
              n: $pll_n,
              divisor: $pll_divisor,
            }
          }
      );
  );
  pcx.add_main_statement(ecx.stmt_expr(ex));
}
<|endoftext|>


<commit_before>use header::{Header, HeaderFormat};
use std::fmt;
use std::str::FromStr;
use header::parsing::{from_comma_delimited, fmt_comma_delimited};

pub use self::ConnectionOption::{KeepAlive, Close, ConnectionHeader};

/// The `Connection` header.
#[derive(Clone, PartialEq, Debug)]
pub struct Connection(pub Vec<ConnectionOption>);

deref!(Connection => Vec<ConnectionOption>);

/// Values that can be in the `Connection` header.
#[derive(Clone, PartialEq, Debug)]
pub enum ConnectionOption {
    /// The `keep-alive` connection value.
    KeepAlive,
    /// The `close` connection value.
    Close,
    /// Values in the Connection header that are supposed to be names of other Headers.
    ///
    /// > When a header field aside from Connection is used to supply control
    /// > information for or about the current connection, the sender MUST list
    /// > the corresponding field-name within the Connection header field.
    // TODO: it would be nice if these "Strings" could be stronger types, since
    // they are supposed to relate to other Header fields (which we have strong
    // types for).
    ConnectionHeader(String),
}

impl FromStr for ConnectionOption {
    fn from_str(s: &str) -> Option<ConnectionOption> {
        match s {
            "keep-alive" => Some(KeepAlive),
            "close" => Some(Close),
            s => Some(ConnectionHeader(s.to_string()))
        }
    }
}

impl fmt::Display for ConnectionOption {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}", match *self {
            KeepAlive => "keep-alive",
            Close => "close",
            ConnectionHeader(ref s) => s.as_slice()
        })
    }
}

impl Header for Connection {
    fn header_name() -> &'static str {
        "Connection"
    }

    fn parse_header(raw: &[Vec<u8>]) -> Option<Connection> {
        from_comma_delimited(raw).map(|vec| Connection(vec))
    }
}

impl HeaderFormat for Connection {
    fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let Connection(ref parts) = *self;
        fmt_comma_delimited(fmt, &parts[])
    }
}

bench_header!(close, Connection, { vec![b"close".to_vec()] });
bench_header!(keep_alive, Connection, { vec![b"keep-alive".to_vec()] });
bench_header!(header, Connection, { vec![b"authorization".to_vec()] });

<commit_msg>fix(headers): make ConnectionHeader unicase<commit_after>use header::{Header, HeaderFormat};
use std::fmt;
use std::str::FromStr;
use header::parsing::{from_comma_delimited, fmt_comma_delimited};
use unicase::UniCase;

pub use self::ConnectionOption::{KeepAlive, Close, ConnectionHeader};

/// The `Connection` header.
#[derive(Clone, PartialEq, Debug)]
pub struct Connection(pub Vec<ConnectionOption>);

deref!(Connection => Vec<ConnectionOption>);

/// Values that can be in the `Connection` header.
#[derive(Clone, PartialEq, Debug)]
pub enum ConnectionOption {
    /// The `keep-alive` connection value.
    KeepAlive,
    /// The `close` connection value.
    Close,
    /// Values in the Connection header that are supposed to be names of other Headers.
    ///
    /// > When a header field aside from Connection is used to supply control
    /// > information for or about the current connection, the sender MUST list
    /// > the corresponding field-name within the Connection header field.
    // TODO: it would be nice if these "Strings" could be stronger types, since
    // they are supposed to relate to other Header fields (which we have strong
    // types for).
    ConnectionHeader(UniCase<String>),
}

impl FromStr for ConnectionOption {
    fn from_str(s: &str) -> Option<ConnectionOption> {
        match s {
            "keep-alive" => Some(KeepAlive),
            "close" => Some(Close),
            s => Some(ConnectionHeader(UniCase(s.to_string())))
        }
    }
}

impl fmt::Display for ConnectionOption {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}", match *self {
            KeepAlive => "keep-alive",
            Close => "close",
            ConnectionHeader(UniCase(ref s)) => s.as_slice()
        })
    }
}

impl Header for Connection {
    fn header_name() -> &'static str {
        "Connection"
    }

    fn parse_header(raw: &[Vec<u8>]) -> Option<Connection> {
        from_comma_delimited(raw).map(|vec| Connection(vec))
    }
}

impl HeaderFormat for Connection {
    fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let Connection(ref parts) = *self;
        fmt_comma_delimited(fmt, &parts[])
    }
}

bench_header!(close, Connection, { vec![b"close".to_vec()] });
bench_header!(keep_alive, Connection, { vec![b"keep-alive".to_vec()] });
bench_header!(header, Connection, { vec![b"authorization".to_vec()] });

<|endoftext|>


<commit_before>use index::btree::internal::InNode;
use index::btree::{NodeCellRef, NodeWriteGuard, write_node, BPlusTree, NodeData};
use index::{EntryKey, Slice};
use std::fmt::Debug;

pub fn is_node_serial<KS, PS>(node: &NodeWriteGuard<KS, PS>) -> bool
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    // check keys
    for i in 0..node.len() {
        if node.keys()[i] <= smallvec!() {
            error!("EMPTY KEY DETECTED !!!");
            return false;
        }
    }
    for i in 1..node.len() {
        if node.keys()[i - 1] >= node.keys()[i] {
            error!("serial check failed for key ordering");
            return false;
        }
    }
    true
}

pub fn is_node_list_serial<KS, PS>(nodes: &Vec<NodeWriteGuard<KS, PS>>) -> bool
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    if nodes.len() == 0 {
        return true;
    }
    for (i, n) in nodes.iter().enumerate() {
        if !is_node_serial(n) {
            error!("node at {} not serial", i);
            return false;
        }
    }

    // check right ref
    for i in 0..nodes.len() - 1 {
        let first_right_bound = nodes[i].right_bound();
        let second_first_node = nodes[i + 1].first_key();
        let second_right_bound = nodes[i + 1].right_bound();
        if first_right_bound >= second_right_bound {
            error!("right bound at {} larger than right right bound", i);
            return false;
        }
        if first_right_bound > second_first_node {
            error!("right bound at {} larger than right first node", i);
            return false;
        }
    }
    return true;
}

pub fn is_node_level_serial<KS, PS>(mut node: NodeWriteGuard<KS, PS>, lsm_level: usize, tree_level: usize) -> bool
    where
        KS: Slice<EntryKey> + Debug + 'static,
        PS: Slice<NodeCellRef> + 'static,
{
    loop {
        let right_ref = node.right_ref().unwrap();
        let right_bound = node.right_bound();
        if !is_node_serial(&node) {
            error!("Node not serial - {} - {}", lsm_level, tree_level);
            return false;
        }
        if node.first_key() > right_bound {
            error!("Node have right key smaller than the first - {} - {}", lsm_level, tree_level);
            return false;
        }
        if node.last_key() > right_bound {
            error!("Node have right key smaller than the last - {} - {}", lsm_level, tree_level);
            return false;
        }
        let next = write_node(right_ref);
        if next.is_none() {
            debug!("Node level check reached non node - {} - {}", lsm_level, tree_level);
            return true;
        }
        if next.first_key() < right_bound {
            error!("next first key smaller than right bound - {} - {}, type {}. Left keys {:?}, right keys {:?}, right bound {:?}, next right bound {:?}",
                   lsm_level, tree_level, node.type_name(), node.keys(), next.keys(), node.right_bound(), next.right_bound());
            return false;
        }
        if next.right_bound() < right_bound {
            error!("next right bound key smaller than right bound - {} - {}", lsm_level, tree_level);
            return false
        }
        node = next;
    }
}

pub fn is_tree_in_order<KS, PS>(tree: &BPlusTree<KS, PS>, level: usize) -> bool
    where
        KS: Slice<EntryKey> + Debug + 'static,
        PS: Slice<NodeCellRef> + 'static,
{
    return ensure_level_in_order::<KS, PS>(&tree.get_root(), level, 0);
}

fn ensure_level_in_order<KS, PS>(node: &NodeCellRef, lsm_level: usize, tree_level: usize) -> bool
    where
        KS: Slice<EntryKey> + Debug + 'static,
        PS: Slice<NodeCellRef> + 'static,
{
    let first_node = write_node::<KS, PS>(&node);
    let sub_ref = match &*first_node {
        &NodeData::Internal(ref n) => Some(n.ptrs.as_slice_immute()[0].clone()),
        _ => None
    };
    if !is_node_level_serial(first_node, lsm_level, tree_level) {
        return false;
    }
    if let Some(sub_level) = sub_ref {
        return ensure_level_in_order::<KS, PS>(&sub_level, lsm_level, tree_level + 1);
    }
    return true;
}<commit_msg>take account of empty node in validations<commit_after>use index::btree::internal::InNode;
use index::btree::{NodeCellRef, NodeWriteGuard, write_node, BPlusTree, NodeData};
use index::{EntryKey, Slice};
use std::fmt::Debug;

pub fn is_node_serial<KS, PS>(node: &NodeWriteGuard<KS, PS>) -> bool
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    // check keys
    for i in 0..node.len() {
        if node.keys()[i] <= smallvec!() {
            error!("EMPTY KEY DETECTED !!!");
            return false;
        }
    }
    for i in 1..node.len() {
        if node.keys()[i - 1] >= node.keys()[i] {
            error!("serial check failed for key ordering");
            return false;
        }
    }
    true
}

pub fn is_node_list_serial<KS, PS>(nodes: &Vec<NodeWriteGuard<KS, PS>>) -> bool
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    if nodes.len() == 0 {
        return true;
    }
    for (i, n) in nodes.iter().enumerate() {
        if !is_node_serial(n) {
            error!("node at {} not serial", i);
            return false;
        }
    }

    // check right ref
    for i in 0..nodes.len() - 1 {
        let first_right_bound = nodes[i].right_bound();
        let second_first_node = nodes[i + 1].first_key();
        let second_right_bound = nodes[i + 1].right_bound();
        if first_right_bound >= second_right_bound {
            error!("right bound at {} larger than right right bound", i);
            return false;
        }
        if first_right_bound > second_first_node {
            error!("right bound at {} larger than right first node", i);
            return false;
        }
    }
    return true;
}

pub fn is_node_level_serial<KS, PS>(mut node: NodeWriteGuard<KS, PS>, lsm_level: usize, tree_level: usize) -> bool
    where
        KS: Slice<EntryKey> + Debug + 'static,
        PS: Slice<NodeCellRef> + 'static,
{
    loop {
        let right_ref = node.right_ref().unwrap();
        let right_bound = if !node.is_empty_node() {
            let right_bound = node.right_bound();
            if !is_node_serial(&node) {
                error!("Node not serial - {} - {}", lsm_level, tree_level);
                return false;
            }
            if node.first_key() > right_bound {
                error!("Node have right key smaller than the first - {} - {}", lsm_level, tree_level);
                return false;
            }
            if node.last_key() > right_bound {
                error!("Node have right key smaller than the last - {} - {}", lsm_level, tree_level);
                return false;
            }
            right_bound
        } else {
            unreachable!()
        };
        let next = write_node(right_ref);
        if next.is_none() {
            debug!("Node level check reached non node - {} - {}", lsm_level, tree_level);
            return true;
        }
        if !next.is_empty_node() {
            if next.first_key() < right_bound {
                error!("next first key smaller than right bound - {} - {}, type {}. Left keys {:?}, right keys {:?}, right bound {:?}, next right bound {:?}",
                       lsm_level, tree_level, node.type_name(), node.keys(), next.keys(), node.right_bound(), next.right_bound());
                return false;
            }
            if next.right_bound() < right_bound {
                error!("next right bound key smaller than right bound - {} - {}", lsm_level, tree_level);
                return false
            }
        }
        node = next;
    }
}

pub fn is_tree_in_order<KS, PS>(tree: &BPlusTree<KS, PS>, level: usize) -> bool
    where
        KS: Slice<EntryKey> + Debug + 'static,
        PS: Slice<NodeCellRef> + 'static,
{
    return ensure_level_in_order::<KS, PS>(&tree.get_root(), level, 0);
}

fn ensure_level_in_order<KS, PS>(node: &NodeCellRef, lsm_level: usize, tree_level: usize) -> bool
    where
        KS: Slice<EntryKey> + Debug + 'static,
        PS: Slice<NodeCellRef> + 'static,
{
    let first_node = write_node::<KS, PS>(&node);
    let sub_ref = match &*first_node {
        &NodeData::Internal(ref n) => Some(n.ptrs.as_slice_immute()[0].clone()),
        _ => None
    };
    if !is_node_level_serial(first_node, lsm_level, tree_level) {
        return false;
    }
    if let Some(sub_level) = sub_ref {
        return ensure_level_in_order::<KS, PS>(&sub_level, lsm_level, tree_level + 1);
    }
    return true;
}<|endoftext|>


<commit_before>extern crate shootr;

extern crate specs;
extern crate chrono;

use self::specs::{DispatcherBuilder, World};
use self::chrono::prelude::*;

use shootr::engine::{Msg, Engine, EventHandler, Id};
use shootr::ecs::{comp, sys, res};
use shootr::util::read_env_var;
use res::Ids;

use std::sync::{Arc, RwLock};
use std::thread::sleep;
use std::time::Duration;

fn main() {
    shootr::engine::execute::<Handler>();
}
struct Handler {
    engine: Engine,
    ids: Ids,
}
impl EventHandler for Handler {
    fn new(engine: Engine) -> Self {
        Handler {
            engine,
            ids: Ids(Arc::new(RwLock::new(Vec::new()))),
        }
    }
    fn main_loop(&self) {
        let mut world = World::new();
        world.register::<comp::Pos>();
        world.register::<comp::Vel>();
        world.add_resource(self.engine.clone());
        world.add_resource(self.ids.clone());
        for _ in 0..1 {
            world
                .create_entity()
                .with(comp::Vel { x: 3, y: 2 })
                .with(comp::Pos { x: 500, y: 500 })
                .build();
        }

        let mut physics = DispatcherBuilder::new()
            .add(sys::Physics, "physics", &[])
            .build();
        let mut renderer = DispatcherBuilder::new().add(sys::Send, "send", &[]).build();
        physics.dispatch(&mut world.res);

        let mut lag: u64 = 0;
        let mut previous = Utc::now();
        let ms_per_update = read_env_var("CORE_MS_PER_UPDATE").parse::<u64>().expect(
            "Failed to parse environmental variable as integer",
        );

        loop {
            let current = Utc::now();
            let elapsed = elapsed_time(previous, current);
            previous = current;
            lag += elapsed;
            while lag >= ms_per_update {
                physics.dispatch(&mut world.res);
                lag -= ms_per_update;
            }
            let progress = lag as f64 / ms_per_update as f64;
            world.add_resource(res::TimeProgress(progress));
            renderer.dispatch(&mut world.res);
            sleep(Duration::from_millis(ms_per_update - lag));
        }
    }
    fn message(&self, msg: &Msg) {
        println!("Received message: {}", msg.content);
    }
    fn connect(&self, id: Id) -> bool {
        self.ids.write().unwrap().push(id);
        true
    }
    fn disconnect(&self, id: Id) {
        let mut ids = self.ids.write().unwrap();
        let pos = ids.iter().position(|&x| x == id).expect(
            "Tried to remove id that was not added in the first place",
        );

        ids.remove(pos);
    }
}

fn elapsed_time(from: chrono::DateTime<Utc>, to: chrono::DateTime<Utc>) -> u64 {
    to.signed_duration_since(from).num_milliseconds() as u64
}
<commit_msg>Core: Change config from ms/update to updates/sec<commit_after>extern crate shootr;

extern crate specs;
extern crate chrono;

use self::specs::{DispatcherBuilder, World};
use self::chrono::prelude::*;

use shootr::engine::{Msg, Engine, EventHandler, Id};
use shootr::ecs::{comp, sys, res};
use shootr::util::read_env_var;
use res::Ids;

use std::sync::{Arc, RwLock};
use std::thread::sleep;
use std::time::Duration;

fn main() {
    shootr::engine::execute::<Handler>();
}
struct Handler {
    engine: Engine,
    ids: Ids,
}
impl EventHandler for Handler {
    fn new(engine: Engine) -> Self {
        Handler {
            engine,
            ids: Ids(Arc::new(RwLock::new(Vec::new()))),
        }
    }
    fn main_loop(&self) {
        let mut world = World::new();
        world.register::<comp::Pos>();
        world.register::<comp::Vel>();
        world.add_resource(self.engine.clone());
        world.add_resource(self.ids.clone());
        for _ in 0..1 {
            world
                .create_entity()
                .with(comp::Vel { x: 8, y: 6 })
                .with(comp::Pos { x: 500, y: 500 })
                .build();
        }

        let mut physics = DispatcherBuilder::new()
            .add(sys::Physics, "physics", &[])
            .build();
        let mut renderer = DispatcherBuilder::new().add(sys::Send, "send", &[]).build();
        physics.dispatch(&mut world.res);

        let mut lag: u64 = 0;
        let mut previous = Utc::now();
        let updates_per_sec = read_env_var("CORE_UPDATES_PER_SEC").parse::<u64>().expect(
            "Failed to parse environmental variable as integer",
        );
        let ms_per_update = 1000 / updates_per_sec;
        loop {
            let current = Utc::now();
            let elapsed = elapsed_time(previous, current);
            previous = current;
            lag += elapsed;
            while lag >= ms_per_update {
                physics.dispatch(&mut world.res);
                lag -= ms_per_update;
            }
            let progress = lag as f64 / ms_per_update as f64;
            world.add_resource(res::TimeProgress(progress));
            renderer.dispatch(&mut world.res);
            sleep(Duration::from_millis(ms_per_update - lag));
        }
    }
    fn message(&self, msg: &Msg) {
        println!("Received message: {}", msg.content);
    }
    fn connect(&self, id: Id) -> bool {
        self.ids.write().unwrap().push(id);
        true
    }
    fn disconnect(&self, id: Id) {
        let mut ids = self.ids.write().unwrap();
        let pos = ids.iter().position(|&x| x == id).expect(
            "Tried to remove id that was not added in the first place",
        );

        ids.remove(pos);
    }
}

fn elapsed_time(from: chrono::DateTime<Utc>, to: chrono::DateTime<Utc>) -> u64 {
    to.signed_duration_since(from).num_milliseconds() as u64
}
<|endoftext|>


<commit_before>use petgraph::graph::NodeIndex;
use uuid::Uuid;
use super::super::LayoutTree;
use super::super::core::container::{Container, ContainerType};
use ::debug_enabled;

// TODO This module needs to be updated like the other modules...
// Need to add some errors for this (such as when trying to move a non-container/view,
// or when trying to grab a workspace whos name already exists)
//
// Also the code is generally pretty crap, cause it's pretty old (mid-2016)

impl LayoutTree {
    /// Gets a workspace by name or creates it
    fn get_or_make_workspace(&mut self, name: &str) -> NodeIndex {
        let active_index = self.tree.follow_path_until(self.tree.root_ix(),
                                                      ContainerType::Output)
            .expect("get_or_make_wksp: Couldn't get output");
        let workspace_ix = self.tree.workspace_ix_by_name(name).unwrap_or_else(|| {
            let root_ix = self.init_workspace(name.to_string(), active_index);
            self.tree.parent_of(root_ix)
                .expect("Workspace was not properly initialized with a root container")
        });
        self.validate();
        workspace_ix
    }

    /// Initializes a workspace and gets the index of the root container
    pub fn init_workspace(&mut self, name: String, output_ix: NodeIndex)
                      -> NodeIndex {
        let geometry = self.tree.get(output_ix)
            .expect("init_workspace: invalid output").get_geometry()
            .expect("init_workspace: no geometry for output");
        let worksp = Container::new_workspace(name.to_string(), geometry);

        trace!("Adding workspace {:?}", worksp);
        let worksp_ix = self.tree.add_child(output_ix, worksp, false);
        let container_ix = self.tree.add_child(worksp_ix,
                                               Container::new_container(geometry), false);
        self.tree.set_ancestor_paths_active(container_ix);
        self.validate();
        container_ix
    }

    /// Switch to the specified workspace
    pub fn switch_to_workspace(&mut self, name: &str) {
        let maybe_active_ix = self.active_container
            .or_else(|| {
                let new_active = self.tree.follow_path(self.tree.root_ix());
                match self.tree[new_active].get_type() {
                    ContainerType::View | ContainerType::Container => {
                        Some(new_active)
                    },
                    // else try and get the root container
                    _ => self.tree.descendant_of_type(new_active, ContainerType::Container).ok()
                }
            });
        if maybe_active_ix.is_none() {
            warn!("{:#?}", self);
            warn!("No active container, cannot switch");
            return;
        }
        let active_ix = maybe_active_ix.unwrap();
        // Get the old (current) workspace
        let old_worksp_ix: NodeIndex;
        if let Ok(index) = self.tree.ancestor_of_type(active_ix, ContainerType::Workspace) {
            old_worksp_ix = index;
            trace!("Switching to workspace {}", name);
        } else {
            match self.tree[active_ix].get_type() {
                ContainerType::Workspace => {
                    old_worksp_ix = active_ix;
                    trace!("Switching to workspace {}", name);
                },
                _ => {
                    warn!("Could not find old workspace, could not set invisible");
                    return;
                }
            }
        }
        // Get the new workspace, or create one if it doesn't work
        let mut workspace_ix = self.get_or_make_workspace(name);
        if old_worksp_ix == workspace_ix {
            return;
        }
        // Set the old one to invisible
        self.tree.set_family_visible(old_worksp_ix, false);
        // Set the new one to visible
        self.tree.set_family_visible(workspace_ix, true);
        // Delete the old workspace if it has no views on it
        self.active_container = None;
        if self.tree.descendant_of_type(old_worksp_ix, ContainerType::View).is_err() {
            let parent_ix = self.tree.parent_of(old_worksp_ix)
                .expect("Workspace had no parent");
            let siblings = self.tree.children_of(parent_ix);
            // Only remove if it's **NOT** the only workspace on the output.
            if siblings.len() > 1 {
                trace!("Removing workspace: {:?}", self.tree[old_worksp_ix].get_name()
                    .expect("Workspace had no name"));
                if let Err(err) = self.remove_workspace(old_worksp_ix) {
                    warn!("Tried to remove empty workspace {:#?}, error: {:?}",
                        old_worksp_ix, err);
                    debug!("{:#?}", self);
                    panic!("Could not remove old workspace");
                }
            }
        }
        workspace_ix = self.tree.workspace_ix_by_name(name)
            .expect("Workspace we just made was deleted!");
        let active_ix = self.tree.follow_path(workspace_ix);
        match self.tree[active_ix].get_type() {
            ContainerType::View  => {
                match self.tree[active_ix] {
                    Container::View { id, ..} => {
                        self.focus_on(id).unwrap_or_else(|_| {
                            warn!("Could not focus on {:?}", id);
                        });
                    },
                    _ => unreachable!()
                }
                self.set_active_node(active_ix)
                    .expect("Could not set new active node");
                self.tree.set_ancestor_paths_active(active_ix);
                self.validate();
                self.validate_path();
                return;
            },
            _ => {
                self.active_container = self.tree
                    .descendant_of_type(active_ix, ContainerType::View)
                    .or_else(|_| self.tree.descendant_of_type(active_ix,
                                                              ContainerType::Container)).ok();
                match self.tree[self.active_container.expect("Workspace had NO children!")] {
                    Container::View { floating, .. } => {
                        if !floating {
                            self.tree.set_ancestor_paths_active(self.active_container.unwrap());
                        } else {
                            let root_c_ix = *self.tree.children_of(workspace_ix).get(0)
                            .expect("The workspace we are switching to had no root container");
                            self.tree.set_ancestor_paths_active(root_c_ix);
                        }
                    },
                    Container::Container { .. } => {
                        self.tree.set_ancestor_paths_active(self.active_container.unwrap());
                    }
                    _ => unreachable!()
                };
            }
        }
        trace!("Focusing on next container");
        self.focus_on_next_container(workspace_ix);
        self.validate();
        self.validate_path();
    }

    /// Moves the active container to a new workspace.
    pub fn send_active_to_workspace(&mut self, name: &str) {
        if let Some(active_ix) = self.active_container {
            let id = self.tree[active_ix].get_id();
            self.send_to_workspace(id, name);
        }
    }
    /// Moves a container to a new workspace
    pub fn send_to_workspace(&mut self, id: Uuid, name: &str) {
        let node_ix = self.tree.lookup_id(id);
        // Ensure focus
        if let Some(active_ix) = node_ix.or(self.active_container) {
            let curr_work_ix = self.active_ix_of(ContainerType::Workspace)
                .expect("send_active: Not currently in a workspace!");
            if active_ix == self.tree.children_of(curr_work_ix)[0] {
                warn!("Tried to move the root container of a workspace, aborting move");
                return;
            }
            let next_work_ix = self.get_or_make_workspace(name);

            // Check if the workspaces are the same
            if next_work_ix == curr_work_ix {
                trace!("Attempted to move a view to the same workspace {}!", name);
                return;
            }
            self.tree.set_family_visible(curr_work_ix, false);

            // Save the parent of this view for focusing
            let maybe_active_parent = self.tree.parent_of(active_ix);

            // Get the root container of the next workspace
            let next_work_children = self.tree.children_of(next_work_ix);
            if cfg!(debug_assertions) || !debug_enabled() {
                assert!(next_work_children.len() == 1,
                        "Next workspace has multiple roots!");
            }
            let next_work_root_ix = next_work_children[0];

            // Move the container
            debug!("Moving container {:?} to workspace {}",
                self.get_active_container(), name);
            self.tree.move_node(active_ix, next_work_root_ix);

            // If it's a fullscreen app, then update the fullscreen lists
            self.transfer_fullscreen(curr_work_ix, next_work_ix, id);

            // Update the active container
            if let Ok(parent_ix) = maybe_active_parent {
                self.tree.set_ancestor_paths_active(parent_ix);
                let ctype = self.tree.node_type(parent_ix).unwrap_or(ContainerType::Root);
                if ctype == ContainerType::Container {
                    self.focus_on_next_container(parent_ix);
                } else {
                    trace!("Send to container invalidated a NodeIndex: {:?} to {:?}",
                    parent_ix, ctype);
                }
                if self.tree.can_remove_empty_parent(parent_ix) {
                    if let Err(err) = self.remove_view_or_container(parent_ix) {
                        error!("{:#?}\nCould not remove {:#?} from tree {:#?}", err, parent_ix, self);
                        panic!("Could not remove empty parent!");
                    }
                }
            }
            else {
                self.focus_on_next_container(curr_work_ix);
            }

            self.tree.set_family_visible(curr_work_ix, true);

            if !self.tree[active_ix].floating() {
                self.normalize_container(active_ix);
            }
        }
        let root_ix = self.tree.root_ix();
        self.layout(root_ix);
        self.validate();
        self.validate_path();
    }

    /// Transfers a fullscreen app from this workspace to another.
    fn transfer_fullscreen(&mut self, cur_work_ix: NodeIndex, next_work_ix: NodeIndex,
                           fullscreen_id: Uuid) {
        if let Some(fullscreen_ids) = self.tree[cur_work_ix].fullscreen_c() {
            if !fullscreen_ids.iter().any(|id| *id == fullscreen_id) {
                return;
            }
        } else {
            return;
        }
        self.tree[cur_work_ix].update_fullscreen_c(fullscreen_id, false)
            .expect("cur_work_ix was not a workspace");
        self.tree[next_work_ix].update_fullscreen_c(fullscreen_id, true)
            .expect("next_work_ix was not a workspace");
    }
}

#[cfg(test)]
mod tests {
    use ::layout::core::tree::tests::basic_tree;

    #[test]
    pub fn switch_empty_workspaces() {
        let mut tree = basic_tree();
        tree.switch_to_workspace("5");
        tree.switch_to_workspace("4");
        tree.switch_to_workspace("5");
        tree.switch_to_workspace("4");
        tree.switch_to_workspace("2");
    }
}
<commit_msg>Changing workspaces focuses correct output<commit_after>use rustwlc::WlcOutput;
use petgraph::graph::NodeIndex;
use uuid::Uuid;
use super::super::LayoutTree;
use super::super::core::container::{Container, ContainerType};
use ::debug_enabled;

// TODO This module needs to be updated like the other modules...
// Need to add some errors for this (such as when trying to move a non-container/view,
// or when trying to grab a workspace whos name already exists)
//
// Also the code is generally pretty crap, cause it's pretty old (mid-2016)

impl LayoutTree {
    /// Gets a workspace by name or creates it
    fn get_or_make_workspace(&mut self, name: &str) -> NodeIndex {
        let active_index = self.tree.follow_path_until(self.tree.root_ix(),
                                                      ContainerType::Output)
            .expect("get_or_make_wksp: Couldn't get output");
        let workspace_ix = self.tree.workspace_ix_by_name(name).unwrap_or_else(|| {
            let root_ix = self.init_workspace(name.to_string(), active_index);
            self.tree.parent_of(root_ix)
                .expect("Workspace was not properly initialized with a root container")
        });
        self.validate();
        workspace_ix
    }

    /// Initializes a workspace and gets the index of the root container
    pub fn init_workspace(&mut self, name: String, output_ix: NodeIndex)
                      -> NodeIndex {
        let geometry = self.tree.get(output_ix)
            .expect("init_workspace: invalid output").get_geometry()
            .expect("init_workspace: no geometry for output");
        let worksp = Container::new_workspace(name.to_string(), geometry);

        trace!("Adding workspace {:?}", worksp);
        let worksp_ix = self.tree.add_child(output_ix, worksp, false);
        let container_ix = self.tree.add_child(worksp_ix,
                                               Container::new_container(geometry), false);
        self.tree.set_ancestor_paths_active(container_ix);
        self.validate();
        container_ix
    }

    /// Switch to the specified workspace
    pub fn switch_to_workspace(&mut self, name: &str) {
        let maybe_active_ix = self.active_container
            .or_else(|| {
                let new_active = self.tree.follow_path(self.tree.root_ix());
                match self.tree[new_active].get_type() {
                    ContainerType::View | ContainerType::Container => {
                        Some(new_active)
                    },
                    // else try and get the root container
                    _ => self.tree.descendant_of_type(new_active, ContainerType::Container).ok()
                }
            });
        if maybe_active_ix.is_none() {
            warn!("{:#?}", self);
            warn!("No active container, cannot switch");
            return;
        }
        let active_ix = maybe_active_ix.unwrap();
        // Get the old (current) workspace
        let old_worksp_ix: NodeIndex;
        if let Ok(index) = self.tree.ancestor_of_type(active_ix, ContainerType::Workspace) {
            old_worksp_ix = index;
            trace!("Switching to workspace {}", name);
        } else {
            match self.tree[active_ix].get_type() {
                ContainerType::Workspace => {
                    old_worksp_ix = active_ix;
                    trace!("Switching to workspace {}", name);
                },
                _ => {
                    warn!("Could not find old workspace, could not set invisible");
                    return;
                }
            }
        }
        // Get the new workspace, or create one if it doesn't work
        let mut workspace_ix = self.get_or_make_workspace(name);
        if old_worksp_ix == workspace_ix {
            return;
        }
        let old_worksp_parent_ix = self.tree.parent_of(old_worksp_ix)
            .expect("Old workspace had no parent");
        let new_worksp_parent_ix = self.tree.parent_of(workspace_ix)
            .expect("New workspace had no parent");
        // Only set the old one to be invisible if new and old share output.
        if new_worksp_parent_ix == old_worksp_parent_ix {
            // Set the old one to invisible
            self.tree.set_family_visible(old_worksp_ix, false);
        }
        // Set the new one to visible
        self.tree.set_family_visible(workspace_ix, true);
        // Focus on the new output
        match self.tree[new_worksp_parent_ix] {
            Container::Output { handle, .. } => {
                WlcOutput::focus(Some(handle))
            },
            _ => unreachable!()
        }
        // Delete the old workspace if it has no views on it
        self.active_container = None;
        if self.tree.descendant_of_type(old_worksp_ix, ContainerType::View).is_err() {
            let siblings = self.tree.children_of(old_worksp_parent_ix);
            // Only remove if it's **NOT** the only workspace on the output.
            if siblings.len() > 1 {
                trace!("Removing workspace: {:?}", self.tree[old_worksp_ix].get_name()
                    .expect("Workspace had no name"));
                if let Err(err) = self.remove_workspace(old_worksp_ix) {
                    warn!("Tried to remove empty workspace {:#?}, error: {:?}",
                        old_worksp_ix, err);
                    debug!("{:#?}", self);
                    panic!("Could not remove old workspace");
                }
            }
        }
        workspace_ix = self.tree.workspace_ix_by_name(name)
            .expect("Workspace we just made was deleted!");
        let active_ix = self.tree.follow_path(workspace_ix);
        match self.tree[active_ix].get_type() {
            ContainerType::View  => {
                match self.tree[active_ix] {
                    Container::View { id, ..} => {
                        self.focus_on(id).unwrap_or_else(|_| {
                            warn!("Could not focus on {:?}", id);
                        });
                    },
                    _ => unreachable!()
                }
                self.set_active_node(active_ix)
                    .expect("Could not set new active node");
                self.tree.set_ancestor_paths_active(active_ix);
                self.validate();
                self.validate_path();
                return;
            },
            _ => {
                self.active_container = self.tree
                    .descendant_of_type(active_ix, ContainerType::View)
                    .or_else(|_| self.tree.descendant_of_type(active_ix,
                                                              ContainerType::Container)).ok();
                match self.tree[self.active_container.expect("Workspace had NO children!")] {
                    Container::View { floating, .. } => {
                        if !floating {
                            self.tree.set_ancestor_paths_active(self.active_container.unwrap());
                        } else {
                            let root_c_ix = *self.tree.children_of(workspace_ix).get(0)
                            .expect("The workspace we are switching to had no root container");
                            self.tree.set_ancestor_paths_active(root_c_ix);
                        }
                    },
                    Container::Container { .. } => {
                        self.tree.set_ancestor_paths_active(self.active_container.unwrap());
                    }
                    _ => unreachable!()
                };
            }
        }
        trace!("Focusing on next container");
        self.focus_on_next_container(workspace_ix);
        self.validate();
        self.validate_path();
    }

    /// Moves the active container to a new workspace.
    pub fn send_active_to_workspace(&mut self, name: &str) {
        if let Some(active_ix) = self.active_container {
            let id = self.tree[active_ix].get_id();
            self.send_to_workspace(id, name);
        }
    }
    /// Moves a container to a new workspace
    pub fn send_to_workspace(&mut self, id: Uuid, name: &str) {
        let node_ix = self.tree.lookup_id(id);
        // Ensure focus
        if let Some(active_ix) = node_ix.or(self.active_container) {
            let curr_work_ix = self.active_ix_of(ContainerType::Workspace)
                .expect("send_active: Not currently in a workspace!");
            if active_ix == self.tree.children_of(curr_work_ix)[0] {
                warn!("Tried to move the root container of a workspace, aborting move");
                return;
            }
            let next_work_ix = self.get_or_make_workspace(name);

            // Check if the workspaces are the same
            if next_work_ix == curr_work_ix {
                trace!("Attempted to move a view to the same workspace {}!", name);
                return;
            }
            self.tree.set_family_visible(curr_work_ix, false);

            // Save the parent of this view for focusing
            let maybe_active_parent = self.tree.parent_of(active_ix);

            // Get the root container of the next workspace
            let next_work_children = self.tree.children_of(next_work_ix);
            if cfg!(debug_assertions) || !debug_enabled() {
                assert!(next_work_children.len() == 1,
                        "Next workspace has multiple roots!");
            }
            let next_work_root_ix = next_work_children[0];

            // Move the container
            debug!("Moving container {:?} to workspace {}",
                self.get_active_container(), name);
            self.tree.move_node(active_ix, next_work_root_ix);

            // If it's a fullscreen app, then update the fullscreen lists
            self.transfer_fullscreen(curr_work_ix, next_work_ix, id);

            // Update the active container
            if let Ok(parent_ix) = maybe_active_parent {
                self.tree.set_ancestor_paths_active(parent_ix);
                let ctype = self.tree.node_type(parent_ix).unwrap_or(ContainerType::Root);
                if ctype == ContainerType::Container {
                    self.focus_on_next_container(parent_ix);
                } else {
                    trace!("Send to container invalidated a NodeIndex: {:?} to {:?}",
                    parent_ix, ctype);
                }
                if self.tree.can_remove_empty_parent(parent_ix) {
                    if let Err(err) = self.remove_view_or_container(parent_ix) {
                        error!("{:#?}\nCould not remove {:#?} from tree {:#?}", err, parent_ix, self);
                        panic!("Could not remove empty parent!");
                    }
                }
            }
            else {
                self.focus_on_next_container(curr_work_ix);
            }

            self.tree.set_family_visible(curr_work_ix, true);

            if !self.tree[active_ix].floating() {
                self.normalize_container(active_ix);
            }
        }
        let root_ix = self.tree.root_ix();
        self.layout(root_ix);
        self.validate();
        self.validate_path();
    }

    /// Transfers a fullscreen app from this workspace to another.
    fn transfer_fullscreen(&mut self, cur_work_ix: NodeIndex, next_work_ix: NodeIndex,
                           fullscreen_id: Uuid) {
        if let Some(fullscreen_ids) = self.tree[cur_work_ix].fullscreen_c() {
            if !fullscreen_ids.iter().any(|id| *id == fullscreen_id) {
                return;
            }
        } else {
            return;
        }
        self.tree[cur_work_ix].update_fullscreen_c(fullscreen_id, false)
            .expect("cur_work_ix was not a workspace");
        self.tree[next_work_ix].update_fullscreen_c(fullscreen_id, true)
            .expect("next_work_ix was not a workspace");
    }
}

#[cfg(test)]
mod tests {
    use ::layout::core::tree::tests::basic_tree;

    #[test]
    pub fn switch_empty_workspaces() {
        let mut tree = basic_tree();
        tree.switch_to_workspace("5");
        tree.switch_to_workspace("4");
        tree.switch_to_workspace("5");
        tree.switch_to_workspace("4");
        tree.switch_to_workspace("2");
    }
}
<|endoftext|>


<commit_before>
use call;
use error::GGRError;
use error::GGRResult;
use gron;
use serde_json;
use regex;
use std::collections::HashMap;

pub struct Changes { }

impl Changes {
    /// Returns a ChangeInfos object on success. This value comes direct from the http call and
    /// is a valid json object
    pub fn query_changes(call: &call::Call, querystring: &str) -> GGRResult<ChangeInfos> {
        if let Ok(cr) = call.get("/changes/".into(), querystring) {
            let body = match cr.body {
                Some(x) => x,
                None => {
                    /* no body content */
                    return Ok(ChangeInfos::new());
                }
            };
            let data2 = try!(String::from_utf8(body));

            let data5 = match serde_json::de::from_str(&data2) {
                Ok(d) => d,
                Err(e) => {
                    println!("error: {}",e);
                    return Err(GGRError::from(e));
                }
            };

            let changeinfos = ChangeInfos::new_with_data(Some(data5));

            return Ok(changeinfos);
        } else {
            println!("call problem with: {}", &querystring);
        }
        Ok(ChangeInfos::new())
    }
}

/// Abstraction for Gron format
struct GronInfo {
    sel: String,
    val: String,
}

impl From<String> for GronInfo {
    /// splits a string of 'a=b' style to `GronInfo { sel:"a", val:"b" }`
    fn from(s: String) -> Self {
        let mut out: GronInfo = GronInfo {
            sel: String::new(),
            val: String::new(),
        };
        let mut v = s.splitn(2, '=');
        out.sel = String::from(v.next().unwrap_or("")).trim().to_string();
        out.val = String::from(v.next().unwrap_or("")).trim().to_string();

        out
    }
}

impl GronInfo {
    /// returns true if Self.sel ends with one element of ew
    pub fn sel_ends_with_one_of(&self, ew: &Vec<String>) -> bool {
        for e in ew {
            if self.sel.ends_with(e) {
                return true;
            }
        }
        false
    }
}

#[derive(Default)]
pub struct ChangeInfos {
    pub json: Option<serde_json::value::Value>,
}

impl ChangeInfos {
    /// creates a new ChangeInfos instance. ChangeInfos.json is None
    pub fn new() -> ChangeInfos {
        ChangeInfos {
            json: None,
        }
    }

    /// creates new ChangeInfos object with an initial ChangeInfos.json value
    pub fn new_with_data(json: Option<serde_json::value::Value>)
    -> ChangeInfos {
        ChangeInfos {
            json: json,
        }
    }

    /// returns the self.json as a array of GronInfo objects
    fn as_selectinfo_array(&self) -> Vec<GronInfo> {
        if let Some(json) = self.json.clone() {
            let mut vec = Vec::new();

            if let Err(x) = gron::json_to_gron(&mut vec, "", &json) {
                println!("error: {}", x);
                return Vec::new();
            };

            let v: Vec<GronInfo> = vec.split(|x| *x == '\n' as u8)
                .map(|chunk| {
                    GronInfo::from(String::from_utf8_lossy(chunk).to_string())
                    })
                .collect();
            return v;
        }
        return Vec::new();
    }

    /// returns a Vec<String> object. Only elements there names ends on one of `selector`s entries
    /// are returned. Is a `selector` entry a '*' all fields are returned.
    pub fn as_string(&self, selector: Vec<String>) -> Vec<String> {
        let vec = self.as_selectinfo_array();
        let mut out: Vec<String> = Vec::new();
        let mut all_fields = false;
        let mut with_object_start = false;

        // manipulate selector to have a '.' in front of all variables.
        let selector = {
            let mut sel_v: Vec<String> = Vec::new();
            for s in &selector {
                // special operators
                if s.eq("*") {
                    all_fields = true;
                }
                if s.eq("+") {
                    with_object_start = true;
                }

                let mut s = s.clone();
                s.insert(0, '.');
                sel_v.push(s);
            }
            sel_v
        };

        // find longest 'sel'
        let mut sel_max_len = 0;
        for v in &vec {
            if v.sel.len() > sel_max_len  && (v.sel_ends_with_one_of(&selector) || all_fields) {
                sel_max_len = v.sel.len();
            }
        }

        for v in &vec {
            if v.sel_ends_with_one_of(&selector) || all_fields {
                if v.sel.is_empty() && v.val.is_empty() || (v.val == "{}" && !with_object_start) {
                    continue;
                }
                out.push(format!("{sel:width_sel$} {val}", sel=v.sel, val=v.val, width_sel=sel_max_len));
            }
        }

        out
    }

    /// prints all selectable fields os a search string
    ///
    /// returns two values. First one is the count of returned json objects and second value is a
    /// HashMap<String, usize> with all fields and gow much they occure.
    pub fn fieldslist(&self) -> (usize, HashMap<String, usize>) {
        let mut out_hmap: HashMap<String, usize> = HashMap::new();
        let mut entries = 0;

        if let Some(obj) = self.json.clone() {
            if let Some(array) = obj.as_array() {
                entries = array.len();
                for entry in array {
                    match *entry {
                        serde_json::value::Value::Object(ref x) => {
                            for key in x.keys() {
                                let counter = out_hmap.entry(key.to_owned()).or_insert(0);
                                *counter += 1;
                            }
                        }
                        _ => continue,
                    }
                }
            } else {
                println!("no array");
            }
        }

        (entries, out_hmap)
    }

    /// return the string in machinereadable format
    pub fn raw(&self) -> String {
        let json = self.json.clone();

        format!("{}", json.unwrap_or(serde_json::value::Value::String("".into())))
    }

    /// return in human readable form
    pub fn human(&self) -> String {
        let json = self.json.clone();

        format!("{}", &serde_json::ser::to_string_pretty(&json.unwrap_or(serde_json::value::Value::String("".into()))).unwrap_or("problem with pretty printing"))
    }
}

<commit_msg>changes: rework gron mechanism<commit_after>
use call;
use error::GGRError;
use error::GGRResult;
use gron;
use serde_json;
use regex;
use std::collections::HashMap;

pub struct Changes { }

impl Changes {
    /// Returns a ChangeInfos object on success. This value comes direct from the http call and
    /// is a valid json object
    pub fn query_changes(call: &call::Call, querystring: &str) -> GGRResult<ChangeInfos> {
        if let Ok(cr) = call.get("/changes/".into(), querystring) {
            let body = match cr.body {
                Some(x) => x,
                None => {
                    /* no body content */
                    return Ok(ChangeInfos::new());
                }
            };
            let data2 = try!(String::from_utf8(body));

            let data5 = match serde_json::de::from_str(&data2) {
                Ok(d) => d,
                Err(e) => {
                    println!("error: {}",e);
                    return Err(GGRError::from(e));
                }
            };

            let changeinfos = ChangeInfos::new_with_data(Some(data5));

            return Ok(changeinfos);
        } else {
            println!("call problem with: {}", &querystring);
        }
        Ok(ChangeInfos::new())
    }
}

/// Abstraction for Gron format into a Key/Val storage tyupe
pub struct KeyValue {
    pub id: String,
    pub key: String,
    pub val: String,
}

impl From<String> for KeyValue {
    /// splits a string of 'a=b' style to `KeyValue { sel:"a", val:"b" }`
    fn from(s: String) -> Self {
        let mut out: KeyValue = KeyValue {
            id: String::new(),
            key: String::new(),
            val: String::new(),
        };

        let re = regex::Regex::new(r"^\[(?P<id>\di*?)].(?P<key>.*)=(?P<val>.*)$").unwrap();
        for cap in re.captures_iter(&s) {
            out.id = cap.name("id").unwrap_or("").trim().into();
            out.key = cap.name("key").unwrap_or("").trim().into();
            out.val = cap.name("val").unwrap_or("").trim().into();
        }

        out
    }
}

impl KeyValue {
    /// returns true if Self.key ends with one element of ew
    fn key_end_with_one_of(&self, ew: &[String]) -> bool {
        for e in ew {
            if self.key.ends_with(e) {
                return true;
            }
        }
        false
    }
}

#[derive(Default, Debug)]
pub struct ChangeInfos {
    pub json: Option<serde_json::value::Value>,
    filter_key: Vec<String>,
    filter_val: Vec<String>,
}

impl ChangeInfos {
    /// creates a new ChangeInfos instance. ChangeInfos.json is None
    pub fn new() -> ChangeInfos {
        ChangeInfos {
            json: None,
            filter_key: Vec::new(),
            filter_val: Vec::new(),
        }
    }

    /// creates new ChangeInfos object with an initial ChangeInfos.json value
    pub fn new_with_data(json: Option<serde_json::value::Value>)
    -> ChangeInfos {
        ChangeInfos {
            json: json,
            filter_key: Vec::new(),
            filter_val: Vec::new(),
        }
    }

    /// returns the self.json as a array of KeyValue objects
    ///
    /// The returned array is filtered through `filter_key`, `filter_val` function
    pub fn as_keyval_array(&self) -> Vec<KeyValue> {
        let mut out = Vec::new();
        if let Some(json) = self.json.clone() {
            let mut vec = Vec::new();

            if let Err(x) = gron::json_to_gron(&mut vec, "", &json) {
                println!("error: {}", x);
                return Vec::new();
            };

            for line in vec.split(|x| *x == b'\n') {
                let kv = KeyValue::from(String::from_utf8_lossy(line).to_string());

                let mut matched = false;
                // key filter
                for r in &self.filter_key {
                    if let Ok(re) = regex::Regex::new(r) {
                        if re.is_match(&kv.key) {
                            matched = true;
                            break;
                        }
                    }
                }

                // val filter
                for r in &self.filter_val {
                    if let Ok(re) = regex::Regex::new(r) {
                        if re.is_match(&kv.val) {
                            matched = true;
                            break;
                        }
                    }
                }

                if matched {
                    out.push(kv);
                }
            }
        }
        out
    }

    /// add a regular expression filter for keys
    ///
    /// The filter needs to be resetted through `filter_reset`.
    pub fn filter_key(&mut self, r: &str) -> &mut Self {
        self.filter_key.push(String::from(r));
        self
    }

    /// add a regular expression filter for values
    ///
    /// The filter needs to be resetted through `filter_reset`.
    pub fn filter_val(&mut self, r: String) -> &mut Self {
        self.filter_val.push(r);
        self
    }

    /// reset key and value filter
    pub fn filter_reset(&mut self) -> &mut Self {
        self.filter_val.clear();
        self.filter_key.clear();
        self
    }

    /// returns a Vec<String> object. Only elements there names ends on one of `selector`s entries
    /// are returned. Is a `selector` entry a '*' all fields are returned.
    pub fn as_string(&self, selector: Vec<String>) -> String {
        let vec = self.as_keyval_array();
        let mut out = String::new();
        let mut all_fields = false;
        let mut with_object_start = false;

        let selector = {
            let mut sel_v: Vec<String> = Vec::new();
            for s in &selector {
                // special operators
                if s.eq("*") {
                    all_fields = true;
                    continue;
                }
                if s.eq("+") {
                    with_object_start = true;
                    continue;
                }
                if s.eq("[]") {
                    continue;
                }

                // manipulate selector to have a '.' in front of all variables.
                let mut s = s.clone();
                s.insert(0, '.');
                sel_v.push(s);
            }
            sel_v
        };

        // find longest 'sel'
        let mut sel_max_len = 0;
        for v in &vec {
            if v.key.len() > sel_max_len  && (v.key_end_with_one_of(&selector) || all_fields) {
                sel_max_len = v.key.len();
            }
        }

        for v in &vec {
            if v.key_end_with_one_of(&selector) || all_fields {
                if v.key.is_empty() && v.val.is_empty() || (v.val == "{}" && !with_object_start) {
                    continue;
                }
                out.push_str(&format!("{sel:width_sel$} {val}\n", sel=v.key, val=v.val, width_sel=sel_max_len));
            }
        }

        out
    }

    pub fn as_string_reg(&self, selector: &str) -> Vec<String> {
        let vec = self.as_keyval_array();
        let mut out: Vec<String> = Vec::new();

        if let Ok(re) = regex::Regex::new(selector) {
            for kv in vec {
                if re.is_match(&kv.key) {
                    out.push(format!("{} {}", kv.key, kv.val));
                }
            }
        }

        out
    }

    /// prints all selectable fields os a search string
    ///
    /// returns two values. First one is the count of returned json objects and second value is a
    /// HashMap<String, usize> with all fields and gow much they occure.
    pub fn fieldslist(&self) -> (usize, HashMap<String, usize>) {
        let mut out_hmap: HashMap<String, usize> = HashMap::new();
        let mut entries = 0;

        if let Some(obj) = self.json.clone() {
            if let Some(array) = obj.as_array() {
                entries = array.len();
                for entry in array {
                    match *entry {
                        serde_json::value::Value::Object(ref x) => {
                            for key in x.keys() {
                                let counter = out_hmap.entry(key.to_owned()).or_insert(0);
                                *counter += 1;
                            }
                        }
                        _ => continue,
                    }
                }
            } else {
                println!("no array");
            }
        }

        (entries, out_hmap)
    }

    /// return the string in machinereadable format
    pub fn raw(&self) -> String {
        let json = self.json.clone();

        format!("{}", json.unwrap_or(serde_json::value::Value::String("".into())))
    }

    /// return in human readable form
    pub fn human(&self) -> String {
        let json = self.json.clone();

        format!("{}", &serde_json::ser::to_string_pretty(&json.unwrap_or(serde_json::value::Value::String("".into()))).unwrap_or("problem with pretty printing"))
    }
}

<|endoftext|>


<commit_before>use toml::Value;

/// Check whether the configuration is valid for the store
///
/// The passed `Value` _must be_ the `[store]` sub-tree of the configuration. Otherwise this will
/// fail.
///
/// It checks whether the configuration looks like the store wants it to be:
///
/// ```toml
/// [store]
/// pre-create-hook-aspects = [ "misc", "encryption", "version-control"]
///
/// [store.aspects.misc]
/// parallel = true
///
/// [store.aspects.encryption]
/// parallel = false
///
/// [store.aspects.version-control]
/// parallel = false
///
/// [store.hooks.gnupg]
/// aspect = "encryption"
/// key = "0x123456789"
///
/// [store.hooks.git]
/// aspect = "version-control"
/// ```
///
/// It checks:
///  * Whether all the maps are there (whether store, store.aspects, store.aspects.example are all
///  maps)
///  * Whether each aspect configuration has a "parallel = <Boolean>" setting
///  * Whether each hook congfiguration has a "aspect = <String>" setting
///
/// It does NOT check:
///  * Whether all aspects which are used in the hook configuration are also configured
///
/// No configuration is a valid configuration, as the store will use the most conservative settings
/// automatically. This has also performance impact, as all hooks run in no-parallel mode then.
/// You have been warned!
///
///
pub fn config_is_valid(config: &Option<Value>) -> bool {
    use std::collections::BTreeMap;
    use std::io::Write;
    use std::io::stderr;

    if config.is_none() {
        return true;
    }

    fn has_key_with_string_ary(v: &BTreeMap<String, Value>, key: &str) -> bool {
        v.get(key)
            .map_or_else(|| {
                write!(stderr(), "Required key '{}' is not in store config", key).ok();
                false
            }, |t| match *t {
                    Value::Array(ref a) => a.iter().all(|elem| {
                        match *elem {
                            Value::String(_) => true,
                            _ => false,
                        }
                    }),
                    _ => {
                        write!(stderr(), "Key '{}' in store config should contain an array", key)
                            .ok();
                        false
                    }
            })
    }

    /// Check that
    /// * the top-level configuration
    /// * is a table
    /// * where all entries of a key `section` (eg. "hooks" or "aspects")
    ///     * Are maps
    ///     * where each has a key `key` (eg. "aspect" or "parallel")
    ///     * which fullfills constraint `f` (typecheck)
    fn check_all_inner_maps_have_key_with<F>(store_config: &BTreeMap<String, Value>,
                                             section: &str,
                                             key: &str,
                                             f: F)
        -> bool
        where F: Fn(&Value) -> bool
    {
        store_config.get(section) // The store config has the section `section`
            .map_or_else(|| {
                write!(stderr(), "Store config expects section '{}' to be present, but isn't.",
                        section).ok();
                false
            }, |section_table| {
                match *section_table { // which is
                    Value::Table(ref section_table) => // a table
                        section_table
                            .iter() // which has values,
                            .all(|(inner_key, cfg)| { // and all of these values
                                match *cfg {
                                    Value::Table(ref hook_config) => { // are tables
                                        hook_config.get(key) // with a key
                                            // fullfilling this constraint
                                            .map_or(false, |hook_aspect| f(&hook_aspect))
                                    },
                                    _ => {
                                        write!(stderr(), "Store config expects '{}' to be in '{}.{}', but isn't.",
                                                 key, section, inner_key).ok();
                                        false
                                    }
                                }
                            }),
                    _ => {
                        write!(stderr(), "Store config expects '{}' to be a Table, but isn't.",
                               section).ok();
                        false
                    }
                }
            })
    }

    match *config {
        Some(Value::Table(ref t)) => {
            has_key_with_string_ary(t, "store-unload-hook-aspects")    &&

            has_key_with_string_ary(t, "pre-create-hook-aspects")      &&
            has_key_with_string_ary(t, "post-create-hook-aspects")     &&
            has_key_with_string_ary(t, "pre-retrieve-hook-aspects")    &&
            has_key_with_string_ary(t, "post-retrieve-hook-aspects")   &&
            has_key_with_string_ary(t, "pre-update-hook-aspects")      &&
            has_key_with_string_ary(t, "post-update-hook-aspects")     &&
            has_key_with_string_ary(t, "pre-delete-hook-aspects")      &&
            has_key_with_string_ary(t, "post-delete-hook-aspects")     &&

            // The section "hooks" has maps which have a key "aspect" which has a value of type
            // String
            check_all_inner_maps_have_key_with(t, "hooks", "aspect",
                                               |asp| is_match!(asp, &Value::String(_))) &&

            // The section "aspects" has maps which have a key "parllel" which has a value of type
            // Boolean
            check_all_inner_maps_have_key_with(t, "aspects", "parallel",
                                               |asp| is_match!(asp, &Value::Boolean(_)))
        }
        _ => {
            write!(stderr(), "Store config is no table").ok();
            false
        },
    }
}

pub fn get_store_unload_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("store-unload-hook-aspects", value)
}

pub fn get_pre_create_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("pre-create-hook-aspects", value)
}

pub fn get_post_create_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("post-create-hook-aspects", value)
}

pub fn get_pre_retrieve_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("pre-retrieve-hook-aspects", value)
}

pub fn get_post_retrieve_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("post-retrieve-hook-aspects", value)
}

pub fn get_pre_update_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("pre-update-hook-aspects", value)
}

pub fn get_post_update_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("post-update-hook-aspects", value)
}

pub fn get_pre_delete_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("pre-delete-hook-aspects", value)
}

pub fn get_post_delete_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("post-delete-hook-aspects", value)
}

pub fn get_pre_move_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("pre-move-hook-aspects", value)
}

pub fn get_post_move_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("post-move-hook-aspects", value)
}

#[derive(Debug)]
pub struct AspectConfig {
    parallel: bool,
    mutable_hooks: bool,
    config: Value,
}

impl AspectConfig {

    pub fn new(init: Value) -> AspectConfig {
        debug!("Trying to parse AspectConfig from: {:?}", init);
        let parallel = AspectConfig::is_parallel(&init);
        let muthooks = AspectConfig::allows_mutable_hooks(&init);
        AspectConfig {
            config: init,
            mutable_hooks: muthooks,
            parallel: parallel,
        }
    }

    fn is_parallel(init: &Value) -> bool {
        match *init {
            Value::Table(ref t) =>
                t.get("parallel")
                    .map_or(false, |value| {
                        match *value {
                            Value::Boolean(b) => b,
                            _ => false,
                        }
                    }),
            _ => false,
        }
    }

    fn allows_mutable_hooks(init: &Value) -> bool {
        match *init {
            Value::Table(ref t) =>
                t.get("mutable_hooks")
                    .map_or(false, |value| {
                        match *value {
                            Value::Boolean(b) => b,
                            _ => false,
                        }
                    }),
            _ => false,
        }
    }

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

    /// Get the aspect configuration for an aspect.
    ///
    /// Pass the store configuration object, this searches in `[aspects][<aspect_name>]`.
    ///
    /// Returns `None` if one of the keys in the chain is not available
    pub fn get_for(v: &Option<Value>, a_name: String) -> Option<AspectConfig> {
        debug!("Get aspect configuration for {:?} from {:?}", a_name, v);
        let res = match *v {
            Some(Value::Table(ref tabl)) => {
                match tabl.get("aspects") {
                    Some(&Value::Table(ref tabl)) => {
                        tabl.get(&a_name[..]).map(|asp| AspectConfig::new(asp.clone()))
                    },

                    _ => None,
                }
            },
            _ => None,
        };
        debug!("Found aspect configuration for {:?}: {:?}", a_name, res);
        res
    }

}

fn get_aspect_names_for_aspect_position(config_name: &'static str, value: &Option<Value>) -> Vec<String> {
    let mut v = vec![];

    match *value {
        Some(Value::Table(ref t)) => {
            match t.get(config_name) {
                Some(&Value::Array(ref a)) => {
                    for elem in a {
                        match *elem {
                            Value::String(ref s) => v.push(s.clone()),
                            _ => warn!("Non-String in configuration, inside '{}'", config_name),
                        }
                    }
                },
                _ => warn!("'{}' configuration key should contain Array, does not", config_name),
            };
        },
        None => warn!("No store configuration"),
        _ => warn!("Configuration is not a table"),
    }
    v
}

<commit_msg>Make warning more verbose, tell what kind of variable cannot be fetched<commit_after>use toml::Value;

/// Check whether the configuration is valid for the store
///
/// The passed `Value` _must be_ the `[store]` sub-tree of the configuration. Otherwise this will
/// fail.
///
/// It checks whether the configuration looks like the store wants it to be:
///
/// ```toml
/// [store]
/// pre-create-hook-aspects = [ "misc", "encryption", "version-control"]
///
/// [store.aspects.misc]
/// parallel = true
///
/// [store.aspects.encryption]
/// parallel = false
///
/// [store.aspects.version-control]
/// parallel = false
///
/// [store.hooks.gnupg]
/// aspect = "encryption"
/// key = "0x123456789"
///
/// [store.hooks.git]
/// aspect = "version-control"
/// ```
///
/// It checks:
///  * Whether all the maps are there (whether store, store.aspects, store.aspects.example are all
///  maps)
///  * Whether each aspect configuration has a "parallel = <Boolean>" setting
///  * Whether each hook congfiguration has a "aspect = <String>" setting
///
/// It does NOT check:
///  * Whether all aspects which are used in the hook configuration are also configured
///
/// No configuration is a valid configuration, as the store will use the most conservative settings
/// automatically. This has also performance impact, as all hooks run in no-parallel mode then.
/// You have been warned!
///
///
pub fn config_is_valid(config: &Option<Value>) -> bool {
    use std::collections::BTreeMap;
    use std::io::Write;
    use std::io::stderr;

    if config.is_none() {
        return true;
    }

    fn has_key_with_string_ary(v: &BTreeMap<String, Value>, key: &str) -> bool {
        v.get(key)
            .map_or_else(|| {
                write!(stderr(), "Required key '{}' is not in store config", key).ok();
                false
            }, |t| match *t {
                    Value::Array(ref a) => a.iter().all(|elem| {
                        match *elem {
                            Value::String(_) => true,
                            _ => false,
                        }
                    }),
                    _ => {
                        write!(stderr(), "Key '{}' in store config should contain an array", key)
                            .ok();
                        false
                    }
            })
    }

    /// Check that
    /// * the top-level configuration
    /// * is a table
    /// * where all entries of a key `section` (eg. "hooks" or "aspects")
    ///     * Are maps
    ///     * where each has a key `key` (eg. "aspect" or "parallel")
    ///     * which fullfills constraint `f` (typecheck)
    fn check_all_inner_maps_have_key_with<F>(store_config: &BTreeMap<String, Value>,
                                             section: &str,
                                             key: &str,
                                             f: F)
        -> bool
        where F: Fn(&Value) -> bool
    {
        store_config.get(section) // The store config has the section `section`
            .map_or_else(|| {
                write!(stderr(), "Store config expects section '{}' to be present, but isn't.",
                        section).ok();
                false
            }, |section_table| {
                match *section_table { // which is
                    Value::Table(ref section_table) => // a table
                        section_table
                            .iter() // which has values,
                            .all(|(inner_key, cfg)| { // and all of these values
                                match *cfg {
                                    Value::Table(ref hook_config) => { // are tables
                                        hook_config.get(key) // with a key
                                            // fullfilling this constraint
                                            .map_or(false, |hook_aspect| f(&hook_aspect))
                                    },
                                    _ => {
                                        write!(stderr(), "Store config expects '{}' to be in '{}.{}', but isn't.",
                                                 key, section, inner_key).ok();
                                        false
                                    }
                                }
                            }),
                    _ => {
                        write!(stderr(), "Store config expects '{}' to be a Table, but isn't.",
                               section).ok();
                        false
                    }
                }
            })
    }

    match *config {
        Some(Value::Table(ref t)) => {
            has_key_with_string_ary(t, "store-unload-hook-aspects")    &&

            has_key_with_string_ary(t, "pre-create-hook-aspects")      &&
            has_key_with_string_ary(t, "post-create-hook-aspects")     &&
            has_key_with_string_ary(t, "pre-retrieve-hook-aspects")    &&
            has_key_with_string_ary(t, "post-retrieve-hook-aspects")   &&
            has_key_with_string_ary(t, "pre-update-hook-aspects")      &&
            has_key_with_string_ary(t, "post-update-hook-aspects")     &&
            has_key_with_string_ary(t, "pre-delete-hook-aspects")      &&
            has_key_with_string_ary(t, "post-delete-hook-aspects")     &&

            // The section "hooks" has maps which have a key "aspect" which has a value of type
            // String
            check_all_inner_maps_have_key_with(t, "hooks", "aspect",
                                               |asp| is_match!(asp, &Value::String(_))) &&

            // The section "aspects" has maps which have a key "parllel" which has a value of type
            // Boolean
            check_all_inner_maps_have_key_with(t, "aspects", "parallel",
                                               |asp| is_match!(asp, &Value::Boolean(_)))
        }
        _ => {
            write!(stderr(), "Store config is no table").ok();
            false
        },
    }
}

pub fn get_store_unload_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("store-unload-hook-aspects", value)
}

pub fn get_pre_create_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("pre-create-hook-aspects", value)
}

pub fn get_post_create_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("post-create-hook-aspects", value)
}

pub fn get_pre_retrieve_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("pre-retrieve-hook-aspects", value)
}

pub fn get_post_retrieve_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("post-retrieve-hook-aspects", value)
}

pub fn get_pre_update_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("pre-update-hook-aspects", value)
}

pub fn get_post_update_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("post-update-hook-aspects", value)
}

pub fn get_pre_delete_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("pre-delete-hook-aspects", value)
}

pub fn get_post_delete_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("post-delete-hook-aspects", value)
}

pub fn get_pre_move_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("pre-move-hook-aspects", value)
}

pub fn get_post_move_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("post-move-hook-aspects", value)
}

#[derive(Debug)]
pub struct AspectConfig {
    parallel: bool,
    mutable_hooks: bool,
    config: Value,
}

impl AspectConfig {

    pub fn new(init: Value) -> AspectConfig {
        debug!("Trying to parse AspectConfig from: {:?}", init);
        let parallel = AspectConfig::is_parallel(&init);
        let muthooks = AspectConfig::allows_mutable_hooks(&init);
        AspectConfig {
            config: init,
            mutable_hooks: muthooks,
            parallel: parallel,
        }
    }

    fn is_parallel(init: &Value) -> bool {
        match *init {
            Value::Table(ref t) =>
                t.get("parallel")
                    .map_or(false, |value| {
                        match *value {
                            Value::Boolean(b) => b,
                            _ => false,
                        }
                    }),
            _ => false,
        }
    }

    fn allows_mutable_hooks(init: &Value) -> bool {
        match *init {
            Value::Table(ref t) =>
                t.get("mutable_hooks")
                    .map_or(false, |value| {
                        match *value {
                            Value::Boolean(b) => b,
                            _ => false,
                        }
                    }),
            _ => false,
        }
    }

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

    /// Get the aspect configuration for an aspect.
    ///
    /// Pass the store configuration object, this searches in `[aspects][<aspect_name>]`.
    ///
    /// Returns `None` if one of the keys in the chain is not available
    pub fn get_for(v: &Option<Value>, a_name: String) -> Option<AspectConfig> {
        debug!("Get aspect configuration for {:?} from {:?}", a_name, v);
        let res = match *v {
            Some(Value::Table(ref tabl)) => {
                match tabl.get("aspects") {
                    Some(&Value::Table(ref tabl)) => {
                        tabl.get(&a_name[..]).map(|asp| AspectConfig::new(asp.clone()))
                    },

                    _ => None,
                }
            },
            _ => None,
        };
        debug!("Found aspect configuration for {:?}: {:?}", a_name, res);
        res
    }

}

fn get_aspect_names_for_aspect_position(config_name: &'static str, value: &Option<Value>) -> Vec<String> {
    let mut v = vec![];

    match *value {
        Some(Value::Table(ref t)) => {
            match t.get(config_name) {
                Some(&Value::Array(ref a)) => {
                    for elem in a {
                        match *elem {
                            Value::String(ref s) => v.push(s.clone()),
                            _ => warn!("Non-String in configuration, inside '{}'", config_name),
                        }
                    }
                },
                _ => warn!("'{}' configuration key should contain Array, does not", config_name),
            };
        },
        None => warn!("No store configuration, cannot get '{}'", config_name),
        _ => warn!("Configuration is not a table"),
    }
    v
}

<|endoftext|>