<commit_before>use actix::prelude::*;
use godcoin::prelude::*;
use log::{info, warn};
use std::{sync::Arc, time::Duration};

#[derive(Message)]
pub struct StartProductionLoop;

#[derive(Message)]
#[rtype(result = "Result<(), verify::TxErr>")]
pub struct PushTx(pub TxVariant);

#[derive(Message)]
#[rtype(result = "Result<(), verify::BlockErr>")]
pub struct ForceProduceBlock;

pub struct Minter {
    chain: Arc<Blockchain>,
    minter_key: KeyPair,
    wallet_addr: ScriptHash,
    tx_pool: TxPool,
}

impl Actor for Minter {
    type Context = Context<Self>;
}

impl Minter {
    pub fn new(chain: Arc<Blockchain>, minter_key: KeyPair, wallet_addr: ScriptHash) -> Self {
        Self {
            chain: Arc::clone(&chain),
            minter_key,
            wallet_addr,
            tx_pool: TxPool::new(chain),
        }
    }

    fn produce(&mut self) -> Result<(), verify::BlockErr> {
        let mut transactions = self.tx_pool.flush();

        {
            let rewards = transactions
                .iter()
                .fold(Asset::default(), |acc, tx| acc.add(tx.fee).unwrap());
            if rewards.amount > 0 {
                transactions.push(TxVariant::RewardTx(RewardTx {
                    base: Tx {
                        tx_type: TxType::REWARD,
                        fee: asset::EMPTY_GRAEL,
                        timestamp: 0,
                        signature_pairs: Vec::new(),
                    },
                    to: self.wallet_addr.clone(),
                    rewards,
                }));
            }
        }

        let head = self.chain.get_chain_head();
        let block = head.new_child(transactions).sign(&self.minter_key);

        let height = block.height;
        let tx_len = block.transactions.len();

        self.chain.insert_block(block)?;
        let txs = if tx_len == 1 { "tx" } else { "txs" };
        info!(
            "Produced block at height {} with {} {}",
            height, tx_len, txs
        );
        Ok(())
    }
}

impl Handler<StartProductionLoop> for Minter {
    type Result = ();

    fn handle(&mut self, _: StartProductionLoop, ctx: &mut Self::Context) -> Self::Result {
        let dur = Duration::from_secs(3);
        ctx.run_later(dur, |minter, ctx| {
            minter.produce().unwrap();
            ctx.notify(StartProductionLoop);
        });
    }
}

impl Handler<ForceProduceBlock> for Minter {
    type Result = Result<(), verify::BlockErr>;

    fn handle(&mut self, _: ForceProduceBlock, _: &mut Self::Context) -> Self::Result {
        warn!("Forcing produced block...");
        self.produce()
    }
}

impl Handler<PushTx> for Minter {
    type Result = Result<(), verify::TxErr>;

    fn handle(&mut self, msg: PushTx, _: &mut Self::Context) -> Self::Result {
        static CONFIG: verify::Config = verify::Config::strict();
        self.tx_pool.push(msg.0.precompute(), CONFIG)
    }
}
<commit_msg>Assert the minter is constructed with the correct minter key<commit_after>use actix::prelude::*;
use godcoin::prelude::*;
use log::{info, warn};
use std::{sync::Arc, time::Duration};

#[derive(Message)]
pub struct StartProductionLoop;

#[derive(Message)]
#[rtype(result = "Result<(), verify::TxErr>")]
pub struct PushTx(pub TxVariant);

#[derive(Message)]
#[rtype(result = "Result<(), verify::BlockErr>")]
pub struct ForceProduceBlock;

pub struct Minter {
    chain: Arc<Blockchain>,
    minter_key: KeyPair,
    wallet_addr: ScriptHash,
    tx_pool: TxPool,
}

impl Actor for Minter {
    type Context = Context<Self>;
}

impl Minter {
    pub fn new(chain: Arc<Blockchain>, minter_key: KeyPair, wallet_addr: ScriptHash) -> Self {
        assert_eq!(chain.get_owner().minter, minter_key.0);
        Self {
            chain: Arc::clone(&chain),
            minter_key,
            wallet_addr,
            tx_pool: TxPool::new(chain),
        }
    }

    fn produce(&mut self) -> Result<(), verify::BlockErr> {
        let mut transactions = self.tx_pool.flush();

        {
            let rewards = transactions
                .iter()
                .fold(Asset::default(), |acc, tx| acc.add(tx.fee).unwrap());
            if rewards.amount > 0 {
                transactions.push(TxVariant::RewardTx(RewardTx {
                    base: Tx {
                        tx_type: TxType::REWARD,
                        fee: asset::EMPTY_GRAEL,
                        timestamp: 0,
                        signature_pairs: Vec::new(),
                    },
                    to: self.wallet_addr.clone(),
                    rewards,
                }));
            }
        }

        let head = self.chain.get_chain_head();
        let block = head.new_child(transactions).sign(&self.minter_key);

        let height = block.height;
        let tx_len = block.transactions.len();

        self.chain.insert_block(block)?;
        let txs = if tx_len == 1 { "tx" } else { "txs" };
        info!(
            "Produced block at height {} with {} {}",
            height, tx_len, txs
        );
        Ok(())
    }
}

impl Handler<StartProductionLoop> for Minter {
    type Result = ();

    fn handle(&mut self, _: StartProductionLoop, ctx: &mut Self::Context) -> Self::Result {
        let dur = Duration::from_secs(3);
        ctx.run_later(dur, |minter, ctx| {
            minter.produce().unwrap();
            ctx.notify(StartProductionLoop);
        });
    }
}

impl Handler<ForceProduceBlock> for Minter {
    type Result = Result<(), verify::BlockErr>;

    fn handle(&mut self, _: ForceProduceBlock, _: &mut Self::Context) -> Self::Result {
        warn!("Forcing produced block...");
        self.produce()
    }
}

impl Handler<PushTx> for Minter {
    type Result = Result<(), verify::TxErr>;

    fn handle(&mut self, msg: PushTx, _: &mut Self::Context) -> Self::Result {
        static CONFIG: verify::Config = verify::Config::strict();
        self.tx_pool.push(msg.0.precompute(), CONFIG)
    }
}
<|endoftext|>


<commit_before>use proc_macro2;
use proc_macro2::Span;
use syn;
use syn::fold::Fold;
use syn::spanned::Spanned;

use diagnostic_shim::*;
use meta::*;
use model::*;
use util::*;

pub fn derive(item: syn::DeriveInput) -> Result<proc_macro2::TokenStream, Diagnostic> {
    let model = Model::from_item(&item)?;
    let tokens = MetaItem::all_with_name(&item.attrs, "belongs_to")
        .into_iter()
        .filter_map(
            |attr| match derive_belongs_to(&model, &item.generics, attr) {
                Ok(t) => Some(t),
                Err(e) => {
                    e.emit();
                    None
                }
            },
        );

    Ok(wrap_in_dummy_mod(
        model.dummy_mod_name("associations"),
        quote!(#(#tokens)*),
    ))
}

fn derive_belongs_to(
    model: &Model,
    generics: &syn::Generics,
    meta: MetaItem,
) -> Result<proc_macro2::TokenStream, Diagnostic> {
    let AssociationOptions {
        parent_struct,
        foreign_key,
    } = AssociationOptions::from_meta(meta)?;
    let (_, ty_generics, _) = generics.split_for_impl();

    let foreign_key_field = model.find_column(&foreign_key)?;
    let struct_name = &model.name;
    let foreign_key_access = foreign_key_field.name.access();
    let foreign_key_ty = inner_of_option_ty(&foreign_key_field.ty);
    let table_name = model.table_name();

    let mut generics = generics.clone();

    let parent_struct = ReplacePathLifetimes::new(|i, span| {
        let letter = char::from(b'b' + i as u8);
        let lifetime = syn::Lifetime::new(&format!("'__{}", letter), span);
        generics.params.push(parse_quote!(#lifetime));
        lifetime
    })
    .fold_type_path(parent_struct);

    // TODO: Remove this special casing as soon as we bump our minimal supported
    // rust version to >= 1.30.0 because this version will add
    // `impl<'a, T> From<&'a Option<T>> for Option<&'a T>` to the std-lib
    let (foreign_key_expr, foreign_key_ty) = if is_option_ty(&foreign_key_field.ty) {
        (
            quote!(self#foreign_key_access.as_ref()),
            quote!(#foreign_key_ty),
        )
    } else {
        generics.params.push(parse_quote!(__FK));
        {
            let where_clause = generics.where_clause.get_or_insert(parse_quote!(where));
            where_clause
                .predicates
                .push(parse_quote!(__FK: std::hash::Hash + std::cmp::Eq));
            where_clause.predicates.push(
                parse_quote!(for<'__a> &'__a #foreign_key_ty: std::convert::Into<::std::option::Option<&'__a __FK>>),
            );
            where_clause.predicates.push(
                parse_quote!(for<'__a> &'__a #parent_struct: diesel::associations::Identifiable<Id = &'__a __FK>),
            );
        }

        (
            quote!(std::convert::Into::into(&self#foreign_key_access)),
            quote!(__FK),
        )
    };

    let (impl_generics, _, where_clause) = generics.split_for_impl();

    Ok(quote! {
        impl #impl_generics diesel::associations::BelongsTo<#parent_struct>
            for #struct_name #ty_generics
        #where_clause
        {
            type ForeignKey = #foreign_key_ty;
            type ForeignKeyColumn = #table_name::#foreign_key;

            fn foreign_key(&self) -> std::option::Option<&Self::ForeignKey> {
                #foreign_key_expr
            }

            fn foreign_key_column() -> Self::ForeignKeyColumn {
                #table_name::#foreign_key
            }
        }
    })
}

struct AssociationOptions {
    parent_struct: syn::TypePath,
    foreign_key: syn::Ident,
}

impl AssociationOptions {
    fn from_meta(meta: MetaItem) -> Result<Self, Diagnostic> {
        let parent_struct = meta
            .nested()?
            .find(|m| m.path().is_ok() || m.name().is_ident("parent"))
            .ok_or_else(|| meta.span())
            .and_then(|m| {
                m.path()
                    .map(|i| parse_quote!(#i))
                    .or_else(|_| m.ty_value())
                    .map_err(|_| m.span())
            })
            .and_then(|ty| match ty {
                syn::Type::Path(ty_path) => Ok(ty_path),
                _ => Err(ty.span()),
            })
            .map_err(|span| {
                span.error("Expected a struct name")
                    .help("e.g. `#[belongs_to(User)]` or `#[belongs_to(parent = \"User<'_>\")]")
            })?;
        let foreign_key = {
            let parent_struct_name = parent_struct
                .path
                .segments
                .last()
                .expect("paths always have at least one segment");
            meta.nested_item("foreign_key")?
                .map(|i| i.ident_value())
                .unwrap_or_else(|| Ok(infer_foreign_key(&parent_struct_name.ident)))?
        };

        let (unrecognized_paths, unrecognized_options): (Vec<_>, Vec<_>) = meta
            .nested()?
            .skip(1)
            .filter(|n| !n.name().is_ident("foreign_key"))
            .partition(|item| item.path().is_ok());

        if !unrecognized_paths.is_empty() {
            let parent_path_string = path_to_string(&parent_struct.path);
            let unrecognized_path_strings: Vec<_> = unrecognized_paths
                .iter()
                .filter_map(|item| item.path().as_ref().map(path_to_string).ok())
                .collect();

            meta.span()
                .warning(format!(
                    "belongs_to takes a single parent. Change\n\
                     \tbelongs_to({}, {})\n\
                     to\n\
                     \tbelongs_to({})\n\
                     {}",
                    parent_path_string,
                    unrecognized_path_strings.join(","),
                    parent_path_string,
                    unrecognized_path_strings
                        .iter()
                        .map(|path| format!("\tbelongs_to({})", path))
                        .collect::<Vec<_>>()
                        .join("\n")
                ))
                .emit();
        }

        for ignored in unrecognized_options {
            ignored
                .span()
                .warning(format!(
                    "Unrecognized option {}",
                    path_to_string(&ignored.name())
                ))
                .emit();
        }

        Ok(Self {
            parent_struct,
            foreign_key,
        })
    }
}

fn infer_foreign_key(name: &syn::Ident) -> syn::Ident {
    let snake_case = camel_to_snake(&name.to_string());
    syn::Ident::new(&format!("{}_id", snake_case), name.span())
}

struct ReplacePathLifetimes<F> {
    count: usize,
    f: F,
}

impl<F> ReplacePathLifetimes<F> {
    fn new(f: F) -> Self {
        Self { count: 0, f }
    }
}

impl<F> Fold for ReplacePathLifetimes<F>
where
    F: FnMut(usize, Span) -> syn::Lifetime,
{
    fn fold_lifetime(&mut self, mut lt: syn::Lifetime) -> syn::Lifetime {
        if lt.ident == "_" {
            lt = (self.f)(self.count, lt.span());
            self.count += 1;
        }
        lt
    }
}
<commit_msg>Remove a workaround for an old rust version<commit_after>use proc_macro2;
use proc_macro2::Span;
use syn;
use syn::fold::Fold;
use syn::spanned::Spanned;

use diagnostic_shim::*;
use meta::*;
use model::*;
use util::*;

pub fn derive(item: syn::DeriveInput) -> Result<proc_macro2::TokenStream, Diagnostic> {
    let model = Model::from_item(&item)?;
    let tokens = MetaItem::all_with_name(&item.attrs, "belongs_to")
        .into_iter()
        .filter_map(
            |attr| match derive_belongs_to(&model, &item.generics, attr) {
                Ok(t) => Some(t),
                Err(e) => {
                    e.emit();
                    None
                }
            },
        );

    Ok(wrap_in_dummy_mod(
        model.dummy_mod_name("associations"),
        quote!(#(#tokens)*),
    ))
}

fn derive_belongs_to(
    model: &Model,
    generics: &syn::Generics,
    meta: MetaItem,
) -> Result<proc_macro2::TokenStream, Diagnostic> {
    let AssociationOptions {
        parent_struct,
        foreign_key,
    } = AssociationOptions::from_meta(meta)?;
    let (_, ty_generics, _) = generics.split_for_impl();

    let foreign_key_field = model.find_column(&foreign_key)?;
    let struct_name = &model.name;
    let foreign_key_access = foreign_key_field.name.access();
    let foreign_key_ty = inner_of_option_ty(&foreign_key_field.ty);
    let table_name = model.table_name();

    let mut generics = generics.clone();

    let parent_struct = ReplacePathLifetimes::new(|i, span| {
        let letter = char::from(b'b' + i as u8);
        let lifetime = syn::Lifetime::new(&format!("'__{}", letter), span);
        generics.params.push(parse_quote!(#lifetime));
        lifetime
    })
    .fold_type_path(parent_struct);

    generics.params.push(parse_quote!(__FK));
    {
        let where_clause = generics.where_clause.get_or_insert(parse_quote!(where));
        where_clause
            .predicates
            .push(parse_quote!(__FK: std::hash::Hash + std::cmp::Eq));
        where_clause.predicates.push(
                parse_quote!(for<'__a> &'__a #foreign_key_ty: std::convert::Into<::std::option::Option<&'__a __FK>>),
            );
        where_clause.predicates.push(
                parse_quote!(for<'__a> &'__a #parent_struct: diesel::associations::Identifiable<Id = &'__a __FK>),
            );
    }

    let foreign_key_expr = quote!(std::convert::Into::into(&self#foreign_key_access));
    let foreign_key_ty = quote!(__FK);

    let (impl_generics, _, where_clause) = generics.split_for_impl();

    Ok(quote! {
        impl #impl_generics diesel::associations::BelongsTo<#parent_struct>
            for #struct_name #ty_generics
        #where_clause
        {
            type ForeignKey = #foreign_key_ty;
            type ForeignKeyColumn = #table_name::#foreign_key;

            fn foreign_key(&self) -> std::option::Option<&Self::ForeignKey> {
                #foreign_key_expr
            }

            fn foreign_key_column() -> Self::ForeignKeyColumn {
                #table_name::#foreign_key
            }
        }
    })
}

struct AssociationOptions {
    parent_struct: syn::TypePath,
    foreign_key: syn::Ident,
}

impl AssociationOptions {
    fn from_meta(meta: MetaItem) -> Result<Self, Diagnostic> {
        let parent_struct = meta
            .nested()?
            .find(|m| m.path().is_ok() || m.name().is_ident("parent"))
            .ok_or_else(|| meta.span())
            .and_then(|m| {
                m.path()
                    .map(|i| parse_quote!(#i))
                    .or_else(|_| m.ty_value())
                    .map_err(|_| m.span())
            })
            .and_then(|ty| match ty {
                syn::Type::Path(ty_path) => Ok(ty_path),
                _ => Err(ty.span()),
            })
            .map_err(|span| {
                span.error("Expected a struct name")
                    .help("e.g. `#[belongs_to(User)]` or `#[belongs_to(parent = \"User<'_>\")]")
            })?;
        let foreign_key = {
            let parent_struct_name = parent_struct
                .path
                .segments
                .last()
                .expect("paths always have at least one segment");
            meta.nested_item("foreign_key")?
                .map(|i| i.ident_value())
                .unwrap_or_else(|| Ok(infer_foreign_key(&parent_struct_name.ident)))?
        };

        let (unrecognized_paths, unrecognized_options): (Vec<_>, Vec<_>) = meta
            .nested()?
            .skip(1)
            .filter(|n| !n.name().is_ident("foreign_key"))
            .partition(|item| item.path().is_ok());

        if !unrecognized_paths.is_empty() {
            let parent_path_string = path_to_string(&parent_struct.path);
            let unrecognized_path_strings: Vec<_> = unrecognized_paths
                .iter()
                .filter_map(|item| item.path().as_ref().map(path_to_string).ok())
                .collect();

            meta.span()
                .warning(format!(
                    "belongs_to takes a single parent. Change\n\
                     \tbelongs_to({}, {})\n\
                     to\n\
                     \tbelongs_to({})\n\
                     {}",
                    parent_path_string,
                    unrecognized_path_strings.join(","),
                    parent_path_string,
                    unrecognized_path_strings
                        .iter()
                        .map(|path| format!("\tbelongs_to({})", path))
                        .collect::<Vec<_>>()
                        .join("\n")
                ))
                .emit();
        }

        for ignored in unrecognized_options {
            ignored
                .span()
                .warning(format!(
                    "Unrecognized option {}",
                    path_to_string(&ignored.name())
                ))
                .emit();
        }

        Ok(Self {
            parent_struct,
            foreign_key,
        })
    }
}

fn infer_foreign_key(name: &syn::Ident) -> syn::Ident {
    let snake_case = camel_to_snake(&name.to_string());
    syn::Ident::new(&format!("{}_id", snake_case), name.span())
}

struct ReplacePathLifetimes<F> {
    count: usize,
    f: F,
}

impl<F> ReplacePathLifetimes<F> {
    fn new(f: F) -> Self {
        Self { count: 0, f }
    }
}

impl<F> Fold for ReplacePathLifetimes<F>
where
    F: FnMut(usize, Span) -> syn::Lifetime,
{
    fn fold_lifetime(&mut self, mut lt: syn::Lifetime) -> syn::Lifetime {
        if lt.ident == "_" {
            lt = (self.f)(self.count, lt.span());
            self.count += 1;
        }
        lt
    }
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! SOS init parameters
//!
//! This crate is intended to facilitate the sharing of initialization
//! parameters between "higher-level" SOS subcrates (such as [`alloc`] and
//! [`paging`]) in a platform-independent way.
//!
//! [`alloc`](../alloc)
//! [`paging`](../paging)
#![no_std]
#![deny(missing_docs)]

extern crate memory;
extern crate elf;
extern crate arrayvec;

use memory::{ PAddr, Page, PhysicalPage, FrameRange };
use core::default::Default;

use core::slice::Iter as SliceIter;
use arrayvec::{ArrayVec};

pub mod mem;

const MAX_MEM_AREAS: usize = 0x100;

/// If we are on x86_64 or armv7 this uses the 64-bit ELF word
#[cfg(target_pointer_width = "64")]
pub type ElfSections = elf::section::Sections<'static, u64>;

/// If we are on x86, this uses the 32-bit ELF word
#[cfg(target_pointer_width = "32")]
pub type ElfSections = elf::section::Sections<'static, u32>;

/// Parameters used during the init process
#[derive(Clone, Debug)]
pub struct InitParams {
    /// The base of the kernel memory range
    pub kernel_base: PAddr
  , /// The top of the kernel memory range
    pub kernel_top: PAddr
  , /// The base of the memory range for the kernel heap
    pub heap_base: PAddr
  , /// The top of the memory range to use for the kernel heap
    pub heap_top: PAddr
  , /// The base of the memory range for the kernel stack
    pub stack_base: PAddr
  , /// The top of the memory range to use for the kernel stack
    pub stack_top: PAddr
  , /// The start address of the Multiboot info structure, if it exists.
    ///
    /// N.B. that this is currently never `None`, as we only support multiboot.
    /// However, this may change at a later date.
    pub multiboot_start: Option<PAddr>
  , /// The end address of the Multiboot info structure, if it exists.
    ///
    /// N.B. that this is currently never `None`, as we only support multiboot.
    /// However, this may change at a later date.
    pub multiboot_end: Option<PAddr>
  , /// Map of memory areas
    pub mem_map: ArrayVec<[mem::Area; MAX_MEM_AREAS]>
}

impl Default for InitParams {
    fn default() -> Self {
        // use memory::arch::{HEAP_BASE, HEAP_TOP, STACK_BASE, STACK_TOP};
        InitParams { kernel_base: PAddr::from(0x0)
                     // NOTE: this is, of course, Extremely Wrong, but the
                     //       `Default` impl is not going to make _correct_
                     //       params, just fill in default values for other
                     //       fns that make params.
                     // TODO: should this be an Option instead?
                   , kernel_top: PAddr::from(0x0)
                   , heap_base:  PAddr::from(0x0)
                   , heap_top: PAddr::from(0x0)
                   , stack_base: PAddr::from(0x0)
                   , stack_top: PAddr::from(0x0)
                   , multiboot_start: None
                   , multiboot_end: None
                   , mem_map: ArrayVec::<[mem::Area; MAX_MEM_AREAS]>::new()
                   }
    }
}

impl InitParams {
    /// Returns an iterator over the kernel's ELF sections
    // TODO: is this cross-platform? are we using ELF on all our supported
    //       architectures? i think we are, but we should ensure this is the
    //       case...
    //          – eliza, 1/22/2017
    pub fn elf_sections(&self) ->  ElfSections {
        unimplemented!()
    }

    /// Returns the start address of the multiboot info struct
    ///
    /// # Panics
    /// If this is a non-Multiboot kernel
    // TODO: instead of panicking, return Option!
    //          - eliza, 5/26/2017
    #[inline]
    pub fn multiboot_start(&self) -> PAddr {
        self.multiboot_start
            .expect("Attempted to access Multiboot info structure on a \
                     non-Multiboot kernel!")
    }

    /// Returns the end address of the multiboot info struct
    ///
    /// # Panics
    /// If this is a non-Multiboot kernel
    // TODO: instead of panicking, return Option!
    //          - eliza, 5/26/2017
    pub fn multiboot_end(&self) -> PAddr {
        self.multiboot_end
            .expect("Attempted to access Multiboot info structure on a \
                     non-Multiboot kernel!")
    }

    /// Returns the range of frames containing the kernel binary.
    ///
    /// The kernel _should_ start on the first address in the frame range,
    /// since the kernel should be page aligned.
    //  TODO: this should be an array vector or linked list of frame ranges
    //        possibly?
    //          - eliza, 2/28/2017
    #[inline]
    pub fn kernel_frames(&self) -> FrameRange {
        // TODO: assert that the kernel base addr is page aligned here?
        //       this should maybe be a debug assertion?
        //          - eliza, 1/22/2017
        PhysicalPage::containing(self.kernel_base) ..
        PhysicalPage::containing(self.kernel_top)
    }

    /// Returns the range of frames containing the kernel heap
    ///
    /// The heap _should_ start on the first address in the frame range,
    /// since the heap should be page aligned.
    #[inline]
    pub fn heap_frames(&self) -> FrameRange {
        // TODO: assert that the heap base addr is page aligned here?
        //       this should maybe be a debug assertion?
        //          - eliza, 1/22/2017
        PhysicalPage::containing(self.heap_base) ..
        PhysicalPage::containing(self.heap_top)
    }

    /// Returns the range of frames containing the kernel stack.
    #[inline]
    pub fn stack_frames(&self) -> FrameRange {
        unimplemented!()
    }

    /// returns an iterator over the memory map
    #[inline]
    pub fn mem_map(&self) -> mem::Map {
        self.mem_map.iter()
    }

}
<commit_msg>fix(params): fix stack overflow caused by too-large memory areas array<commit_after>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! SOS init parameters
//!
//! This crate is intended to facilitate the sharing of initialization
//! parameters between "higher-level" SOS subcrates (such as [`alloc`] and
//! [`paging`]) in a platform-independent way.
//!
//! [`alloc`](../alloc)
//! [`paging`](../paging)
#![no_std]
#![deny(missing_docs)]

extern crate memory;
extern crate elf;
extern crate arrayvec;

use memory::{ PAddr, Page, PhysicalPage, FrameRange };
use core::default::Default;

use core::slice::Iter as SliceIter;
use arrayvec::{ArrayVec};

pub mod mem;

const MAX_MEM_AREAS: usize = 32;

/// If we are on x86_64 or armv7 this uses the 64-bit ELF word
#[cfg(target_pointer_width = "64")]
pub type ElfSections = elf::section::Sections<'static, u64>;

/// If we are on x86, this uses the 32-bit ELF word
#[cfg(target_pointer_width = "32")]
pub type ElfSections = elf::section::Sections<'static, u32>;

/// Parameters used during the init process
#[derive(Clone, Debug)]
pub struct InitParams {
    /// The base of the kernel memory range
    pub kernel_base: PAddr
  , /// The top of the kernel memory range
    pub kernel_top: PAddr
  , /// The base of the memory range for the kernel heap
    pub heap_base: PAddr
  , /// The top of the memory range to use for the kernel heap
    pub heap_top: PAddr
  , /// The base of the memory range for the kernel stack
    pub stack_base: PAddr
  , /// The top of the memory range to use for the kernel stack
    pub stack_top: PAddr
  , /// The start address of the Multiboot info structure, if it exists.
    ///
    /// N.B. that this is currently never `None`, as we only support multiboot.
    /// However, this may change at a later date.
    pub multiboot_start: Option<PAddr>
  , /// The end address of the Multiboot info structure, if it exists.
    ///
    /// N.B. that this is currently never `None`, as we only support multiboot.
    /// However, this may change at a later date.
    pub multiboot_end: Option<PAddr>
  , /// Map of memory areas
    pub mem_map: ArrayVec<[mem::Area; MAX_MEM_AREAS]>
}

impl Default for InitParams {
    fn default() -> Self {
        // use memory::arch::{HEAP_BASE, HEAP_TOP, STACK_BASE, STACK_TOP};
        InitParams { kernel_base: PAddr::from(0x0)
                     // NOTE: this is, of course, Extremely Wrong, but the
                     //       `Default` impl is not going to make _correct_
                     //       params, just fill in default values for other
                     //       fns that make params.
                     // TODO: should this be an Option instead?
                   , kernel_top: PAddr::from(0x0)
                   , heap_base:  PAddr::from(0x0)
                   , heap_top: PAddr::from(0x0)
                   , stack_base: PAddr::from(0x0)
                   , stack_top: PAddr::from(0x0)
                   , multiboot_start: None
                   , multiboot_end: None
                   , mem_map: ArrayVec::<[mem::Area; MAX_MEM_AREAS]>::new()
                   }
    }
}

impl InitParams {
    /// Returns an iterator over the kernel's ELF sections
    // TODO: is this cross-platform? are we using ELF on all our supported
    //       architectures? i think we are, but we should ensure this is the
    //       case...
    //          – eliza, 1/22/2017
    pub fn elf_sections(&self) ->  ElfSections {
        unimplemented!()
    }

    /// Returns the start address of the multiboot info struct
    ///
    /// # Panics
    /// If this is a non-Multiboot kernel
    // TODO: instead of panicking, return Option!
    //          - eliza, 5/26/2017
    #[inline]
    pub fn multiboot_start(&self) -> PAddr {
        self.multiboot_start
            .expect("Attempted to access Multiboot info structure on a \
                     non-Multiboot kernel!")
    }

    /// Returns the end address of the multiboot info struct
    ///
    /// # Panics
    /// If this is a non-Multiboot kernel
    // TODO: instead of panicking, return Option!
    //          - eliza, 5/26/2017
    pub fn multiboot_end(&self) -> PAddr {
        self.multiboot_end
            .expect("Attempted to access Multiboot info structure on a \
                     non-Multiboot kernel!")
    }

    /// Returns the range of frames containing the kernel binary.
    ///
    /// The kernel _should_ start on the first address in the frame range,
    /// since the kernel should be page aligned.
    //  TODO: this should be an array vector or linked list of frame ranges
    //        possibly?
    //          - eliza, 2/28/2017
    #[inline]
    pub fn kernel_frames(&self) -> FrameRange {
        // TODO: assert that the kernel base addr is page aligned here?
        //       this should maybe be a debug assertion?
        //          - eliza, 1/22/2017
        PhysicalPage::containing(self.kernel_base) ..
        PhysicalPage::containing(self.kernel_top)
    }

    /// Returns the range of frames containing the kernel heap
    ///
    /// The heap _should_ start on the first address in the frame range,
    /// since the heap should be page aligned.
    #[inline]
    pub fn heap_frames(&self) -> FrameRange {
        // TODO: assert that the heap base addr is page aligned here?
        //       this should maybe be a debug assertion?
        //          - eliza, 1/22/2017
        PhysicalPage::containing(self.heap_base) ..
        PhysicalPage::containing(self.heap_top)
    }

    /// Returns the range of frames containing the kernel stack.
    #[inline]
    pub fn stack_frames(&self) -> FrameRange {
        unimplemented!()
    }

    /// returns an iterator over the memory map
    #[inline]
    pub fn mem_map(&self) -> mem::Map {
        self.mem_map.iter()
    }

}
<|endoftext|>


<commit_before>use coordinates::{CoordinateSystem, Point};
use std::ops::{Index, IndexMut, Add};
use std::marker::PhantomData;
use typenum::uint::Unsigned;
use typenum::consts::U1;

/// This enum serves to represent the type of a tensor. A tensor can have any number of indices, and each one can be either
/// covariant (a lower index), or contravariant (an upper index). For example, a vector is a tensor with only one contravariant index.
#[derive(Clone, Copy)]
pub enum IndexType {
       Covariant,
       Contravariant
}

pub trait TensorIndex {
	fn index_type() -> IndexType;
}

pub struct ContravariantIndex;
impl TensorIndex for ContravariantIndex {
	fn index_type() -> IndexType { IndexType::Contravariant }
}

pub struct CovariantIndex;
impl TensorIndex for CovariantIndex {
	fn index_type() -> IndexType { IndexType::Covariant }
}

pub trait Variance {
	type Rank: Unsigned + Add<U1>;
	fn rank() -> usize { Self::Rank::to_usize() }
	fn variance() -> Vec<IndexType>;
}

impl Variance for ContravariantIndex {
	type Rank = U1;
	fn variance() -> Vec<IndexType> { vec![IndexType::Contravariant] }
}

impl Variance for CovariantIndex {
	type Rank = U1;
	fn variance() -> Vec<IndexType> { vec![IndexType::Covariant] }
}

impl<T, U> Variance for (T, U)
	where
		T: Variance,
		<T::Rank as Add<U1>>::Output: Unsigned + Add<U1>,
		U: TensorIndex
{
	type Rank = <T::Rank as Add<U1>>::Output;

	fn variance() -> Vec<IndexType> {
		let mut result = T::variance();
		result.push(U::index_type());
		result
	}
}

/// This is a struct that represents a generic tensor
pub struct Tensor<T: CoordinateSystem, U: Variance> {
	p: Point<T>,
	x: Vec<f64>,
	phantom: PhantomData<U>
}

impl<T, U> Tensor<T, U> where T: CoordinateSystem, U: Variance {

	/// Returns the point at which the tensor is defined.
	pub fn get_point(&self) -> &Point<T> {
		&self.p
	}

	/// Returns a reference to a coordinate of the tensor, at indices specified by the slice.
	/// The length of the slice (the number of indices) has to be compatible with the rank of the tensor.
	pub fn get_coord(&self, i: &[usize]) -> &f64 {
		assert_eq!(i.len(), U::rank());
		let dim = T::dimension();
		let index = i.into_iter().fold(0, |res, idx| { assert!(*idx < dim); res*dim + idx });
		&self.x[index]
	}

	/// Returns a mutable reference to a coordinate of the tensor, at indices specified by the slice.
	/// The length of the slice (the number of indices) has to be compatible with the rank of the tensor.
	pub fn get_coord_mut(&mut self, i: &[usize]) -> &mut f64 {
		assert_eq!(i.len(), U::rank());
		let dim = T::dimension();
		let index = i.into_iter().fold(0, |res, idx| { assert!(*idx < dim); res*dim + idx });
		&mut self.x[index]
	}

	/// Returns the variance of the tensor, that is, the list of the index types.
	/// A vector would return vec![Contravariant], a metric tensor: vec![Covariant, Covariant].
	pub fn get_variance() -> Vec<IndexType> { U::variance() }

	/// Returns the rank of the tensor
	pub fn get_rank() -> usize { U::rank() }

	pub fn new(point: Point<T>) -> Tensor<T, U> {
		let len = U::rank();
		let num_coords = T::dimension().pow(len as u32);
		let mut coords: Vec<f64> = Vec::with_capacity(num_coords);
		for _ in 0..num_coords {
			coords.push(0.0);
		}
		Tensor {
			p: point,
			x: coords,
			phantom: PhantomData
		}
	}
}

impl<'a, T, U> Index<&'a [usize]> for Tensor<T, U> where T: CoordinateSystem, U: Variance {
	type Output = f64;

	fn index(&self, idx: &'a [usize]) -> &f64 {
		self.get_coord(idx)
	}
}

impl<'a, T, U> IndexMut<&'a [usize]> for Tensor<T, U> where T: CoordinateSystem, U: Variance {
	fn index_mut(&mut self, idx: &'a [usize]) -> &mut f64 {
		self.get_coord_mut(idx)
	}
}

pub type Vector<T> = Tensor<T, ContravariantIndex>;
pub type Covector<T> = Tensor<T, CovariantIndex>;
pub type Matrix<T> = Tensor<T, (ContravariantIndex, CovariantIndex)>;
<commit_msg>Added a test for ranks<commit_after>use coordinates::{CoordinateSystem, Point};
use std::ops::{Index, IndexMut, Add};
use std::marker::PhantomData;
use typenum::uint::Unsigned;
use typenum::consts::U1;

/// This enum serves to represent the type of a tensor. A tensor can have any number of indices, and each one can be either
/// covariant (a lower index), or contravariant (an upper index). For example, a vector is a tensor with only one contravariant index.
#[derive(Clone, Copy)]
pub enum IndexType {
       Covariant,
       Contravariant
}

pub trait TensorIndex {
	fn index_type() -> IndexType;
}

pub struct ContravariantIndex;
impl TensorIndex for ContravariantIndex {
	fn index_type() -> IndexType { IndexType::Contravariant }
}

pub struct CovariantIndex;
impl TensorIndex for CovariantIndex {
	fn index_type() -> IndexType { IndexType::Covariant }
}

pub trait Variance {
	type Rank: Unsigned + Add<U1>;
	fn rank() -> usize { Self::Rank::to_usize() }
	fn variance() -> Vec<IndexType>;
}

impl Variance for ContravariantIndex {
	type Rank = U1;
	fn variance() -> Vec<IndexType> { vec![IndexType::Contravariant] }
}

impl Variance for CovariantIndex {
	type Rank = U1;
	fn variance() -> Vec<IndexType> { vec![IndexType::Covariant] }
}

impl<T, U> Variance for (T, U)
	where
		T: Variance,
		<T::Rank as Add<U1>>::Output: Unsigned + Add<U1>,
		U: TensorIndex
{
	type Rank = <T::Rank as Add<U1>>::Output;

	fn variance() -> Vec<IndexType> {
		let mut result = T::variance();
		result.push(U::index_type());
		result
	}
}

/// This is a struct that represents a generic tensor
pub struct Tensor<T: CoordinateSystem, U: Variance> {
	p: Point<T>,
	x: Vec<f64>,
	phantom: PhantomData<U>
}

impl<T, U> Tensor<T, U> where T: CoordinateSystem, U: Variance {

	/// Returns the point at which the tensor is defined.
	pub fn get_point(&self) -> &Point<T> {
		&self.p
	}

	/// Returns a reference to a coordinate of the tensor, at indices specified by the slice.
	/// The length of the slice (the number of indices) has to be compatible with the rank of the tensor.
	pub fn get_coord(&self, i: &[usize]) -> &f64 {
		assert_eq!(i.len(), U::rank());
		let dim = T::dimension();
		let index = i.into_iter().fold(0, |res, idx| { assert!(*idx < dim); res*dim + idx });
		&self.x[index]
	}

	/// Returns a mutable reference to a coordinate of the tensor, at indices specified by the slice.
	/// The length of the slice (the number of indices) has to be compatible with the rank of the tensor.
	pub fn get_coord_mut(&mut self, i: &[usize]) -> &mut f64 {
		assert_eq!(i.len(), U::rank());
		let dim = T::dimension();
		let index = i.into_iter().fold(0, |res, idx| { assert!(*idx < dim); res*dim + idx });
		&mut self.x[index]
	}

	/// Returns the variance of the tensor, that is, the list of the index types.
	/// A vector would return vec![Contravariant], a metric tensor: vec![Covariant, Covariant].
	pub fn get_variance() -> Vec<IndexType> { U::variance() }

	/// Returns the rank of the tensor
	pub fn get_rank() -> usize { U::rank() }

	pub fn new(point: Point<T>) -> Tensor<T, U> {
		let len = U::rank();
		let num_coords = T::dimension().pow(len as u32);
		let mut coords: Vec<f64> = Vec::with_capacity(num_coords);
		for _ in 0..num_coords {
			coords.push(0.0);
		}
		Tensor {
			p: point,
			x: coords,
			phantom: PhantomData
		}
	}
}

impl<'a, T, U> Index<&'a [usize]> for Tensor<T, U> where T: CoordinateSystem, U: Variance {
	type Output = f64;

	fn index(&self, idx: &'a [usize]) -> &f64 {
		self.get_coord(idx)
	}
}

impl<'a, T, U> IndexMut<&'a [usize]> for Tensor<T, U> where T: CoordinateSystem, U: Variance {
	fn index_mut(&mut self, idx: &'a [usize]) -> &mut f64 {
		self.get_coord_mut(idx)
	}
}

pub type Vector<T> = Tensor<T, ContravariantIndex>;
pub type Covector<T> = Tensor<T, CovariantIndex>;
pub type Matrix<T> = Tensor<T, (ContravariantIndex, CovariantIndex)>;

#[cfg(test)]
mod test {
	use typenum::consts::U4;
	use coordinates::CoordinateSystem;
	use super::{Vector, Matrix};

	struct Test;
	impl CoordinateSystem for Test {
		type Dimension = U4;
	}

	#[test]
	fn test_ranks() {
		assert_eq!(Vector::<Test>::get_rank(), 1);
		assert_eq!(Matrix::<Test>::get_rank(), 2);
	}
}
<|endoftext|>


<commit_before>//! Defines the codec trait for decoding/encoding nodes

use async_trait::async_trait;
use eyre::{bail, Result};
use std::{
    fs::File,
    io::{BufReader, BufWriter, Read, Write},
    path::Path,
};
use stencila_schema::Node;

// Export for use by other crates
pub use ::async_trait;
pub use eyre;
pub use stencila_schema;

/// A codec for for decoding/encoding nodes
///
/// Defines similar functions to `serde_json` (and other `serde` crates) for
/// converting nodes to/from strings, files, readers etc.
#[async_trait]
pub trait Codec {
    fn from_str(_str: &str) -> Result<Node> {
        bail!("Decoding from string is not implemented for this format")
    }

    async fn from_str_async(str: &str) -> Result<Node> {
        Self::from_str(str)
    }

    async fn from_buffer<T: Read>(reader: &mut BufReader<T>) -> Result<Node>
    where
        T: Send + Sync,
    {
        let mut content = String::new();
        reader.read_to_string(&mut content)?;
        Self::from_str(&content)
    }

    async fn from_file(file: &mut File) -> Result<Node> {
        let mut content = String::new();
        file.read_to_string(&mut content)?;
        Self::from_str(&content)
    }

    async fn from_path<T: AsRef<Path>>(path: &T) -> Result<Node>
    where
        T: Send + Sync,
    {
        let mut file = File::open(path)?;
        Self::from_file(&mut file).await
    }

    fn to_string(_node: &Node, _options: Option<EncodeOptions>) -> Result<String> {
        bail!("Encoding to string is not implemented for this format")
    }

    async fn to_string_async(node: &Node, options: Option<EncodeOptions>) -> Result<String> {
        Self::to_string(node, options)
    }

    async fn to_buffer<T: Write>(
        node: &Node,
        writer: &mut BufWriter<T>,
        options: Option<EncodeOptions>,
    ) -> Result<()>
    where
        T: Send + Sync,
    {
        let content = Self::to_string(node, options)?;
        writer.write_all(content.as_bytes())?;
        Ok(())
    }

    async fn to_file(node: &Node, file: &mut File, options: Option<EncodeOptions>) -> Result<()> {
        let content = Self::to_string(node, options)?;
        file.write_all(content.as_bytes())?;
        Ok(())
    }

    async fn to_path<T: AsRef<Path>>(
        node: &Node,
        path: &T,
        options: Option<EncodeOptions>,
    ) -> Result<()>
    where
        T: Send + Sync,
    {
        let mut file = File::open(path)?;
        Self::to_file(node, &mut file, options).await
    }
}

/// Common encoding options
///
/// Encoding functions (including those in plugins) are encouraged to respect these options
/// but are not required to. Indeed, some options do not apply for some formats.
/// For example, a PDF is always `standalone` (so if that option is set to `false` is it will be ignored).
/// Futhermore, some combinations of options are ineffectual e.g. a `theme` when `standalone: false`
#[derive(Clone)]
pub struct EncodeOptions {
    /// Whether to encode in compact form.
    ///
    /// Some formats (e.g HTML and JSON) can be encoded in either compact
    /// or "pretty-printed" ie.e. indented forms.
    pub compact: bool,

    /// Whether to ensure that the encoded document is standalone.
    ///
    /// Some formats (e.g. Markdown, DOCX) are always standalone, others
    /// can be frangments, or standalong documents (e.g HTML).
    pub standalone: bool,

    /// Whether to bundle local media files into the encoded document
    ///
    /// Some formats (e.g. DOCX, PDF) always bundle. For HTML,
    /// bundling means including media as data URIs rather than
    /// links to files.
    pub bundle: bool,

    /// The theme to apply to the encoded document
    ///
    /// Only applies to some formats (e.g. HTML, PDF, PNG).
    pub theme: String,
}

impl Default for EncodeOptions {
    fn default() -> Self {
        Self {
            compact: true,
            standalone: false,
            bundle: false,
            theme: "stencila".to_string(),
        }
    }
}
<commit_msg>docs(Codec trait): Add function comments<commit_after>//! Defines the codec trait for decoding/encoding nodes

use async_trait::async_trait;
use eyre::{bail, Result};
use std::{
    fs::File,
    io::{BufReader, BufWriter, Read, Write},
    path::Path,
};
use stencila_schema::Node;

// Export for use by other crates
pub use ::async_trait;
pub use eyre;
pub use stencila_schema;

/// A codec for decoding and encoding Stencila document nodes to one or more formats
///
/// This trait defines similar functions to `serde_json` (and other `serde` crates) for
/// converting nodes to/from strings, files, readers etc.
#[async_trait]
pub trait Codec {
    /// Decode a document node from a string
    fn from_str(_str: &str) -> Result<Node> {
        bail!("Decoding from string is not implemented for this format")
    }

    /// Decode a document node from a string asynchronously
    async fn from_str_async(str: &str) -> Result<Node> {
        Self::from_str(str)
    }

    /// Decode a document node from a `BufReader`
    async fn from_buffer<T: Read>(reader: &mut BufReader<T>) -> Result<Node>
    where
        T: Send + Sync,
    {
        let mut content = String::new();
        reader.read_to_string(&mut content)?;
        Self::from_str(&content)
    }

    /// Decode a document node from a file
    ///
    /// This function reads the file as a string and passes that on to `from_str`
    /// for decoding. If working with binary formats, you should override this function
    /// to read the file as bytes instead.
    async fn from_file(file: &mut File) -> Result<Node> {
        let mut content = String::new();
        file.read_to_string(&mut content)?;
        Self::from_str(&content)
    }

    /// Decode a document node from a file system path
    async fn from_path<T: AsRef<Path>>(path: &T) -> Result<Node>
    where
        T: Send + Sync,
    {
        let mut file = File::open(path)?;
        Self::from_file(&mut file).await
    }

    /// Encode a document node to a string
    fn to_string(_node: &Node, _options: Option<EncodeOptions>) -> Result<String> {
        bail!("Encoding to string is not implemented for this format")
    }

    /// Encode a document node to a string asynchronously
    async fn to_string_async(node: &Node, options: Option<EncodeOptions>) -> Result<String> {
        Self::to_string(node, options)
    }

    /// Encode a document node to a `BufWriter`
    async fn to_buffer<T: Write>(
        node: &Node,
        writer: &mut BufWriter<T>,
        options: Option<EncodeOptions>,
    ) -> Result<()>
    where
        T: Send + Sync,
    {
        let content = Self::to_string(node, options)?;
        writer.write_all(content.as_bytes())?;
        Ok(())
    }

    /// Encode a document node to a file
    async fn to_file(node: &Node, file: &mut File, options: Option<EncodeOptions>) -> Result<()> {
        let content = Self::to_string(node, options)?;
        file.write_all(content.as_bytes())?;
        Ok(())
    }

    /// Encode a document node to a file system path
    async fn to_path<T: AsRef<Path>>(
        node: &Node,
        path: &T,
        options: Option<EncodeOptions>,
    ) -> Result<()>
    where
        T: Send + Sync,
    {
        let mut file = File::open(path)?;
        Self::to_file(node, &mut file, options).await
    }
}

/// Common encoding options
///
/// Encoding functions (including those in plugins) are encouraged to respect these options
/// but are not required to. Indeed, some options do not apply for some formats.
/// For example, a PDF is always `standalone` (so if that option is set to `false` is it will be ignored).
/// Futhermore, some combinations of options are ineffectual e.g. a `theme` when `standalone: false`
#[derive(Clone)]
pub struct EncodeOptions {
    /// Whether to encode in compact form.
    ///
    /// Some formats (e.g HTML and JSON) can be encoded in either compact
    /// or "pretty-printed" ie.e. indented forms.
    pub compact: bool,

    /// Whether to ensure that the encoded document is standalone.
    ///
    /// Some formats (e.g. Markdown, DOCX) are always standalone, others
    /// can be frangments, or standalong documents (e.g HTML).
    pub standalone: bool,

    /// Whether to bundle local media files into the encoded document
    ///
    /// Some formats (e.g. DOCX, PDF) always bundle. For HTML,
    /// bundling means including media as data URIs rather than
    /// links to files.
    pub bundle: bool,

    /// The theme to apply to the encoded document
    ///
    /// Only applies to some formats (e.g. HTML, PDF, PNG).
    pub theme: String,
}

impl Default for EncodeOptions {
    fn default() -> Self {
        Self {
            compact: true,
            standalone: false,
            bundle: false,
            theme: "stencila".to_string(),
        }
    }
}
<|endoftext|>


<commit_before>use clap::{App, Arg};
use regex::Regex;

fn integer_value(v: String) -> Result<(), String> {
  v.parse::<u16>().map(|_| ()).map_err(|e| format!("'{}' is not a valid port value: {}", v, e) )
}

pub(crate) fn setup_app<'a, 'b>(program: String, version: &'b str) -> App<'a, 'b> {
  App::new(program)
    .version(version)
    .about("Standalone Pact verifier")
    .version_short("v")
    .arg(Arg::with_name("loglevel")
      .short("l")
      .long("loglevel")
      .takes_value(true)
      .use_delimiter(false)
      .possible_values(&["error", "warn", "info", "debug", "trace", "none"])
      .help("Log level (defaults to warn)"))
    .arg(Arg::with_name("file")
      .short("f")
      .long("file")
      .required_unless_one(&["dir", "url", "broker-url"])
      .takes_value(true)
      .use_delimiter(false)
      .multiple(true)
      .number_of_values(1)
      .empty_values(false)
      .help("Pact file to verify (can be repeated)"))
    .arg(Arg::with_name("dir")
      .short("d")
      .long("dir")
      .required_unless_one(&["file", "url", "broker-url"])
      .takes_value(true)
      .use_delimiter(false)
      .multiple(true)
      .number_of_values(1)
      .empty_values(false)
      .help("Directory of pact files to verify (can be repeated)"))
    .arg(Arg::with_name("url")
      .short("u")
      .long("url")
      .required_unless_one(&["file", "dir", "broker-url"])
      .takes_value(true)
      .use_delimiter(false)
      .multiple(true)
      .number_of_values(1)
      .empty_values(false)
      .help("URL of pact file to verify (can be repeated)"))
    .arg(Arg::with_name("broker-url")
      .short("b")
      .long("broker-url")
      .env("PACT_BROKER_BASE_URL")
      .required_unless_one(&["file", "dir", "url"])
      .requires("provider-name")
      .takes_value(true)
      .use_delimiter(false)
      .multiple(true)
      .number_of_values(1)
      .empty_values(false)
      .help("URL of the pact broker to fetch pacts from to verify (requires the provider name parameter)"))
    .arg(Arg::with_name("hostname")
      .short("h")
      .long("hostname")
      .takes_value(true)
      .use_delimiter(false)
      .help("Provider hostname (defaults to localhost)"))
    .arg(Arg::with_name("port")
      .short("p")
      .long("port")
      .takes_value(true)
      .use_delimiter(false)
      .help("Provider port (defaults to protocol default 80/443)")
      .validator(integer_value))
    .arg(Arg::with_name("scheme")
      .long("scheme")
      .takes_value(true)
      .possible_values(&["http", "https"])
      .default_value("http")
      .help("Provider URI scheme (defaults to http)"))
    .arg(Arg::with_name("provider-name")
      .short("n")
      .long("provider-name")
      .takes_value(true)
      .use_delimiter(false)
      .help("Provider name (defaults to provider)"))
    .arg(Arg::with_name("state-change-url")
      .short("s")
      .long("state-change-url")
      .takes_value(true)
      .use_delimiter(false)
      .help("URL to post state change requests to"))
    .arg(Arg::with_name("state-change-as-query")
      .long("state-change-as-query")
      .help("State change request data will be sent as query parameters instead of in the request body"))
    .arg(Arg::with_name("state-change-teardown")
      .long("state-change-teardown")
      .help("State change teardown requests are to be made after each interaction"))
    .arg(Arg::with_name("filter-description")
      .long("filter-description")
      .takes_value(true)
      .use_delimiter(false)
      .validator(|val| Regex::new(&val)
        .map(|_| ())
        .map_err(|err| format!("'{}' is an invalid filter value: {}", val, err)))
      .help("Only validate interactions whose descriptions match this filter"))
    .arg(Arg::with_name("filter-state")
      .long("filter-state")
      .takes_value(true)
      .use_delimiter(false)
      .conflicts_with("filter-no-state")
      .validator(|val| Regex::new(&val)
        .map(|_| ())
        .map_err(|err| format!("'{}' is an invalid filter value: {}", val, err)))
      .help("Only validate interactions whose provider states match this filter"))
    .arg(Arg::with_name("filter-no-state")
      .long("filter-no-state")
      .conflicts_with("filter-state")
      .help("Only validate interactions that have no defined provider state"))
    .arg(Arg::with_name("filter-consumer")
      .short("c")
      .long("filter-consumer")
      .takes_value(true)
      .multiple(true)
      .empty_values(false)
      .help("Consumer name to filter the pacts to be verified (can be repeated)"))
    .arg(Arg::with_name("user")
      .long("user")
      .env("PACT_BROKER_USERNAME")
      .takes_value(true)
      .use_delimiter(false)
      .number_of_values(1)
      .empty_values(false)
      .conflicts_with("token")
      .help("Username to use when fetching pacts from URLS"))
      .arg(Arg::with_name("password")
      .long("password")
      .env("PACT_BROKER_PASSWORD")
      .takes_value(true)
      .use_delimiter(false)
      .number_of_values(1)
      .empty_values(false)
      .conflicts_with("token")
      .help("Password to use when fetching pacts from URLS"))
      .arg(Arg::with_name("token")
      .short("t")
      .long("token")
      .env("PACT_BROKER_TOKEN")
      .takes_value(true)
      .use_delimiter(false)
      .number_of_values(1)
      .empty_values(false)
      .conflicts_with("user")
      .help("Bearer token to use when fetching pacts from URLS"))
    .arg(Arg::with_name("publish")
      .long("publish")
      .requires("broker-url")
      .requires("provider-version")
      .help("Enables publishing of verification results back to the Pact Broker. Requires the broker-url and provider-version parameters."))
    .arg(Arg::with_name("provider-version")
      .long("provider-version")
      .takes_value(true)
      .use_delimiter(false)
      .number_of_values(1)
      .empty_values(false)
      .help("Provider version that is being verified. This is required when publishing results."))
    .arg(Arg::with_name("build-url")
      .long("build-url")
      .takes_value(true)
      .use_delimiter(false)
      .number_of_values(1)
      .empty_values(false)
      .help("URL of the build to associate with the published verification results."))
    .arg(Arg::with_name("provider-tags")
      .long("provider-tags")
      .takes_value(true)
      .use_delimiter(true)
      .empty_values(false)
      .help("Provider tags to use when publishing results. Accepts comma-separated values."))
    .arg(Arg::with_name("base-path")
      .long("base-path")
      .takes_value(true)
      .use_delimiter(false)
      .empty_values(false)
      .help("Base path to add to all requests"))
    .arg(Arg::with_name("consumer-version-tags")
      .long("consumer-version-tags")
      .takes_value(true)
      .use_delimiter(true)
      .empty_values(false)
      .requires("broker-url")
      .conflicts_with("consumer-version-selectors")
      .help("Consumer tags to use when fetching pacts from the Broker. Accepts comma-separated values."))
    .arg(Arg::with_name("consumer-version-selectors")
      .long("consumer-version-selectors")
      .takes_value(true)
      .use_delimiter(false)
      .multiple(true)
      .number_of_values(1)
      .empty_values(false)
      .requires("broker-url")
      .conflicts_with("consumer-version-tags")
      .help("Consumer version selectors to use when fetching pacts from the Broker. Accepts a JSON string as per https://docs.pact.io/pact_broker/advanced_topics/consumer_version_selectors/"))
    .arg(Arg::with_name("disable-ssl-verification")
      .long("disable-ssl-verification")
      .takes_value(false)
      .help("Disables validation of SSL certificates"))
    .arg(Arg::with_name("enable-pending")
      .long("enable-pending")
      .requires("broker-url")
      .help("Enables Pending Pacts"))
    .arg(Arg::with_name("include-wip-pacts-since")
      .long("include-wip-pacts-since")
      .takes_value(true)
      .use_delimiter(false)
      .number_of_values(1)
      .empty_values(false)
      .requires("broker-url")
      .help("Allow pacts that don't match given consumer selectors (or tags) to  be verified, without causing the overall task to fail. For more information, see https://pact.io/wip"))
    }

#[cfg(test)]
mod test {

  use quickcheck::{TestResult, quickcheck};
  use rand::Rng;
  use super::integer_value;
  use expectest::prelude::*;
  use expectest::expect;
  use pact_matching::s;

  #[test]
  fn validates_integer_value() {
    fn prop(s: String) -> TestResult {
      let mut rng = ::rand::thread_rng();
      if rng.gen() && s.chars().any(|ch| !ch.is_numeric()) {
        TestResult::discard()
      } else {
        let validation = integer_value(s.clone());
        match validation {
          Ok(_) => TestResult::from_bool(!s.is_empty() && s.chars().all(|ch| ch.is_numeric() )),
          Err(_) => TestResult::from_bool(s.is_empty() || s.chars().find(|ch| !ch.is_numeric() ).is_some())
        }
      }
    }
    quickcheck(prop as fn(_) -> _);

    expect!(integer_value(s!("1234"))).to(be_ok());
    expect!(integer_value(s!("1234x"))).to(be_err());
  }
}
<commit_msg>feat: support env vars for filters<commit_after>use clap::{App, Arg};
use regex::Regex;

fn integer_value(v: String) -> Result<(), String> {
  v.parse::<u16>().map(|_| ()).map_err(|e| format!("'{}' is not a valid port value: {}", v, e) )
}

pub(crate) fn setup_app<'a, 'b>(program: String, version: &'b str) -> App<'a, 'b> {
  App::new(program)
    .version(version)
    .about("Standalone Pact verifier")
    .version_short("v")
    .arg(Arg::with_name("loglevel")
      .short("l")
      .long("loglevel")
      .takes_value(true)
      .use_delimiter(false)
      .possible_values(&["error", "warn", "info", "debug", "trace", "none"])
      .help("Log level (defaults to warn)"))
    .arg(Arg::with_name("file")
      .short("f")
      .long("file")
      .required_unless_one(&["dir", "url", "broker-url"])
      .takes_value(true)
      .use_delimiter(false)
      .multiple(true)
      .number_of_values(1)
      .empty_values(false)
      .help("Pact file to verify (can be repeated)"))
    .arg(Arg::with_name("dir")
      .short("d")
      .long("dir")
      .required_unless_one(&["file", "url", "broker-url"])
      .takes_value(true)
      .use_delimiter(false)
      .multiple(true)
      .number_of_values(1)
      .empty_values(false)
      .help("Directory of pact files to verify (can be repeated)"))
    .arg(Arg::with_name("url")
      .short("u")
      .long("url")
      .required_unless_one(&["file", "dir", "broker-url"])
      .takes_value(true)
      .use_delimiter(false)
      .multiple(true)
      .number_of_values(1)
      .empty_values(false)
      .help("URL of pact file to verify (can be repeated)"))
    .arg(Arg::with_name("broker-url")
      .short("b")
      .long("broker-url")
      .env("PACT_BROKER_BASE_URL")
      .required_unless_one(&["file", "dir", "url"])
      .requires("provider-name")
      .takes_value(true)
      .use_delimiter(false)
      .multiple(true)
      .number_of_values(1)
      .empty_values(false)
      .help("URL of the pact broker to fetch pacts from to verify (requires the provider name parameter)"))
    .arg(Arg::with_name("hostname")
      .short("h")
      .long("hostname")
      .takes_value(true)
      .use_delimiter(false)
      .help("Provider hostname (defaults to localhost)"))
    .arg(Arg::with_name("port")
      .short("p")
      .long("port")
      .takes_value(true)
      .use_delimiter(false)
      .help("Provider port (defaults to protocol default 80/443)")
      .validator(integer_value))
    .arg(Arg::with_name("scheme")
      .long("scheme")
      .takes_value(true)
      .possible_values(&["http", "https"])
      .default_value("http")
      .help("Provider URI scheme (defaults to http)"))
    .arg(Arg::with_name("provider-name")
      .short("n")
      .long("provider-name")
      .takes_value(true)
      .use_delimiter(false)
      .help("Provider name (defaults to provider)"))
    .arg(Arg::with_name("state-change-url")
      .short("s")
      .long("state-change-url")
      .takes_value(true)
      .use_delimiter(false)
      .help("URL to post state change requests to"))
    .arg(Arg::with_name("state-change-as-query")
      .long("state-change-as-query")
      .help("State change request data will be sent as query parameters instead of in the request body"))
    .arg(Arg::with_name("state-change-teardown")
      .long("state-change-teardown")
      .help("State change teardown requests are to be made after each interaction"))
    .arg(Arg::with_name("filter-description")
      .long("filter-description")
      .env("PACT_DESCRIPTION")
      .takes_value(true)
      .use_delimiter(false)
      .validator(|val| Regex::new(&val)
        .map(|_| ())
        .map_err(|err| format!("'{}' is an invalid filter value: {}", val, err)))
      .help("Only validate interactions whose descriptions match this filter"))
    .arg(Arg::with_name("filter-state")
      .long("filter-state")
      .env("PACT_PROVIDER_STATE")
      .takes_value(true)
      .use_delimiter(false)
      .conflicts_with("filter-no-state")
      .validator(|val| Regex::new(&val)
        .map(|_| ())
        .map_err(|err| format!("'{}' is an invalid filter value: {}", val, err)))
      .help("Only validate interactions whose provider states match this filter"))
    .arg(Arg::with_name("filter-no-state")
      .long("filter-no-state")
      .env("PACT_PROVIDER_NO_STATE")
      .conflicts_with("filter-state")
      .help("Only validate interactions that have no defined provider state"))
    .arg(Arg::with_name("filter-consumer")
      .short("c")
      .long("filter-consumer")
      .takes_value(true)
      .multiple(true)
      .empty_values(false)
      .help("Consumer name to filter the pacts to be verified (can be repeated)"))
    .arg(Arg::with_name("user")
      .long("user")
      .env("PACT_BROKER_USERNAME")
      .takes_value(true)
      .use_delimiter(false)
      .number_of_values(1)
      .empty_values(false)
      .conflicts_with("token")
      .help("Username to use when fetching pacts from URLS"))
      .arg(Arg::with_name("password")
      .long("password")
      .env("PACT_BROKER_PASSWORD")
      .takes_value(true)
      .use_delimiter(false)
      .number_of_values(1)
      .empty_values(false)
      .conflicts_with("token")
      .help("Password to use when fetching pacts from URLS"))
      .arg(Arg::with_name("token")
      .short("t")
      .long("token")
      .env("PACT_BROKER_TOKEN")
      .takes_value(true)
      .use_delimiter(false)
      .number_of_values(1)
      .empty_values(false)
      .conflicts_with("user")
      .help("Bearer token to use when fetching pacts from URLS"))
    .arg(Arg::with_name("publish")
      .long("publish")
      .requires("broker-url")
      .requires("provider-version")
      .help("Enables publishing of verification results back to the Pact Broker. Requires the broker-url and provider-version parameters."))
    .arg(Arg::with_name("provider-version")
      .long("provider-version")
      .takes_value(true)
      .use_delimiter(false)
      .number_of_values(1)
      .empty_values(false)
      .help("Provider version that is being verified. This is required when publishing results."))
    .arg(Arg::with_name("build-url")
      .long("build-url")
      .takes_value(true)
      .use_delimiter(false)
      .number_of_values(1)
      .empty_values(false)
      .help("URL of the build to associate with the published verification results."))
    .arg(Arg::with_name("provider-tags")
      .long("provider-tags")
      .takes_value(true)
      .use_delimiter(true)
      .empty_values(false)
      .help("Provider tags to use when publishing results. Accepts comma-separated values."))
    .arg(Arg::with_name("base-path")
      .long("base-path")
      .takes_value(true)
      .use_delimiter(false)
      .empty_values(false)
      .help("Base path to add to all requests"))
    .arg(Arg::with_name("consumer-version-tags")
      .long("consumer-version-tags")
      .takes_value(true)
      .use_delimiter(true)
      .empty_values(false)
      .requires("broker-url")
      .conflicts_with("consumer-version-selectors")
      .help("Consumer tags to use when fetching pacts from the Broker. Accepts comma-separated values."))
    .arg(Arg::with_name("consumer-version-selectors")
      .long("consumer-version-selectors")
      .takes_value(true)
      .use_delimiter(false)
      .multiple(true)
      .number_of_values(1)
      .empty_values(false)
      .requires("broker-url")
      .conflicts_with("consumer-version-tags")
      .help("Consumer version selectors to use when fetching pacts from the Broker. Accepts a JSON string as per https://docs.pact.io/pact_broker/advanced_topics/consumer_version_selectors/"))
    .arg(Arg::with_name("disable-ssl-verification")
      .long("disable-ssl-verification")
      .takes_value(false)
      .help("Disables validation of SSL certificates"))
    .arg(Arg::with_name("enable-pending")
      .long("enable-pending")
      .requires("broker-url")
      .help("Enables Pending Pacts"))
    .arg(Arg::with_name("include-wip-pacts-since")
      .long("include-wip-pacts-since")
      .takes_value(true)
      .use_delimiter(false)
      .number_of_values(1)
      .empty_values(false)
      .requires("broker-url")
      .help("Allow pacts that don't match given consumer selectors (or tags) to  be verified, without causing the overall task to fail. For more information, see https://pact.io/wip"))
    }

#[cfg(test)]
mod test {

  use quickcheck::{TestResult, quickcheck};
  use rand::Rng;
  use super::integer_value;
  use expectest::prelude::*;
  use expectest::expect;
  use pact_matching::s;

  #[test]
  fn validates_integer_value() {
    fn prop(s: String) -> TestResult {
      let mut rng = ::rand::thread_rng();
      if rng.gen() && s.chars().any(|ch| !ch.is_numeric()) {
        TestResult::discard()
      } else {
        let validation = integer_value(s.clone());
        match validation {
          Ok(_) => TestResult::from_bool(!s.is_empty() && s.chars().all(|ch| ch.is_numeric() )),
          Err(_) => TestResult::from_bool(s.is_empty() || s.chars().find(|ch| !ch.is_numeric() ).is_some())
        }
      }
    }
    quickcheck(prop as fn(_) -> _);

    expect!(integer_value(s!("1234"))).to(be_ok());
    expect!(integer_value(s!("1234x"))).to(be_err());
  }
}
<|endoftext|>


<commit_before>
use ::{
    EdgeDirection,
    Incoming,
};

use visit::{
    GraphBase,
    GraphRef,
    IntoNodeIdentifiers,
    IntoNeighbors,
    IntoNeighborsDirected,
    IntoExternals,
    Visitable,
};

/// Wrapper type for walking the graph as if all edges are reversed.
#[derive(Copy, Clone)]
pub struct Reversed<G>(pub G);

impl<G: GraphBase> GraphBase for Reversed<G> {
    type NodeId = G::NodeId;
    type EdgeId = G::EdgeId;
}

impl<G: GraphRef> GraphRef for Reversed<G> { }

impl<G> IntoNodeIdentifiers for Reversed<G>
    where G: IntoNodeIdentifiers
{
    type NodeIdentifiers = G::NodeIdentifiers;
    fn node_identifiers(self) -> Self::NodeIdentifiers {
        self.0.node_identifiers()
    }

    fn node_count(&self) -> usize {
        self.0.node_count()
    }
}

impl<G> IntoNeighbors for Reversed<G>
    where G: IntoNeighborsDirected
{
    type Neighbors = G::NeighborsDirected;
    fn neighbors(self, n: G::NodeId) -> G::NeighborsDirected
    {
        self.0.neighbors_directed(n, Incoming)
    }
}

impl<G> IntoNeighborsDirected for Reversed<G>
    where G: IntoNeighborsDirected
{
    type NeighborsDirected = G::NeighborsDirected;
    fn neighbors_directed(self, n: G::NodeId, d: EdgeDirection)
        -> G::NeighborsDirected
    {
        self.0.neighbors_directed(n, d.opposite())
    }
}

impl<G> IntoExternals for Reversed<G>
    where G: IntoExternals,
{
    type Externals = G::Externals;
    fn externals(self, d: EdgeDirection) -> G::Externals {
        self.0.externals(d.opposite())
    }
}

impl<G: Visitable> Visitable for Reversed<G>
{
    type Map = G::Map;
    fn visit_map(&self) -> G::Map {
        self.0.visit_map()
    }
    fn reset_map(&self, map: &mut Self::Map) {
        self.0.reset_map(map);
    }
}

<commit_msg>Implement IntoEdgeReferences and related items for Reversed<commit_after>
use ::{
    EdgeDirection,
    Incoming,
};

use visit::{
    GraphBase,
    GraphRef,
    GraphEdgeRef,
    IntoNodeIdentifiers,
    IntoNeighbors,
    IntoNeighborsDirected,
    IntoEdgeReferences,
    IntoExternals,
    Visitable,
    EdgeRef,
};

/// Wrapper type for walking the graph as if all edges are reversed.
#[derive(Copy, Clone)]
pub struct Reversed<G>(pub G);

impl<G: GraphBase> GraphBase for Reversed<G> {
    type NodeId = G::NodeId;
    type EdgeId = G::EdgeId;
}

impl<G: GraphRef> GraphRef for Reversed<G> { }

impl<G> IntoNodeIdentifiers for Reversed<G>
    where G: IntoNodeIdentifiers
{
    type NodeIdentifiers = G::NodeIdentifiers;
    fn node_identifiers(self) -> Self::NodeIdentifiers {
        self.0.node_identifiers()
    }

    fn node_count(&self) -> usize {
        self.0.node_count()
    }
}

impl<G> IntoNeighbors for Reversed<G>
    where G: IntoNeighborsDirected
{
    type Neighbors = G::NeighborsDirected;
    fn neighbors(self, n: G::NodeId) -> G::NeighborsDirected
    {
        self.0.neighbors_directed(n, Incoming)
    }
}

impl<G> IntoNeighborsDirected for Reversed<G>
    where G: IntoNeighborsDirected
{
    type NeighborsDirected = G::NeighborsDirected;
    fn neighbors_directed(self, n: G::NodeId, d: EdgeDirection)
        -> G::NeighborsDirected
    {
        self.0.neighbors_directed(n, d.opposite())
    }
}

impl<G> IntoExternals for Reversed<G>
    where G: IntoExternals,
{
    type Externals = G::Externals;
    fn externals(self, d: EdgeDirection) -> G::Externals {
        self.0.externals(d.opposite())
    }
}

impl<G: Visitable> Visitable for Reversed<G>
{
    type Map = G::Map;
    fn visit_map(&self) -> G::Map {
        self.0.visit_map()
    }
    fn reset_map(&self, map: &mut Self::Map) {
        self.0.reset_map(map);
    }
}

/// An edge reference for `Reversed`.
#[derive(Copy, Clone, Debug)]
pub struct ReversedEdgeRef<R>(R);

/// An edge reference
impl<R> EdgeRef for ReversedEdgeRef<R>
    where R: EdgeRef,
{
    type NodeId = R::NodeId;
    type EdgeId = R::EdgeId;
    type Weight = R::Weight;
    fn source(&self) -> Self::NodeId {
        self.0.target()
    }
    fn target(&self) -> Self::NodeId {
        self.0.source()
    }
    fn weight(&self) -> &Self::Weight {
        self.0.weight()
    }
    fn id(&self) -> Self::EdgeId {
        self.0.id()
    }
}

impl<G> GraphEdgeRef for Reversed<G>
    where G: GraphEdgeRef
{
    type EdgeRef = ReversedEdgeRef<G::EdgeRef>;
}

impl<G> IntoEdgeReferences for Reversed<G>
    where G: IntoEdgeReferences
{
    type EdgeReferences = ReversedEdgeReferences<G::EdgeReferences>;
    fn edge_references(self) -> Self::EdgeReferences {
        ReversedEdgeReferences {
            iter: self.0.edge_references(),
        }
    }
}

/// An iterator of edge references for `Reversed`.
pub struct ReversedEdgeReferences<I> {
    iter: I,
}

impl<I> Iterator for ReversedEdgeReferences<I>
    where I: Iterator,
          I::Item: EdgeRef,
{
    type Item = ReversedEdgeRef<I::Item>;
    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(ReversedEdgeRef)
    }
}

<|endoftext|>


<commit_before>use std::os::getenv;

struct HttpContext{
    request: Request,
    response: Response
}

impl HttpContext{
    fn create() -> HttpContext{
        HttpContext{
            request: Request::populate(),
            response: Response::new()
        }
    }
}

struct Request {
    path: ~str,
    querystring: ~str
}

impl Request {
    fn populate() -> Request {
        Request{
            path: getenv("PATH_INFO").unwrap_or(~""),
            querystring: getenv("QUERY_STRING").unwrap_or(~"")
        }
    }
}

struct Response{
    contenttype: ~str,
    body: ~str
}

impl Response{
    fn new() -> Response{
        Response{contenttype: ~"text/plain", body: ~""}
    }
}

struct Route {
    path: ~str,
    handler: ~fn(&mut HttpContext)
}

struct Router{
    routes: ~[Route],
}

impl Router{
    fn new() -> Router{
        Router{routes: ~[]}
    }
    fn add(&mut self, r: Route){
        self.routes.push(r);
    }
    fn execute(&self, c: &mut HttpContext) {
        for route in self.routes.iter(){
            if(route.path == c.request.path){
                (route.handler)(c);
            }
        }
    }
    fn controller<T>(~self, creator: ~fn(&HttpContext) -> T) -> ControllerBox<T>
    {
        ControllerBox{
            router: self,
            route: ~Route{path: ~"", handler: default_handler},
            creator: Some(creator)
        }
    }
}

trait HttpController{

}

struct ControllerBox<T>{
    router: ~Router,
    route: ~Route,
    creator: Option<~fn(&HttpContext) -> T>
}

impl<T> ControllerBox<T>{
    fn handles(@mut self, path: ~str) -> @mut ControllerBox<T>{
        self.route.path=path;
        self
    }
    fn with<'r>(&'r mut self, invoker: ~fn(&mut T)) -> &'r mut ControllerBox<T>{
        let tmp=self.creator.take();

        self.route.handler = |c| {
            match tmp {
                None => (),
                Some(ref t) => {
                    let mut ctrl=(*t)(c);
                    invoker(&mut ctrl);
                }
            };
        };
        self
    }
}
/*
struct Meh{
    biz: ~fn(int) -> int
}

impl Meh{
    fn foo(@mut self
}
*/

struct TestController{
    context: ~HttpContext
}

impl TestController{
    fn new(c: ~HttpContext) -> TestController{
        TestController{ context: c}
    }
    fn index(&mut self) {
        self.context.response.body.push_str("test index");
    }
}

fn default_handler(context: &mut HttpContext){
    context.response.body.push_str("404 not found");
}

fn index(context: &mut HttpContext){
    context.response.body.push_str("yay index");
}

fn foo(context: &mut HttpContext){
    context.response.body.push_str("yay foo");
}

fn main() {
    let mut context=HttpContext::create();
    let mut router=Router::new();
    router.add(Route{path: ~"", handler: index});
    router.add(Route{path: ~"/foo", handler: foo});

    let mut test = router.controller(|c| TestController::new(c));
    test.handles(~"/test").with(|c| c.index());

    router.execute(&mut context);

    println(context.response.contenttype);
    println("");
    println(context.response.body);
}<commit_msg>closer maybe<commit_after>use std::os::getenv;

struct HttpContext{
    request: Request,
    response: Response
}

impl HttpContext{
    fn create() -> HttpContext{
        HttpContext{
            request: Request::populate(),
            response: Response::new()
        }
    }
}

struct Request {
    path: ~str,
    querystring: ~str
}

impl Request {
    fn populate() -> Request {
        Request{
            path: getenv("PATH_INFO").unwrap_or(~""),
            querystring: getenv("QUERY_STRING").unwrap_or(~"")
        }
    }
}

struct Response{
    contenttype: ~str,
    body: ~str
}

impl Response{
    fn new() -> Response{
        Response{contenttype: ~"text/plain", body: ~""}
    }
}

struct Route {
    path: ~str,
    handler: ~fn(@mut HttpContext)
}

struct Router{
    routes: ~[Route],
}

impl Router{
    fn new() -> Router{
        Router{routes: ~[]}
    }
    fn add(&mut self, r: Route){
        self.routes.push(r);
    }
    fn execute(&self, c: @mut HttpContext) {
        for route in self.routes.iter(){
            if(route.path == c.request.path){
                (route.handler)(c);
            }
        }
    }
    fn controller<T>(~self, creator: ~fn(@mut HttpContext) -> T) -> ControllerBox<T>
    {
        ControllerBox{
            router: self,
            route: ~Route{path: ~"", handler: default_handler},
            creator: Some(creator)
        }
    }
}

trait HttpController{

}

struct ControllerBox<T>{
    router: ~Router,
    route: ~Route,
    creator: Option<~fn(@mut HttpContext) -> T>
}

impl<T> ControllerBox<T>{
    fn handles(@mut self, path: ~str) -> @mut ControllerBox<T>{
        self.route.path=path;
        self
    }
    fn with<'r>(&'r mut self, invoker: ~fn(&mut T)) -> &'r mut ControllerBox<T>{
        let tmp=self.creator.take();

        self.route.handler = |c| {
            match tmp {
                None => (),
                Some(ref t) => {
                    let mut ctrl=(*t)(c);
                    invoker(&mut ctrl);
                }
            };
        };
        self
    }
}
/*
struct Meh{
    biz: ~fn(int) -> int
}

impl Meh{
    fn foo(@mut self
}
*/

struct TestController{
    context: @mut HttpContext
}

impl TestController{
    fn new(c: @mut HttpContext) -> TestController{
        TestController{ context: c}
    }
    fn index(&mut self) {
        self.context.response.body.push_str("test index");
    }
}

fn default_handler(context: @mut HttpContext){
    context.response.body.push_str("404 not found");
}

fn index(context: @mut HttpContext){
    context.response.body.push_str("yay index");
}

fn foo(context: @mut HttpContext){
    context.response.body.push_str("yay foo");
}

fn main() {
    let mut context=HttpContext::create();
    let mut router=~Router::new();
    router.add(Route{path: ~"", handler: index});
    router.add(Route{path: ~"/foo", handler: foo});

    let mut test = @mut router.controller(|c| TestController::new(c));
    test.handles(~"/test").with(|c| c.index());

    router.execute(@mut context);

    println(context.response.contenttype);
    println("");
    println(context.response.body);
}<|endoftext|>


<commit_before>use rustc_serialize::json;
use ::xflow::errors::*;

pub type XFlowEdge = [i32; 2];

// Automatically generate `RustcDecodable` and `RustcEncodable` trait
// implementations

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct XFlowStruct {
    pub id:           String,
    pub version:      i32,
    pub name:         String,
    pub requirements: Vec<XFlowRequirement>,
    pub variables:    XFlowVariables,
    pub nodes:        Vec<XFlowNode>,
    pub edges:        Vec<XFlowEdge>,
    pub branches:     Vec<XFlowBranch>,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct XFlowRequirement {
    pub xtype:   String,
    pub version: i32,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct XFlowVariableDefinition {
    pub name:  String,
    pub vtype: String,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct XFlowVariable {
    pub name:  String,
    pub vtype: String,
    pub value: String,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct XFlowVariables {
    pub input:  Vec<XFlowVariable>,
    pub local:  Vec<XFlowVariable>,
    pub output: Vec<XFlowVariableDefinition>,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct XFlowNode {
    pub id:       i32,
    pub nodetype: String,
    pub label:    String,
    pub action:   String,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct XFlowBranch {
    pub name: String,
    pub edge: XFlowEdge,
}

impl XFlowStruct {
    /// Constructs a new `XFlowStruct`
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// ```
    pub fn new() -> XFlowStruct {
        XFlowStruct {
            id:          "".to_string(),
            name:        "".to_string(),
            version:      1,
            requirements: Vec::<XFlowRequirement>::new(),
            variables:    XFlowVariables {
                input:  Vec::<XFlowVariable>::new(),
                local:  Vec::<XFlowVariable>::new(),
                output: Vec::<XFlowVariableDefinition>::new(),
            },
            nodes:        Vec::<XFlowNode>::new(),
            edges:        Vec::<XFlowEdge>::new(),
            branches:     Vec::<XFlowBranch>::new(),
        }
    }

    /// Return a string representation of the XFlowStruct
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// xfs.to_string();
    /// ```
    pub fn to_string(&self) -> String {
        format!("xflow {}", self.id)
    }

    /// Get `XFlowNode`s of `nodetype` and `action`
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// xfs.get_nodes_by("flow", "start");
    /// ```
    pub fn get_nodes_by(&self, nodetype:&str, action:&str) -> Vec<&XFlowNode> {

        let res:Vec<&XFlowNode> = self.nodes.iter().filter({|node|
            node.nodetype == nodetype &&
                node.action == action
        }).collect();

        res
    }

    /// Get `XFlowNode`s of `nodetype`
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// xfs.get_nodes_of_type("flow");
    /// ```
    pub fn get_nodes_of_type(&self, nodetype:&str) -> Vec<&XFlowNode> {

        let res:Vec<&XFlowNode> = self.nodes.iter().filter({|node|
            node.nodetype == nodetype
        }).collect();

        res
    }

    /// Return a JSON representation of the XFlowStruct
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// xfs.to_json();
    /// ```
    pub fn to_json(&self) -> String {
        json::encode(&self).unwrap()
    }

    /// Initialize a XFlowStruct from a JSON string
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    ///
    /// let empty_flow = "{\"id\":\"empty\",\"name\":\"empty\",\"version\":1,\"requirements\":[{\"xtype\":\"flow\",\"version\":1},{\"xtype\":\"flox\",\"version\":1}],\"variables\":{\"input\":[],\"output\":[],\"local\":[]},\"nodes\":[],\"edges\":[],\"branches\":[]}";
    ///
    /// let xfs = XFlowStruct::from_json(empty_flow);
    /// ```
    pub fn from_json(json_string:&str) -> XFlowStruct {
        let xfs:XFlowStruct = json::decode(json_string).unwrap();
        xfs
    }

    pub fn get_in_edges(&self, node:&XFlowNode) -> Vec<&XFlowEdge> {

        let res:Vec<&XFlowEdge> = self.edges.iter().filter({|edge|
            edge[1] == node.id
        }).collect();

        res
    }

    pub fn get_out_edges(&self, node:&XFlowNode) -> Vec<&XFlowEdge> {

        let res:Vec<&XFlowEdge> = self.edges.iter().filter({|edge|
            edge[0] == node.id
        }).collect();

        res
    }

    pub fn get_branches_for(&self, edge:&XFlowEdge) -> Vec<&XFlowBranch> {

        let res:Vec<&XFlowBranch> = self.branches.iter().filter({|branch|
            edge[0] == branch.edge[0] &&
                edge[1] == branch.edge[1]
        }).collect();

        res

    }

    pub fn get_entry_node(&self) -> Result<&XFlowNode, XFlowError> {
        let res = self.get_nodes_by("flow", "start");
        match res.len() {
            0 => Err(XFlowError::NoEntryNode),
            1 => Ok(res[0]),
            _ => Err(XFlowError::MultipleEntryNodes),
        }
    }

    pub fn get_terminal_nodes(&self) -> Result<Vec<&XFlowNode>, XFlowError> {
        let res = self.get_nodes_by("flow", "end");
        match res.len() {
            0 => Err(XFlowError::NoTerminalNode),
            _ => Ok(res),
        }
    }

}

<commit_msg>Remove Clone from xfstruct<commit_after>use rustc_serialize::json;
use ::xflow::errors::*;

pub type XFlowEdge = [i32; 2];

// Automatically generate `RustcDecodable` and `RustcEncodable` trait
// implementations

#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct XFlowStruct {
    pub id:           String,
    pub version:      i32,
    pub name:         String,
    pub requirements: Vec<XFlowRequirement>,
    pub variables:    XFlowVariables,
    pub nodes:        Vec<XFlowNode>,
    pub edges:        Vec<XFlowEdge>,
    pub branches:     Vec<XFlowBranch>,
}

#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct XFlowRequirement {
    pub xtype:   String,
    pub version: i32,
}

#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct XFlowVariableDefinition {
    pub name:  String,
    pub vtype: String,
}

#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct XFlowVariable {
    pub name:  String,
    pub vtype: String,
    pub value: String,
}

#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct XFlowVariables {
    pub input:  Vec<XFlowVariable>,
    pub local:  Vec<XFlowVariable>,
    pub output: Vec<XFlowVariableDefinition>,
}

#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct XFlowNode {
    pub id:       i32,
    pub nodetype: String,
    pub label:    String,
    pub action:   String,
}

#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct XFlowBranch {
    pub name: String,
    pub edge: XFlowEdge,
}

impl XFlowStruct {
    /// Constructs a new `XFlowStruct`
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// ```
    pub fn new() -> XFlowStruct {
        XFlowStruct {
            id:          "".to_string(),
            name:        "".to_string(),
            version:      1,
            requirements: Vec::<XFlowRequirement>::new(),
            variables:    XFlowVariables {
                input:  Vec::<XFlowVariable>::new(),
                local:  Vec::<XFlowVariable>::new(),
                output: Vec::<XFlowVariableDefinition>::new(),
            },
            nodes:        Vec::<XFlowNode>::new(),
            edges:        Vec::<XFlowEdge>::new(),
            branches:     Vec::<XFlowBranch>::new(),
        }
    }

    /// Return a string representation of the XFlowStruct
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// xfs.to_string();
    /// ```
    pub fn to_string(&self) -> String {
        format!("xflow {}", self.id)
    }

    /// Get `XFlowNode`s of `nodetype` and `action`
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// xfs.get_nodes_by("flow", "start");
    /// ```
    pub fn get_nodes_by(&self, nodetype:&str, action:&str) -> Vec<&XFlowNode> {

        let res:Vec<&XFlowNode> = self.nodes.iter().filter({|node|
            node.nodetype == nodetype &&
                node.action == action
        }).collect();

        res
    }

    /// Get `XFlowNode`s of `nodetype`
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// xfs.get_nodes_of_type("flow");
    /// ```
    pub fn get_nodes_of_type(&self, nodetype:&str) -> Vec<&XFlowNode> {

        let res:Vec<&XFlowNode> = self.nodes.iter().filter({|node|
            node.nodetype == nodetype
        }).collect();

        res
    }

    /// Return a JSON representation of the XFlowStruct
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// xfs.to_json();
    /// ```
    pub fn to_json(&self) -> String {
        json::encode(&self).unwrap()
    }

    /// Initialize a XFlowStruct from a JSON string
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    ///
    /// let empty_flow = "{\"id\":\"empty\",\"name\":\"empty\",\"version\":1,\"requirements\":[{\"xtype\":\"flow\",\"version\":1},{\"xtype\":\"flox\",\"version\":1}],\"variables\":{\"input\":[],\"output\":[],\"local\":[]},\"nodes\":[],\"edges\":[],\"branches\":[]}";
    ///
    /// let xfs = XFlowStruct::from_json(empty_flow);
    /// ```
    pub fn from_json(json_string:&str) -> XFlowStruct {
        let xfs:XFlowStruct = json::decode(json_string).unwrap();
        xfs
    }

    pub fn get_in_edges(&self, node:&XFlowNode) -> Vec<&XFlowEdge> {

        let res:Vec<&XFlowEdge> = self.edges.iter().filter({|edge|
            edge[1] == node.id
        }).collect();

        res
    }

    pub fn get_out_edges(&self, node:&XFlowNode) -> Vec<&XFlowEdge> {

        let res:Vec<&XFlowEdge> = self.edges.iter().filter({|edge|
            edge[0] == node.id
        }).collect();

        res
    }

    pub fn get_branches_for(&self, edge:&XFlowEdge) -> Vec<&XFlowBranch> {

        let res:Vec<&XFlowBranch> = self.branches.iter().filter({|branch|
            edge[0] == branch.edge[0] &&
                edge[1] == branch.edge[1]
        }).collect();

        res

    }

    pub fn get_entry_node(&self) -> Result<&XFlowNode, XFlowError> {
        let res = self.get_nodes_by("flow", "start");
        match res.len() {
            0 => Err(XFlowError::NoEntryNode),
            1 => Ok(res[0]),
            _ => Err(XFlowError::MultipleEntryNodes),
        }
    }

    pub fn get_terminal_nodes(&self) -> Result<Vec<&XFlowNode>, XFlowError> {
        let res = self.get_nodes_by("flow", "end");
        match res.len() {
            0 => Err(XFlowError::NoTerminalNode),
            _ => Ok(res),
        }
    }

}

<|endoftext|>