<commit_before>//
// Copyright:: Copyright (c) 2015 Chef Software, Inc.
// License:: Apache License, Version 2.0
//
// 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.
//

extern crate regex;
#[no_link] extern crate regex_macros;
extern crate clap;
#[macro_use] extern crate log;
extern crate env_logger;
extern crate term;
#[macro_use] extern crate hyper;
extern crate delivery;
extern crate rustc_serialize;
extern crate time;

use delivery::cli;

fn main() {
    env_logger::init().unwrap();
    cli::run();
}
<commit_msg>Make `make clean build` work again by removing regex_macros<commit_after>//
// Copyright:: Copyright (c) 2015 Chef Software, Inc.
// License:: Apache License, Version 2.0
//
// 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.
//

extern crate regex;
extern crate clap;
#[macro_use] extern crate log;
extern crate env_logger;
extern crate term;
#[macro_use] extern crate hyper;
extern crate delivery;
extern crate rustc_serialize;
extern crate time;

use delivery::cli;

fn main() {
    env_logger::init().unwrap();
    cli::run();
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::env;
use std::fmt;
use std::io;
use std::io::Write;
use std::sync::Mutex;

extern crate syn;
use syn::*;

mod rust_lib;

#[derive(Debug)]
struct ConvertedType {
    /// The type converted to C (e.g. `uint32_t`)
    prefix: String,
    /// Stuff that might need to go after the identifier (e.g. `[3]` for an array).
    postfix: String,
}

impl ConvertedType {
    fn new<T: Into<String>>(pre: T, post: String) -> Self {
        ConvertedType {
            prefix: pre.into(),
            postfix: post
        }
    }

    fn format_with_ident(&self, ident: &Ident) -> String {
        format!("{} {}{}", &self.prefix, &ident.to_string(), &self.postfix)
    }
}

impl Into<String> for ConvertedType {
    fn into(self) -> String {
        let mut str = String::from(self.prefix);
        str.push_str(&self.postfix);
        str
    }
}

impl From<String> for ConvertedType {
    fn from(str: String) -> ConvertedType {
        ConvertedType {
            prefix: str,
            postfix: String::new()
        }
    }
}

impl fmt::Display for ConvertedType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}{}", &self.prefix, &self.postfix)
    }
}

fn has_attribute(target: MetaItem, attrs: &Vec<Attribute>) -> bool {
    return attrs
               .iter()
               .any(|ref attr| attr.style == AttrStyle::Outer && attr.value == target);
}

fn has_no_mangle(attrs: &Vec<Attribute>) -> bool {
    has_attribute(MetaItem::Word(Ident::new("no_mangle")), attrs)
}

fn wr_func_body(attrs: &Vec<Attribute>) -> String {
    if has_attribute(MetaItem::Word(Ident::new("destructor_safe")), attrs) {
        String::from("WR_DESTRUCTOR_SAFE_FUNC")
    } else {
        String::from("WR_FUNC")
    }
}

fn is_repr_c(attrs: &Vec<Attribute>) -> bool {
    let repr_args = vec![NestedMetaItem::MetaItem(MetaItem::Word(Ident::new("C")))];
    has_attribute(MetaItem::List(Ident::new("repr"), repr_args), attrs)
}

fn is_repr_u32(attrs: &Vec<Attribute>) -> bool {
    let repr_args = vec![NestedMetaItem::MetaItem(MetaItem::Word(Ident::new("u32")))];
    has_attribute(MetaItem::List(Ident::new("repr"), repr_args), attrs)
}

fn is_c_abi(abi: &Option<Abi>) -> bool {
    abi == &Some(Abi::Named(String::from("C")))
}

fn map_path(p: &Path) -> ConvertedType {
    let l = p.segments[0].ident.to_string();
    let mut c = match l.as_ref() {
        "usize" => "size_t".to_string(),
        "u8" => "uint8_t".to_string(),
        "u32" => "uint32_t".to_string(),
        "u64" => "uint64_t".to_string(),
        "i8" => "int8_t".to_string(),
        "i32" => "int32_t".to_string(),
        "i64" => "int64_t".to_string(),
        "f32" => "float".to_string(),
        "c_void" => "void".to_string(),
        _ => l,
    };
    if let PathParameters::AngleBracketed(ref d) = p.segments[0].parameters {
        let template_args = d.types
            .iter()
            .map(|ty| map_ty(ty).into())
            .collect::<Vec<String>>()
            .join(", ");
        if !template_args.is_empty() {
            c.push('<');
            c.push_str(&template_args);
            c.push('>');
        }
    }
    ConvertedType::from(c)
}

fn map_mut_ty(mut_ty: &MutTy) -> ConvertedType {
    map_ty(&mut_ty.ty)
}

fn map_ty(ty: &Ty) -> ConvertedType {
    match ty {
        &Ty::Path(_, ref p) => map_path(p),
        &Ty::Ptr(ref p) => ConvertedType::from(format!("{}*", map_ty(&p.ty))),
        &Ty::Rptr(_, ref mut_ty) => ConvertedType::from(format!("{}*", map_mut_ty(mut_ty))),
        &Ty::Array(ref p, ConstExpr::Lit(Lit::Int(sz, _))) => ConvertedType::new(map_ty(&p), format!("[{}]", sz)),
        _ => ConvertedType::from(format!("unknown {:?}", ty)),
    }
}

fn map_return_type(ret: &FunctionRetTy) -> ConvertedType {
    match ret {
        &FunctionRetTy::Default => ConvertedType::from("void".to_string()),
        &FunctionRetTy::Ty(ref ty) => map_ty(ty),
    }
}

fn map_arg(f: &FnArg) -> String {
    match f {
        &FnArg::Captured(Pat::Ident(_, ref ident, _), ref ty) => map_ty(ty).format_with_ident(ident),
        _ => "unknown".to_string(),
    }
}

fn map_field(f: &Field) -> String {
    let mut ret = String::from("  ");
    let converted = map_ty(&f.ty);
    ret.push_str(&converted.format_with_ident(f.ident.as_ref().expect("Struct fields must have idents")));
    ret.push_str(";\n");
    ret
}

fn map_generic_param(t: &TyParam) -> String {
    let mut ret = String::from("typename ");
    ret.push_str(&t.ident.to_string());
    ret
}

fn fold_enum_variants(accum: (String, i32), v: &Variant) -> (String, i32) {
    // `accum` contains the combined string of converted enum variants so far, to which
    // we will append the converted version of `v`. The other thing in `accum` is the
    // value of the previous variant. If `v` has an explicit value we keep that, otherwise
    // we increment the value of the previous variant to get the new one. This is all
    // so that we properly support enums with explicitly-specified and discontinuous
    // values.
    let mut ret = accum.0;
    ret.push_str("  ");
    ret.push_str(&v.ident.to_string());
    ret.push_str(" = ");
    let new_value = match &v.discriminant {
        &None => accum.1 + 1,
        &Some(ConstExpr::Lit(Lit::Int(ref specified_value, _))) => *specified_value as i32,
        &Some(_) => {
            // we don't handle this yet, so just put in something that will fail C compilation
            writeln!(io::stderr(), "warning, unsupported enum discriminant").unwrap();
            ret.push_str("???");
            accum.1 + 1
        }
    };
    ret.push_str(&new_value.to_string());
    ret.push_str(",\n");
    (ret, new_value)
}

/// A structure to store all the results of converting Rust stuff to C
/// stuff, so that we can pick and choose what we output.
struct ConversionResults {
    /// This holds the C function signatures of no_mangle rust functions,
    /// in the order that they were encountered in Rust.
    funcs: Vec<String>,
    /// This holds the C conversions of repr(C) structs and repr(u32) enums
    /// from Rust. The 'ds' in the name stands for 'data structures'. The
    /// key of the map is the name of the type, and the value is the C code.
    c_ds: BTreeMap<String, String>,
    /// This holds the dependency tree. If a struct contains another struct
    /// or an enum it will be in this map. The key is the dependent type,
    /// the list of values are all the things it depends on.
    _dep_tree: BTreeMap<String, Vec<String>>,
}

fn main() {
    let p = env::args().nth(1).unwrap();

    let results = Mutex::new(ConversionResults {
        funcs: Vec::new(),
        c_ds: BTreeMap::new(),
        _dep_tree: BTreeMap::new(),
    });

    rust_lib::parse(p, &|mod_name, items| {
        for item in items {
            match item.node {
                ItemKind::Fn(ref decl,
                             ref _unsafe,
                             ref _const,
                             ref abi,
                             ref _generic,
                             ref _block) => {
                    writeln!(io::stderr(), "processing function {}::{}", mod_name, &item.ident).unwrap();
                    if has_no_mangle(&item.attrs) && is_c_abi(&abi) {
                        results.lock().unwrap().funcs.push(
                            format!("WR_INLINE {}\n{}({})\n{};\n",
                                    map_return_type(&decl.output),
                                    item.ident,
                                    decl.inputs
                                        .iter()
                                        .map(map_arg)
                                        .collect::<Vec<_>>()
                                        .join(", "),
                                    wr_func_body(&item.attrs)));
                    }
                }
                ItemKind::Struct(ref variant,
                                 ref generics) => {
                    writeln!(io::stderr(), "processing struct {}::{}", mod_name, &item.ident).unwrap();
                    if is_repr_c(&item.attrs) {
                        if let &VariantData::Struct(ref fields) = variant {
                            let mut c_struct = String::new();
                            if !generics.ty_params.is_empty() {
                                c_struct.push_str(&(
                                    format!("template<{}>",
                                            generics.ty_params
                                                    .iter()
                                                    .map(map_generic_param)
                                                    .collect::<Vec<_>>()
                                                    .join(", "))));
                            }
                            c_struct.push_str(&(
                                format!("struct {} {{\n{}}};\n",
                                        item.ident,
                                        fields.iter()
                                              .map(map_field)
                                              .collect::<String>())));
                            results.lock().unwrap().c_ds.insert(
                                item.ident.to_string(),
                                c_struct);
                        }
                    }
                }
                ItemKind::Enum(ref variants, ref _generics) => {
                    writeln!(io::stderr(), "processing enum {}::{}", mod_name, &item.ident).unwrap();
                    if is_repr_u32(&item.attrs) {
                        let c_enum = format!("enum class {}: uint32_t {{\n{}\n  Sentinel /* this must be last for serialization purposes. */\n}};\n",
                                             item.ident,
                                             variants.iter()
                                                     .fold((String::new(), -1), fold_enum_variants)
                                                     .0);
                        results.lock().unwrap().c_ds.insert(
                            item.ident.to_string(),
                            c_enum);
                    }
                }
                _ => {}
            }
        }
    });
    for (_, c_stuff) in &results.lock().unwrap().c_ds {
        println!("{}", c_stuff);
    }
    for func in &results.lock().unwrap().funcs {
        println!("{}", func);
    }
}
<commit_msg>Avoid lossy conversions from ConvertedType to ConvertedType through String<commit_after>use std::collections::BTreeMap;
use std::env;
use std::fmt;
use std::io;
use std::io::Write;
use std::sync::Mutex;

extern crate syn;
use syn::*;

mod rust_lib;

#[derive(Debug, Clone)]
struct ConvertedType {
    /// The type converted to C (e.g. `uint32_t`)
    prefix: String,
    /// Stuff that might need to go after the identifier (e.g. `[3]` for an array).
    postfix: String,
}

impl ConvertedType {
    fn append_prefix(&self, str: &str) -> ConvertedType {
        let mut clone = self.clone();
        clone.prefix.push_str(str);
        clone
    }

    fn append_postfix(&self, str: &str) -> ConvertedType {
        let mut clone = self.clone();
        clone.postfix.push_str(str);
        clone
    }

    fn format_with_ident(&self, ident: &Ident) -> String {
        format!("{} {}{}", &self.prefix, &ident.to_string(), &self.postfix)
    }
}

impl From<String> for ConvertedType {
    fn from(str: String) -> ConvertedType {
        ConvertedType {
            prefix: str,
            postfix: String::new()
        }
    }
}

impl fmt::Display for ConvertedType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}{}", &self.prefix, &self.postfix)
    }
}

fn has_attribute(target: MetaItem, attrs: &Vec<Attribute>) -> bool {
    return attrs
               .iter()
               .any(|ref attr| attr.style == AttrStyle::Outer && attr.value == target);
}

fn has_no_mangle(attrs: &Vec<Attribute>) -> bool {
    has_attribute(MetaItem::Word(Ident::new("no_mangle")), attrs)
}

fn wr_func_body(attrs: &Vec<Attribute>) -> String {
    if has_attribute(MetaItem::Word(Ident::new("destructor_safe")), attrs) {
        String::from("WR_DESTRUCTOR_SAFE_FUNC")
    } else {
        String::from("WR_FUNC")
    }
}

fn is_repr_c(attrs: &Vec<Attribute>) -> bool {
    let repr_args = vec![NestedMetaItem::MetaItem(MetaItem::Word(Ident::new("C")))];
    has_attribute(MetaItem::List(Ident::new("repr"), repr_args), attrs)
}

fn is_repr_u32(attrs: &Vec<Attribute>) -> bool {
    let repr_args = vec![NestedMetaItem::MetaItem(MetaItem::Word(Ident::new("u32")))];
    has_attribute(MetaItem::List(Ident::new("repr"), repr_args), attrs)
}

fn is_c_abi(abi: &Option<Abi>) -> bool {
    abi == &Some(Abi::Named(String::from("C")))
}

fn map_path(p: &Path) -> ConvertedType {
    let l = p.segments[0].ident.to_string();
    let mut c = match l.as_ref() {
        "usize" => "size_t".to_string(),
        "u8" => "uint8_t".to_string(),
        "u32" => "uint32_t".to_string(),
        "u64" => "uint64_t".to_string(),
        "i8" => "int8_t".to_string(),
        "i32" => "int32_t".to_string(),
        "i64" => "int64_t".to_string(),
        "f32" => "float".to_string(),
        "c_void" => "void".to_string(),
        _ => l,
    };
    if let PathParameters::AngleBracketed(ref d) = p.segments[0].parameters {
        let template_args = d.types
            .iter()
            .map(|ty| map_ty(ty).to_string())
            .collect::<Vec<String>>()
            .join(", ");
        if !template_args.is_empty() {
            c.push('<');
            c.push_str(&template_args);
            c.push('>');
        }
    }
    ConvertedType::from(c)
}

fn map_mut_ty(mut_ty: &MutTy) -> ConvertedType {
    map_ty(&mut_ty.ty)
}

fn map_ty(ty: &Ty) -> ConvertedType {
    match ty {
        &Ty::Path(_, ref p) => map_path(p),
        &Ty::Ptr(ref p) => map_ty(&p.ty).append_prefix("*"),
        &Ty::Rptr(_, ref mut_ty) => map_mut_ty(mut_ty).append_prefix("*"),
        &Ty::Array(ref p, ConstExpr::Lit(Lit::Int(sz, _))) => map_ty(&p).append_postfix(&format!("[{}]", sz)),
        _ => ConvertedType::from(format!("unknown {:?}", ty)),
    }
}

fn map_return_type(ret: &FunctionRetTy) -> ConvertedType {
    match ret {
        &FunctionRetTy::Default => ConvertedType::from("void".to_string()),
        &FunctionRetTy::Ty(ref ty) => map_ty(ty),
    }
}

fn map_arg(f: &FnArg) -> String {
    match f {
        &FnArg::Captured(Pat::Ident(_, ref ident, _), ref ty) => map_ty(ty).format_with_ident(ident),
        _ => "unknown".to_string(),
    }
}

fn map_field(f: &Field) -> String {
    let mut ret = String::from("  ");
    let converted = map_ty(&f.ty);
    ret.push_str(&converted.format_with_ident(f.ident.as_ref().expect("Struct fields must have idents")));
    ret.push_str(";\n");
    ret
}

fn map_generic_param(t: &TyParam) -> String {
    let mut ret = String::from("typename ");
    ret.push_str(&t.ident.to_string());
    ret
}

fn fold_enum_variants(accum: (String, i32), v: &Variant) -> (String, i32) {
    // `accum` contains the combined string of converted enum variants so far, to which
    // we will append the converted version of `v`. The other thing in `accum` is the
    // value of the previous variant. If `v` has an explicit value we keep that, otherwise
    // we increment the value of the previous variant to get the new one. This is all
    // so that we properly support enums with explicitly-specified and discontinuous
    // values.
    let mut ret = accum.0;
    ret.push_str("  ");
    ret.push_str(&v.ident.to_string());
    ret.push_str(" = ");
    let new_value = match &v.discriminant {
        &None => accum.1 + 1,
        &Some(ConstExpr::Lit(Lit::Int(ref specified_value, _))) => *specified_value as i32,
        &Some(_) => {
            // we don't handle this yet, so just put in something that will fail C compilation
            writeln!(io::stderr(), "warning, unsupported enum discriminant").unwrap();
            ret.push_str("???");
            accum.1 + 1
        }
    };
    ret.push_str(&new_value.to_string());
    ret.push_str(",\n");
    (ret, new_value)
}

/// A structure to store all the results of converting Rust stuff to C
/// stuff, so that we can pick and choose what we output.
struct ConversionResults {
    /// This holds the C function signatures of no_mangle rust functions,
    /// in the order that they were encountered in Rust.
    funcs: Vec<String>,
    /// This holds the C conversions of repr(C) structs and repr(u32) enums
    /// from Rust. The 'ds' in the name stands for 'data structures'. The
    /// key of the map is the name of the type, and the value is the C code.
    c_ds: BTreeMap<String, String>,
    /// This holds the dependency tree. If a struct contains another struct
    /// or an enum it will be in this map. The key is the dependent type,
    /// the list of values are all the things it depends on.
    _dep_tree: BTreeMap<String, Vec<String>>,
}

fn main() {
    let p = env::args().nth(1).unwrap();

    let results = Mutex::new(ConversionResults {
        funcs: Vec::new(),
        c_ds: BTreeMap::new(),
        _dep_tree: BTreeMap::new(),
    });

    rust_lib::parse(p, &|mod_name, items| {
        for item in items {
            match item.node {
                ItemKind::Fn(ref decl,
                             ref _unsafe,
                             ref _const,
                             ref abi,
                             ref _generic,
                             ref _block) => {
                    writeln!(io::stderr(), "processing function {}::{}", mod_name, &item.ident).unwrap();
                    if has_no_mangle(&item.attrs) && is_c_abi(&abi) {
                        results.lock().unwrap().funcs.push(
                            format!("WR_INLINE {}\n{}({})\n{};\n",
                                    map_return_type(&decl.output),
                                    item.ident,
                                    decl.inputs
                                        .iter()
                                        .map(map_arg)
                                        .collect::<Vec<_>>()
                                        .join(", "),
                                    wr_func_body(&item.attrs)));
                    }
                }
                ItemKind::Struct(ref variant,
                                 ref generics) => {
                    writeln!(io::stderr(), "processing struct {}::{}", mod_name, &item.ident).unwrap();
                    if is_repr_c(&item.attrs) {
                        if let &VariantData::Struct(ref fields) = variant {
                            let mut c_struct = String::new();
                            if !generics.ty_params.is_empty() {
                                c_struct.push_str(&(
                                    format!("template<{}>",
                                            generics.ty_params
                                                    .iter()
                                                    .map(map_generic_param)
                                                    .collect::<Vec<_>>()
                                                    .join(", "))));
                            }
                            c_struct.push_str(&(
                                format!("struct {} {{\n{}}};\n",
                                        item.ident,
                                        fields.iter()
                                              .map(map_field)
                                              .collect::<String>())));
                            results.lock().unwrap().c_ds.insert(
                                item.ident.to_string(),
                                c_struct);
                        }
                    }
                }
                ItemKind::Enum(ref variants, ref _generics) => {
                    writeln!(io::stderr(), "processing enum {}::{}", mod_name, &item.ident).unwrap();
                    if is_repr_u32(&item.attrs) {
                        let c_enum = format!("enum class {}: uint32_t {{\n{}\n  Sentinel /* this must be last for serialization purposes. */\n}};\n",
                                             item.ident,
                                             variants.iter()
                                                     .fold((String::new(), -1), fold_enum_variants)
                                                     .0);
                        results.lock().unwrap().c_ds.insert(
                            item.ident.to_string(),
                            c_enum);
                    }
                }
                _ => {}
            }
        }
    });
    for (_, c_stuff) in &results.lock().unwrap().c_ds {
        println!("{}", c_stuff);
    }
    for func in &results.lock().unwrap().funcs {
        println!("{}", func);
    }
}
<|endoftext|>


<commit_before>use futures::stream::{self, StreamExt};
use log::{self, *};
use std::future::Future;
use std::io::Write;
use std::sync::Arc;
use tokio::task;
use trust_dns_resolver::config::*;
use trust_dns_resolver::error::{ResolveError, ResolveErrorKind};
use trust_dns_resolver::lookup::Lookup;
use trust_dns_resolver::proto::rr::RecordType;
use trust_dns_resolver::proto::xfer::DnsRequestOptions;
use trust_dns_resolver::TokioAsyncResolver;

type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;

#[derive(Clone)]
pub struct MyResolver {
    inner: Arc<TokioAsyncResolver>,
    name: String,
}

#[derive(Debug)]
pub enum MyLookup {
    Lookup(Lookup),
    NxDomain,
    Timeout,
    Error,
}

impl From<std::result::Result<Lookup, ResolveError>> for MyLookup {
    fn from(res: std::result::Result<Lookup, ResolveError>) -> Self {
        match res {
            Ok(lookup) => MyLookup::Lookup(lookup),
            Err(err) => match err.kind() {
                ResolveErrorKind::NoRecordsFound { .. } => MyLookup::NxDomain,
                ResolveErrorKind::Timeout => MyLookup::Timeout,
                _ => MyLookup::Error,
            },
        }
    }
}

impl MyResolver {
    pub async fn new(i: usize) -> Result<Self> {
        let config = match i {
            1 => ResolverConfig::google(),
            2 => ResolverConfig::cloudflare(),
            _ => ResolverConfig::quad9(),
        };
        let opts = ResolverOpts {
            //validate: true,
            ..ResolverOpts::default()
        };
        let resolver = TokioAsyncResolver::tokio(config, opts).await?;
        debug!("Created {} Resolver.", i);

        Ok(MyResolver {
            inner: Arc::new(resolver),
            name: i.to_string(),
        })
    }

    /// Async lookup algorithm -- no work is done
    pub fn lookup(&self, query: Arc<Query>) -> impl Future<Output = Vec<MyLookup>> {
        Self::inner_lookup(self.clone(), query)
    }

    async fn inner_lookup(resolver: Self, query: Arc<Query>) -> Vec<MyLookup> {
        let futures: Vec<_> = query
            .record_types
            .iter()
            .map(|x| make_lookup(&resolver.name, &resolver.inner, x.clone()))
            .collect();

        stream::iter(futures)
            .buffer_unordered(2)
            .inspect(|lookup| trace!("Received lookup {:?}", lookup))
            .collect::<Vec<MyLookup>>()
            .await
    }
}

async fn make_lookup(i: &str, resolver: &TokioAsyncResolver, record_type: RecordType) -> MyLookup {
    let lookup = resolver
        .lookup("www.example.com.", record_type, DnsRequestOptions::default())
        .await
        .into();
    debug!("Received {} Lookup for record type {}.", i, record_type);

    lookup
}

/// Wait asyncly for the work to finish
async fn lookups(tasks: Vec<task::JoinHandle<Vec<MyLookup>>>) -> Vec<MyLookup> {
    let mut res = Vec::new();
    for t in tasks {
        let r = t.await;
        res.push(r);
    }

    res.into_iter().flatten().flatten().collect()
}

async fn do_main(query: Query) -> Result<Vec<MyLookup>> {
    let query = Arc::new(query);

    let google = MyResolver::new(1).await?;
    let cloudflare = MyResolver::new(2).await?;
    let quad6 = MyResolver::new(3).await?;
    debug!("Created all the resolvers");

    let tasks: Vec<task::JoinHandle<Vec<MyLookup>>> = vec![google, cloudflare, quad6]
        .iter()
        .map(|resolver| resolver.lookup(query.clone()))
        .map(task::spawn)
        .collect();
    debug!("Created and spawned all the futures");

    let lookups = lookups(tasks).await;
    debug!("Awaited all the futures");

    Ok(lookups)
}

#[derive(Debug)]
pub struct Query {
    name: String,
    record_types: Vec<RecordType>,
}

fn main() -> Result<()> {
    let start = std::time::Instant::now();
    env_logger::Builder::from_default_env()
        .format(move |buf, rec| {
            let t = start.elapsed().as_secs_f32();
            let thread_id_string = format!("{:?}", std::thread::current().id());
            let thread_id = &thread_id_string[9..thread_id_string.len() - 1];
            writeln!(buf, "{:.03} [{:5}] ({:}) - {}", t, rec.level(), thread_id, rec.args())
        })
        .init();

    let query = Query {
        name: "www.example.com".to_string(),
        record_types: vec![
            RecordType::A,
            RecordType::A,
            RecordType::A,
            RecordType::AAAA,
            RecordType::MX,
            RecordType::AAAA,
            RecordType::TXT,
            RecordType::TXT,
            RecordType::TXT,
        ],
    };

    let mut rt = tokio::runtime::Runtime::new().expect("Failed to create runtime.");

    rt.block_on(async {
        let lookups = do_main(query).await;
        match lookups {
            //Ok(lookups) => info!("Lookup: {:#?}", lookups),
            Ok(_) => info!("Done."),
            Err(e) => error!("An error occurred: {}", e),
        }
    });

    Ok(())
}
<commit_msg>Empty main<commit_after>fn main() -> Result<()> {
    let start = std::time::Instant::now();
    env_logger::Builder::from_default_env()
        .format(move |buf, rec| {
            let t = start.elapsed().as_secs_f32();
            let thread_id_string = format!("{:?}", std::thread::current().id());
            let thread_id = &thread_id_string[9..thread_id_string.len() - 1];
            writeln!(buf, "{:.03} [{:5}] ({:}) - {}", t, rec.level(), thread_id, rec.args())
        })
        .init();

    rt.block_on(async {});

    Ok(())
}
<|endoftext|>


<commit_before>use std::net::UdpSocket;
use std::io;
use std::io::Write;
use std::thread;

fn main () {
    let child = thread::spawn(move || {
        let socket = UdpSocket::bind("0.0.0.0:0").expect("couldn't bind to address");
        socket.set_broadcast(true).expect("set_broadcast call failed");

        print!("> ");
        io::stdout().flush().unwrap();

        loop {

            let mut input = String::new();
            match io::stdin().read_line(&mut input) {
                Ok(_) => {
                    input.pop();

                    process(&socket, input);
                    print!("> ");
                    io::stdout().flush().unwrap();
                }
                Err(error) => println!("error: {}", error),
            }
        }
    });

    let child2 = thread::spawn(move || {
        let socket = UdpSocket::bind("0.0.0.0:4041").expect("couldn't bind to address");
        loop {

            let mut buf_header = [0; 2];
            let (received_bytes, _source) = socket.recv_from(&mut buf_header)
                .expect("Didn't receive data");

            let mut left: u8  = std::str::from_utf8(&buf_header[1..2]).unwrap().parse().unwrap();

            while left > 0 {
                let mut buffer = [0; 1];
                let (received_bytes2, _source) = socket.recv_from(&mut buffer).expect("didn't receive data TODO");
                left = left - received_bytes2 as u8;
                println!("{}", left);
            }

            //println!("{}", std::str::from_utf8(&buf[0..received_bytes2]).unwrap());
            io::stdout().flush().unwrap();
        }
    });

    child.join().unwrap();
    child2.join().unwrap();
}

fn process(socket: &UdpSocket, input: String) {
    match input.as_ref() {
        "" => {
        },
        _ => {
            let size = input.len();
            println!("{}", size);
            let message = format!("{}{}{}", "M", size, input);
            socket.send_to(&message.into_bytes(), "255.255.255.255:4041").expect("couldn't send data");
        }
    }
    ()
}
<commit_msg>Basic functionality working<commit_after>use std::net::UdpSocket;
use std::io;
use std::io::Write;
use std::thread;
use std::time::Duration;
use std::process;
use std::sync::{Arc, Mutex};
use std::collections::HashMap;
use std::time::SystemTime;

fn main () {
    let peers = Arc::new(Mutex::new(HashMap::new()));

    let peers_sender = peers.clone();
    let sender = thread::spawn(move || {
        let socket = UdpSocket::bind("0.0.0.0:0").expect("couldn't bind to address");
        socket.set_broadcast(true).expect("set_broadcast call failed");

        print!("> ");
        io::stdout().flush().unwrap();

        loop {
            let mut input = String::new();
            match io::stdin().read_line(&mut input) {
                Ok(_) => {
                    input.pop();

                    process(&socket, input);
                    print!("> ");
                    io::stdout().flush().unwrap();
                    println!("peers {:?}", *peers_sender.lock().unwrap());
                }
                Err(error) =>
                    println!("error: {}", error),
            }
        }
    });

    let prober = thread::spawn(|| {
        let socket = UdpSocket::bind("0.0.0.0:0").expect("couldn't bind to address");
        socket.set_broadcast(true).expect("set_broadcast call failed");
        loop {
            let message = format!("P");
            socket.send_to(&message.into_bytes(), "255.255.255.255:4041").expect("couldn't send data");
            thread::sleep(Duration::from_millis(5000)); //TODO put in seconds
        }
    });

    let peers_rec = peers.clone();
    let receiver = thread::spawn(move || {
        let socket = UdpSocket::bind("0.0.0.0:4041").expect("couldn't bind to address");

        loop {
            let mut buffer = [0; 512];
            let (received_bytes, source) = socket.recv_from(&mut buffer)
                .expect("Didn't receive data");

            match std::str::from_utf8(&buffer[0..1]).unwrap() {
                "M" => {
                    println!("{}", std::str::from_utf8(&buffer[2..received_bytes]).unwrap());
                    io::stdout().flush().unwrap();
                }

                "P" => {
                    println!("probe with source {}", source);
                    peers_rec.lock().unwrap().insert(source, SystemTime::now()); //TODO insert only seconds and IP
                    // clean hosts that have not received content for more than x seconds
                }

                _ =>  {
                }
            }

        }
    });

    receiver.join().unwrap();
    sender.join().unwrap();
    prober.join().unwrap();
}

fn process(socket: &UdpSocket, input: String) {
    match input.as_ref() {
        "" => {

        },

        "/quit" => {
            process::exit(0x0f00);
        },

        "/peers" => {
            //TODO print list of
        },

        _ => {
            let size = input.len();
            let message = format!("M{}{}", size, input);
            socket.send_to(&message.into_bytes(), "255.255.255.255:4041").expect("couldn't send data");
        }
    }
    ()
}
<|endoftext|>


<commit_before>#![feature(globs)] // Allow global imports

extern crate cgmath;
extern crate gl;
extern crate graphics;
extern crate native;
extern crate piston;
extern crate sdl2_game_window;

use sdl2_game_window::GameWindowSDL2;

use cgmath::array::*;
use piston::*;
use gl::types::*;
use std::mem;
use std::ptr;
use std::str;

pub struct App {
  vao: u32,
  vbo: u32,
  projection_matrix: cgmath::matrix::Matrix4<GLfloat>,
  shader_program: u32,
}

pub fn translate(t: &cgmath::vector::Vector3<GLfloat>) -> cgmath::matrix::Matrix4<GLfloat> {
  cgmath::matrix::Matrix4::new(
    1.0, 0.0, 0.0, 0.0,
    0.0, 1.0, 0.0, 0.0,
    0.0, 0.0, 1.0, 0.0,
    t.x, t.y, t.z, 1.0,
  )
}

impl Game for App {
  fn key_press(&mut self, _args: &KeyPressArgs) {
    match _args.key {
      piston::keyboard::A => {
        self.transform_projection(&translate(&cgmath::vector::Vector3::new(0.1, 0.0, 0.0)));
      },
      piston::keyboard::D => {
        self.transform_projection(&translate(&cgmath::vector::Vector3::new(-0.1, 0.0, 0.0)));
      },
      piston::keyboard::LShift => {
        self.transform_projection(&translate(&cgmath::vector::Vector3::new(0.0, 0.1, 0.0)));
      },
      piston::keyboard::Space => {
        self.transform_projection(&translate(&cgmath::vector::Vector3::new(0.0, -0.1, 0.0)));
      },
      piston::keyboard::W => {
        self.transform_projection(&translate(&cgmath::vector::Vector3::new(0.0, 0.0, 0.1)));
      },
      piston::keyboard::S => {
        self.transform_projection(&translate(&cgmath::vector::Vector3::new(0.0, 0.0, -0.1)));
      },
      _ => {},
    }
  }

  fn load(&mut self) {
    let vs = compile_shader(VS_SRC, gl::VERTEX_SHADER);
    let fs = compile_shader(FS_SRC, gl::FRAGMENT_SHADER);

    self.shader_program = link_program(vs, fs);

    unsafe {
      // Create Vertex Array Object
      gl::GenVertexArrays(1, &mut self.vao);
      gl::BindVertexArray(self.vao);

      // Create a Vertex Buffer Object and copy the vertex data to it
      gl::GenBuffers(1, &mut self.vbo);
      gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo);
      gl::BufferData(gl::ARRAY_BUFFER,
                      (VERTEX_DATA.len() * mem::size_of::<GLfloat>()) as GLsizeiptr,
                      mem::transmute(&VERTEX_DATA[0]),
                      gl::STATIC_DRAW);

      gl::UseProgram(self.shader_program);
      let loc = gl::GetUniformLocation(self.shader_program, "proj_matrix".to_c_str().unwrap());
      if loc == -1 {
        println!("couldn't read matrix");
      } else {
        self.projection_matrix = cgmath::projection::frustum::<GLfloat>(-1.0, 1.0, -1.0, 1.0, 0.1, 2.0);
        self.transform_projection(&translate(&cgmath::vector::Vector3::new(0.0, 0.0, -0.1)));
        gl::UniformMatrix4fv(loc, 1, 0, mem::transmute(self.projection_matrix.ptr()));
      }
      "out_color".with_c_str(|ptr| gl::BindFragDataLocation(self.shader_program, 0, ptr));

      // Specify the layout of the vertex data
      let pos_attr = "position".with_c_str(|ptr| gl::GetAttribLocation(self.shader_program, ptr));
      gl::EnableVertexAttribArray(pos_attr as GLuint);
      gl::VertexAttribPointer(pos_attr as GLuint, 3, gl::FLOAT,
                              gl::FALSE as GLboolean, 0, ptr::null());
    }

    gl::ClearColor(0.0, 0.0, 0.0, 1.0);
  }

  fn render(&mut self, _:&RenderArgs) {
    gl::Clear(gl::COLOR_BUFFER_BIT);

    // Draw a triangle from the 3 vertices
    gl::DrawArrays(gl::TRIANGLES, 0, 3);
  }
}

impl App {
  pub fn new() -> App {
    App {
      vao: 0,
      vbo: 0,
      shader_program: -1 as u32,
      projection_matrix: cgmath::matrix::Matrix4::from_value(0.0),
    }
  }

  pub fn transform_projection(&mut self, t: &cgmath::matrix::Matrix4<GLfloat>) {
    unsafe {
      let loc = gl::GetUniformLocation(self.shader_program, "proj_matrix".to_c_str().unwrap());
      if loc == -1 {
        println!("couldn't read matrix");
      } else {
        self.projection_matrix = self.projection_matrix * *t;
        gl::UniformMatrix4fv(loc, 1, 0, mem::transmute(self.projection_matrix.ptr()));
      }
    }
  }

  pub fn destroy(&mut self) {
    unsafe {
      gl::DeleteBuffers(1, &self.vbo);
      gl::DeleteVertexArrays(1, &self.vao);
    }
  }
}

// Vertex data
static VERTEX_DATA: [GLfloat, ..9] = [
     0.0,  0.5, 0.0,
     0.5, -0.5, 0.0,
    -0.5, -0.5, 0.0,
];

// Shader sources
static VS_SRC: &'static str =
   "#version 150\n\
uniform mat4 proj_matrix;\n\
in vec3 position;\n\
void main() {\n\
gl_Position = proj_matrix * vec4(position, 1.0);\n\
}";

static FS_SRC: &'static str =
   "#version 150\n\
out vec4 out_color;\n\
void main() {\n\
out_color = vec4(1.0, 1.0, 1.0, 1.0);\n\
}";

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
    let shader = gl::CreateShader(ty);
    unsafe {
        // Attempt to compile the shader
        src.with_c_str(|ptr| gl::ShaderSource(shader, 1, &ptr, ptr::null()));
        gl::CompileShader(shader);

        // Get the compile status
        let mut status = gl::FALSE as GLint;
        gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = Vec::from_elem(len as uint - 1, 0u8); // subtract 1 to skip the trailing null character
            gl::GetShaderInfoLog(shader, len, ptr::mut_null(), buf.as_mut_ptr() as *mut GLchar);
            fail!("{}", str::from_utf8(buf.as_slice()).expect("ShaderInfoLog not valid utf8"));
        }
    }
    shader
}

fn link_program(vs: GLuint, fs: GLuint) -> GLuint {
    let program = gl::CreateProgram();

    gl::AttachShader(program, vs);
    gl::AttachShader(program, fs);
    gl::LinkProgram(program);

    unsafe {
        // Get the link status
        let mut status = gl::FALSE as GLint;
        gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len: GLint = 0;
            gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = Vec::from_elem(len as uint - 1, 0u8); // subtract 1 to skip the trailing null character
            gl::GetProgramInfoLog(program, len, ptr::mut_null(), buf.as_mut_ptr() as *mut GLchar);
            fail!("{}", str::from_utf8(buf.as_slice()).expect("ProgramInfoLog not valid utf8"));
        }
    }

    program
}

fn main() {
  let mut window = GameWindowSDL2::new(
    GameWindowSettings {
      title: "playform".to_string(),
      size: [800, 600],
      fullscreen: false,
      exit_on_esc: false,
    }
  );

  App::new().run(&mut window, &GameIteratorSettings {
    updates_per_second: 30,
    max_frames_per_second: 30,
  });
}
<commit_msg>supply vertex data to render in Triangle structs<commit_after>#![feature(globs)] // Allow global imports

extern crate cgmath;
extern crate gl;
extern crate graphics;
extern crate native;
extern crate piston;
extern crate sdl2_game_window;

use sdl2_game_window::GameWindowSDL2;

use cgmath::array::*;
use piston::*;
use gl::types::*;
use std::mem;
use std::ptr;
use std::str;

pub struct Triangle<T> {
  vertices: [cgmath::vector::Vector3<T>, ..3],
}

impl<T: Clone> Clone for Triangle<T> {
  fn clone(&self) -> Triangle<T> {
    Triangle {
      vertices: [self.vertices[0].clone(), self.vertices[1].clone(), self.vertices[2].clone()],
    }
  }
}

pub struct App {
  vao: u32,
  vbo: u32,
  vertex_data: Vec<Triangle<GLfloat>>,
  projection_matrix: cgmath::matrix::Matrix4<GLfloat>,
  shader_program: u32,
}

pub fn translate(t: &cgmath::vector::Vector3<GLfloat>) -> cgmath::matrix::Matrix4<GLfloat> {
  cgmath::matrix::Matrix4::new(
    1.0, 0.0, 0.0, 0.0,
    0.0, 1.0, 0.0, 0.0,
    0.0, 0.0, 1.0, 0.0,
    t.x, t.y, t.z, 1.0,
  )
}

impl<T: Clone> Triangle<T> {
  fn new(
      v1: &cgmath::vector::Vector3<T>,
      v2: &cgmath::vector::Vector3<T>,
      v3: &cgmath::vector::Vector3<T>)
      -> Triangle<T> {
    Triangle {
      vertices: [v1.clone(), v2.clone(), v3.clone()],
    }
  }
}

impl Game for App {
  fn key_press(&mut self, _args: &KeyPressArgs) {
    match _args.key {
      piston::keyboard::A => {
        self.transform_projection(&translate(&cgmath::vector::Vector3::new(0.1, 0.0, 0.0)));
      },
      piston::keyboard::D => {
        self.transform_projection(&translate(&cgmath::vector::Vector3::new(-0.1, 0.0, 0.0)));
      },
      piston::keyboard::LShift => {
        self.transform_projection(&translate(&cgmath::vector::Vector3::new(0.0, 0.1, 0.0)));
      },
      piston::keyboard::Space => {
        self.transform_projection(&translate(&cgmath::vector::Vector3::new(0.0, -0.1, 0.0)));
      },
      piston::keyboard::W => {
        self.transform_projection(&translate(&cgmath::vector::Vector3::new(0.0, 0.0, 0.1)));
      },
      piston::keyboard::S => {
        self.transform_projection(&translate(&cgmath::vector::Vector3::new(0.0, 0.0, -0.1)));
      },
      _ => {},
    }
  }

  fn load(&mut self) {
    let vs = compile_shader(VS_SRC, gl::VERTEX_SHADER);
    let fs = compile_shader(FS_SRC, gl::FRAGMENT_SHADER);

    self.shader_program = link_program(vs, fs);

    unsafe {
      // Create Vertex Array Object
      gl::GenVertexArrays(1, &mut self.vao);
      gl::BindVertexArray(self.vao);

      // Create a Vertex Buffer Object and copy the vertex data to it
      gl::GenBuffers(1, &mut self.vbo);
      gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo);
      gl::BufferData(gl::ARRAY_BUFFER,
                      (self.vertex_data.len() * mem::size_of::<Triangle<GLfloat>>()) as GLsizeiptr,
                      mem::transmute(&self.vertex_data.slice(0, self.vertex_data.len())[0]),
                      gl::STATIC_DRAW);

      gl::UseProgram(self.shader_program);
      let loc = gl::GetUniformLocation(self.shader_program, "proj_matrix".to_c_str().unwrap());
      if loc == -1 {
        println!("couldn't read matrix");
      } else {
        self.projection_matrix = cgmath::projection::frustum::<GLfloat>(-1.0, 1.0, -1.0, 1.0, 0.1, 2.0);
        self.transform_projection(&translate(&cgmath::vector::Vector3::new(0.0, 0.0, -0.1)));
        gl::UniformMatrix4fv(loc, 1, 0, mem::transmute(self.projection_matrix.ptr()));
      }
      "out_color".with_c_str(|ptr| gl::BindFragDataLocation(self.shader_program, 0, ptr));

      // Specify the layout of the vertex data
      let pos_attr = "position".with_c_str(|ptr| gl::GetAttribLocation(self.shader_program, ptr));
      gl::EnableVertexAttribArray(pos_attr as GLuint);
      gl::VertexAttribPointer(pos_attr as GLuint, 3, gl::FLOAT,
                              gl::FALSE as GLboolean, 0, ptr::null());
    }

    gl::ClearColor(0.0, 0.0, 0.0, 1.0);
  }

  fn render(&mut self, _:&RenderArgs) {
    gl::Clear(gl::COLOR_BUFFER_BIT);

    // Draw a triangle from the 3 vertices
    gl::DrawArrays(gl::TRIANGLES, 0, 3);
  }
}

impl App {
  pub fn new() -> App {
    App {
      vao: 0,
      vbo: 0,
      vertex_data: Vec::from_slice([
        Triangle::new(
          &cgmath::vector::Vector3::new( 0.0,  0.5, 0.0),
          &cgmath::vector::Vector3::new( 0.5, -0.5, 0.0),
          &cgmath::vector::Vector3::new(-0.5, -0.5, 0.0),
        ),
      ]),
      shader_program: -1 as u32,
      projection_matrix: cgmath::matrix::Matrix4::from_value(0.0),
    }
  }

  pub fn transform_projection(&mut self, t: &cgmath::matrix::Matrix4<GLfloat>) {
    unsafe {
      let loc = gl::GetUniformLocation(self.shader_program, "proj_matrix".to_c_str().unwrap());
      if loc == -1 {
        println!("couldn't read matrix");
      } else {
        self.projection_matrix = self.projection_matrix * *t;
        gl::UniformMatrix4fv(loc, 1, 0, mem::transmute(self.projection_matrix.ptr()));
      }
    }
  }

  pub fn destroy(&mut self) {
    unsafe {
      gl::DeleteBuffers(1, &self.vbo);
      gl::DeleteVertexArrays(1, &self.vao);
    }
  }
}

// Shader sources
static VS_SRC: &'static str =
   "#version 150\n\
uniform mat4 proj_matrix;\n\
in vec3 position;\n\
void main() {\n\
gl_Position = proj_matrix * vec4(position, 1.0);\n\
}";

static FS_SRC: &'static str =
   "#version 150\n\
out vec4 out_color;\n\
void main() {\n\
out_color = vec4(1.0, 1.0, 1.0, 1.0);\n\
}";

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
    let shader = gl::CreateShader(ty);
    unsafe {
        // Attempt to compile the shader
        src.with_c_str(|ptr| gl::ShaderSource(shader, 1, &ptr, ptr::null()));
        gl::CompileShader(shader);

        // Get the compile status
        let mut status = gl::FALSE as GLint;
        gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = Vec::from_elem(len as uint - 1, 0u8); // subtract 1 to skip the trailing null character
            gl::GetShaderInfoLog(shader, len, ptr::mut_null(), buf.as_mut_ptr() as *mut GLchar);
            fail!("{}", str::from_utf8(buf.as_slice()).expect("ShaderInfoLog not valid utf8"));
        }
    }
    shader
}

fn link_program(vs: GLuint, fs: GLuint) -> GLuint {
    let program = gl::CreateProgram();

    gl::AttachShader(program, vs);
    gl::AttachShader(program, fs);
    gl::LinkProgram(program);

    unsafe {
        // Get the link status
        let mut status = gl::FALSE as GLint;
        gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len: GLint = 0;
            gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = Vec::from_elem(len as uint - 1, 0u8); // subtract 1 to skip the trailing null character
            gl::GetProgramInfoLog(program, len, ptr::mut_null(), buf.as_mut_ptr() as *mut GLchar);
            fail!("{}", str::from_utf8(buf.as_slice()).expect("ProgramInfoLog not valid utf8"));
        }
    }

    program
}

fn main() {
  let mut window = GameWindowSDL2::new(
    GameWindowSettings {
      title: "playform".to_string(),
      size: [800, 600],
      fullscreen: false,
      exit_on_esc: false,
    }
  );

  App::new().run(&mut window, &GameIteratorSettings {
    updates_per_second: 30,
    max_frames_per_second: 30,
  });
}
<|endoftext|>


<commit_before>use std::io::{self, Read};
use std::env;
use std::fmt;
use std::fs::File;

struct Col {
    pub buffers: Vec<String>
}
impl Col {
    fn new() -> Col {
        Col { buffers: Vec::new() }
    }
    fn add_buf(&mut self) {
        self.buffers.push(String::new());
    }
    fn append(&mut self, chr: char) {
        let mut len = self.buffers.len();

        if len == 0 {
            self.add_buf();
            len = 1;
        }

        let ref mut buffer = self.buffers[len-1];
        buffer.push(chr);
    }
    fn append_str(&mut self, str: &str) {
        for chr in str.chars() {
            self.append(chr);
        }
    }
    fn out(&self, template: &Template) -> String {
        let mut out: String = String::new();

        out.push_str(template.col_start.as_str());
        for ref buf in self.buffers.iter() {
            out.push_str(format!("{}{}{}",
                    template.segment_start.as_str(),
                    buf,
                    template.segment_end.as_str()
                ).as_str());
        }
        out.push_str(template.col_end.as_str());

        out
    }
}

struct Row {
    pub cols: Vec<Col>
}
impl Row {
    fn add_col(&mut self, col: Col) {
        self.cols.push(col);
    }
    fn get_col(&mut self, index: u8) -> &mut Col {
        self.cols.get_mut(index as usize).unwrap()
    }
    fn col_count(&self) -> usize {
        self.cols.len()
    }
    fn new() -> Row {
        let mut row: Row = Row { cols: Vec::new() };
        row.add_col(Col::new());
        row
    }
    fn out(&self, template: &Template) -> String {
        let mut out: String = String::new();

        out.push_str(template.row_start.as_str());
        for ref col in self.cols.iter() {
            let formatted = format!("{}", col.out(template));
            out.push_str(formatted.as_str());
        }
        out.push_str(template.row_end.as_str());

        out
    }
}

struct Template {
    container_start: String,
    container_end: String,
    row_start: String,
    row_end: String,
    col_start: String,
    col_end: String,
    segment_start: String,
    segment_end: String,
    label: String,
    text: String,
    checkbox: String,
    radio: String,
    textarea: String,
    hr: String,
    button: String
}

/**
 * An empty line implies a new "row"
 * A line starting with a | implies a columnar form section
 * [value] is an input text field
 * {value} is an input textarea field
 * @ is a radio
 * * is a checkbox
 * --- is an hr
 *
 */
fn main() {
    // Read in standard input
    let mut buffer = String::new();
    io::stdin().read_to_string(&mut buffer)
        .expect("Error reading from stdin");

    // Split input by line
    let v: Vec<&str> = buffer.split("\n").collect();

    // Keep track of rows in output
    let mut rows: Vec<Row> = Vec::new();
    let mut row: Row = Row::new();

    // Check arg for template
    let template = match env::args().nth(1) {
        Some(file) => {
            let dir = env::current_dir().unwrap();
            let template_file = format!("{}/{}", dir.display(), file);

            let mut in_file = match File::open(&template_file) {
                Err(why) => panic!("Unable to open template file"),
                Ok(file) => file,
            };

            let mut content = String::new();
            in_file.read_to_string(&mut content)
                .expect("Unable to process template file");

            let sp: Vec<&str> = content.split("\n").collect();

            Template {
                container_start: sp[0].to_string().trim().to_string(),
                container_end: sp[14].to_string().trim().to_string(),
                row_start: sp[1].to_string().trim().to_string(),
                row_end: sp[13].to_string().trim().to_string(),
                col_start: sp[2].to_string().trim().to_string(),
                col_end: sp[12].to_string().trim().to_string(),
                segment_start: sp[3].to_string().trim().to_string(),
                segment_end: sp[11].to_string().trim().to_string(),
                label: sp[4].to_string().trim().to_string(),
                text: sp[5].to_string().trim().to_string(),
                checkbox: sp[6].to_string().trim().to_string(),
                radio: sp[7].to_string().trim().to_string(),
                textarea: sp[8].to_string().trim().to_string(),
                hr: sp[9].to_string().trim().to_string(),
                button: sp[10].to_string().trim().to_string()
            }

        },
        _ => Template {
            container_start: "".to_string(),
            container_end: "".to_string(),
            row_start: "
".to_string(),
            row_end: "
".to_string(),
            col_start: "".to_string(),
            col_end: "".to_string(),
            segment_start: "".to_string(),
            segment_end: "
".to_string(),
            label: "{[value}}".to_string(),
            text: "<input type=\"text\" value=\"{{value}}\"/>".to_string(),
            checkbox: "<input type=\"checkbox\"/>".to_string(),
            radio: "<input type=\"radio\"/>".to_string(),
            textarea: "<textarea>{{value}}</textarea>".to_string(),
            hr: "
".to_string(),
            button: "<button>{{value}}</button>".to_string()
        }
    };

    // Iterate over lines in input
    for line in &v {
        // New row by way of empty line
        if line.chars().count() == 0 {
            rows.push(row);
            row = Row::new();
            continue;
        }

        let mut form_mode = false; // If user toggled form mode
        let mut col_index: u8 = 1; // Keeping tracking of column index
        let mut dashes: u8 = 0; // Keep track of dash count

        // Iterate over characters in string
        for (i, c) in line.chars().enumerate() {
            // Match c against known tokens
            match c {
                '-' => {
                    dashes += 1;
                    if dashes == 3 {
                        row.get_col(col_index-1)
                            .append_str("
");
                        break;
                    }
                },
                '|' => {
                    if i == 0 {
                        form_mode = true;
                        row.get_col(col_index-1).add_buf()
                    } else if form_mode {
                        // Check if we have enough columns in row
                        // if not add a new column
                        if (row.col_count() as u8) < col_index + 1 {
                            row.add_col(Col::new());
                        }

                        // Increment index
                        col_index += 1;

                        row.get_col(col_index-1).add_buf();
                    } else {
                        row.get_col(col_index-1).append(c);
                    }
                },
                '<' => row.get_col(col_index-1)
                        .append_str(""),
                '>' => row.get_col(col_index-1)
                        .append_str(""),
                '[' => row.get_col(col_index-1)
                        .append_str("<input type=\"text\" value=\""),
                ']' => row.get_col(col_index-1)
                        .append_str("\">"),
                '{' => row.get_col(col_index-1)
                        .append_str("<textarea>"),
                '}' => row.get_col(col_index-1)
                        .append_str("</textarea>"),
                '@' => row.get_col(col_index-1)
                        .append_str("<input type=\"radio\">"),
                '(' => row.get_col(col_index-1)
                        .append_str("<button class=\"btn\">"),
                ')' => row.get_col(col_index-1)
                        .append_str("</button>"),
                _ => row.get_col(col_index-1).append(c)
            }
        }
    }

    println!("{}", template.container_start);
    for row in rows {
        println!("{}", row.out(&template));
    }
    println!("{}", template.container_end);
}
<commit_msg>Working templates, handlebars<commit_after>use std::collections::BTreeMap;
use std::env;
use std::fs::File;
use std::io::{self, Read};
use handlebars::Handlebars;

extern crate handlebars;

struct Col {
    pub buffers: Vec<String>
}
impl Col {
    fn new() -> Col {
        Col { buffers: Vec::new() }
    }
    fn add_buf(&mut self) {
        self.buffers.push(String::new());
    }
    fn append(&mut self, chr: char) {
        let mut len = self.buffers.len();

        if len == 0 {
            self.add_buf();
            len = 1;
        }

        let ref mut buffer = self.buffers[len-1];
        buffer.push(chr);
    }
    fn append_str(&mut self, str: &str) {
        for chr in str.chars() {
            self.append(chr);
        }
    }
    fn out(&self, template: &Template) -> String {
        let mut out: String = String::new();

        out.push_str(template.col_start.as_str());
        for ref buf in self.buffers.iter() {
            out.push_str(format!("{}{}{}",
                    template.segment_start.as_str(),
                    buf,
                    template.segment_end.as_str()
                ).as_str());
        }
        out.push_str(template.col_end.as_str());

        out
    }
}

struct Row {
    pub cols: Vec<Col>
}
impl Row {
    fn add_col(&mut self, col: Col) {
        self.cols.push(col);
    }
    fn get_col(&mut self, index: u8) -> &mut Col {
        self.cols.get_mut(index as usize).unwrap()
    }
    fn col_count(&self) -> usize {
        self.cols.len()
    }
    fn new() -> Row {
        let mut row: Row = Row { cols: Vec::new() };
        row.add_col(Col::new());
        row
    }
    fn out(&self, template: &Template) -> String {
        let mut out: String = String::new();

        out.push_str(template.row_start.as_str());
        for ref col in self.cols.iter() {
            let formatted = format!("{}", col.out(template));
            out.push_str(formatted.as_str());
        }
        out.push_str(template.row_end.as_str());

        out
    }
}

struct Template {
    container_start: String,
    container_end: String,
    row_start: String,
    row_end: String,
    col_start: String,
    col_end: String,
    segment_start: String,
    segment_end: String,
    label: String,
    text: String,
    checkbox: String,
    radio: String,
    textarea: String,
    hr: String,
    button: String
}

struct Working {
    str: String,
    until: char,
    template: String
}
impl Working {
    fn new(until: char, template: &String) -> Working {
        Working {
            str: String::new(),
            until: until,
            template: template.clone()
        }
    }
    fn is_working(&self) -> bool {
        self.until != '\0'
    }
    fn append(&mut self, chr: char) {
        self.str.push(chr);
    }
    fn compile(&self) -> String {
        // Compile template
        let mut handlebars = Handlebars::new();
        assert!(handlebars.register_template_string("tmpl", self.template.as_str())
            .is_ok());

        // Bind data to template
        let mut data = BTreeMap::new();
        data.insert("value".to_string(), &self.str);
        handlebars.render("tmpl", &data).unwrap()
    }
}

/**
 * An empty line implies a new "row"
 * A line starting with a | implies a columnar form section
 * [value] is an input text field
 * {value} is an input textarea field
 * @ is a radio
 * * is a checkbox
 * --- is an hr
 *
 */
fn main() {
    // Read in standard input
    let mut buffer = String::new();
    io::stdin().read_to_string(&mut buffer)
        .expect("Error reading from stdin");

    // Split input by line
    let v: Vec<&str> = buffer.split("\n").collect();

    // Keep track of rows in output
    let mut rows: Vec<Row> = Vec::new();
    let mut row: Row = Row::new();

    // Check arg for template
    let template = match env::args().nth(1) {
        Some(file) => {
            let dir = env::current_dir().unwrap();
            let template_file = format!("{}/{}", dir.display(), file);

            let mut in_file = match File::open(&template_file) {
                Err(_) => panic!("Unable to open template file"),
                Ok(file) => file,
            };

            let mut content = String::new();
            in_file.read_to_string(&mut content)
                .expect("Unable to process template file");

            let sp: Vec<&str> = content.split("\n").collect();

            Template {
                container_start: sp[0].to_string().trim().to_string(),
                container_end: sp[14].to_string().trim().to_string(),
                row_start: sp[1].to_string().trim().to_string(),
                row_end: sp[13].to_string().trim().to_string(),
                col_start: sp[2].to_string().trim().to_string(),
                col_end: sp[12].to_string().trim().to_string(),
                segment_start: sp[3].to_string().trim().to_string(),
                segment_end: sp[11].to_string().trim().to_string(),
                label: sp[4].to_string().trim().to_string(),
                text: sp[5].to_string().trim().to_string(),
                checkbox: sp[6].to_string().trim().to_string(),
                radio: sp[7].to_string().trim().to_string(),
                textarea: sp[8].to_string().trim().to_string(),
                button: sp[9].to_string().trim().to_string().
                hr: sp[10].to_string().trim().to_string()
            }

        },
        _ => Template {
            container_start: "".to_string(),
            container_end: "".to_string(),
            row_start: "
".to_string(),
            row_end: "
".to_string(),
            col_start: "".to_string(),
            col_end: "".to_string(),
            segment_start: "".to_string(),
            segment_end: "
".to_string(),
            label: "{[value}}".to_string(),
            text: "<input type=\"text\" value=\"{{value}}\"/>".to_string(),
            checkbox: "<input type=\"checkbox\"/>".to_string(),
            radio: "<input type=\"radio\"/>".to_string(),
            textarea: "<textarea>{{value}}</textarea>".to_string(),
            hr: "
".to_string(),
            button: "<button>{{value}}</button>".to_string()
        }
    };

    // Iterate over lines in input
    for line in &v {
        // New row by way of empty line
        if line.chars().count() == 0 {
            rows.push(row);
            row = Row::new();
            continue;
        }

        let mut form_mode = false; // If user toggled form mode
        let mut col_index: u8 = 1; // Keeping tracking of column index
        let mut dashes: u8 = 0; // Keep track of dash count
        let mut working = Working::new('\0', &String::new());

        // Iterate over characters in string
        for (i, c) in line.chars().enumerate() {
            // Match c against known tokens
            match c {
                '-' => {
                    dashes += 1;
                    if dashes == 3 {
                        working = Working::new('\0', &template.hr);
                        row.get_col(col_index-1)
                            .append_str(working.compile().as_str());
                        break;
                    }
                },
                '|' => {
                    if i == 0 {
                        form_mode = true;
                        row.get_col(col_index-1).add_buf()
                    } else if form_mode {
                        // Check if we have enough columns in row
                        // if not add a new column
                        if (row.col_count() as u8) < col_index + 1 {
                            row.add_col(Col::new());
                        }

                        // Increment index
                        col_index += 1;

                        row.get_col(col_index-1).add_buf();
                    } else {
                        row.get_col(col_index-1).append(c);
                    }
                },
                '@' => {
                    working = Working::new('\0', &template.radio);
                    row.get_col(col_index-1)
                        .append_str(working.compile().as_str());
                },
                '*' => {
                    working = Working::new('\0', &template.checkbox);
                    row.get_col(col_index-1)
                        .append_str(working.compile().as_str());
                },
                c if c == '<' && form_mode
                    => working = Working::new('>', &template.label),
                c if c == '[' && form_mode
                    => working = Working::new(']', &template.text),
                c if c == '{' && form_mode
                    => working = Working::new('}', &template.textarea),
                c if c == '(' && form_mode
                    => working = Working::new(')', &template.button),
                // Handle the case we are working towards the end goal of an
                // incoming char
                c if c == working.until => row.get_col(col_index-1)
                        .append_str(working.compile().as_str()),
                _ => {
                    if working.is_working() {
                        working.append(c);
                    } else {
                        row.get_col(col_index-1).append(c)
                    }
                }
            }
        }
    }

    println!("{}", template.container_start);
    for row in rows {
        println!("{}", row.out(&template));
    }
    println!("{}", template.container_end);
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;

use std::io::stdin;
use std::io::Read;
use std::io;
use std::fmt::{self, Display, Debug};
//use std::io::BufRead;
//use nom::{Producer, Move, Input, Consumer, ConsumerState};
use nom::{le_u32};

/*
pub struct BufReadProducer<R: Read + BufRead> {
    reader: R
}

impl<R: Read + BufRead> BufReadProducer<R> {
    pub fn new(reader: R) -> BufReadProducer<R> {
        BufReadProducer { reader: reader }
    }
}

impl<'x, R: Read + BufRead> Producer<'x, &'x [u8], Move> for BufReadProducer<R> {
    fn apply<'a,O,E>(&'x mut self, consumer: &'a mut Consumer<&'x[u8],O,E,Move>) -> &'a ConsumerState<O,E,Move> {
        match consumer.state() {
            &ConsumerState::Continue(ref m) => {
                println!("{:?}", m);
                match *m {
                    Move::Await(_) => (),
                    Move::Consume(bytes) => self.reader.consume(bytes),
                    Move::Seek(position) => panic!("Can't seek BufReadProducer: {:?}", position)
                }

            },
            _  => return consumer.state()
        }

        match self.reader.fill_buf() {
            //TODO: it will probably not give any more data if buf is full -
            //infinite loop!?
            Ok(ref data) => consumer.handle(Input::Element(data)),
            Err(_) => consumer.handle(Input::Eof(None))
        }
    }

    fn run<'a: 'x,O,E: 'x>(&'x mut self, consumer: &'a mut Consumer<&'x[u8],O,E,Move>)   -> Option<&O> {
        //TODO: keep calling apply until we get Done or Err
        //TODO: handle Eof
        if let &ConsumerState::Done(_,ref o) = self.apply(consumer) {
            Some(o)
        } else {
            None
        }
    }
}

consumer_from_parser!(VslConsumer<VslRecordHeader>, vsl_record_header);
consumer_from_parser!(VslTagConsumer<()>, vsl_tag);
*/

/*
 * Shared memory log format
 *
 * The log member points to an array of 32bit unsigned integers containing
 * log records.
 *
 * Each logrecord consist of:
 *    [n]               = ((type & 0xff) << 24) | (length & 0xffff)
 *    [n + 1]           = ((marker & 0x03) << 30) | (identifier & 0x3fffffff)
 *    [n + 2] ... [m]   = content (NUL-terminated)
 *
 * Logrecords are NUL-terminated so that string functions can be run
 * directly on the shmlog data.
 *
 * Notice that the constants in these macros cannot be changed without
 * changing corresponding magic numbers in varnishd/cache/cache_shmlog.c
 */

const VSL_LENOFFSET: u32 = 24;
const VSL_LENMASK: u32 = 0xffff;
const VSL_MARKERMASK: u32 = 0x03;
const VSL_CLIENTMARKER: u32 = 1 << 30;
const VSL_BACKENDMARKER: u32 = 1 << 31;
const VSL_IDENTOFFSET: u32 = 30;
const VSL_IDENTMASK: u32 = !(3 << VSL_IDENTOFFSET);

#[derive(Debug)]
enum VslTag {
    BinaryVsl
}

named!(vsl_tag<&[u8], VslTag>, chain!(
        tag!(b"VSL\0"),
        || {
            VslTag::BinaryVsl
        }));

#[derive(Debug)]
struct VslRecordHeader {
    pub tag: u8,
    pub len: u16,
    pub marker: u8,
    pub ident: u32,
}

fn vsl_record_header<'b>(input: &'b[u8]) -> nom::IResult<&'b[u8], VslRecordHeader, u32> {
    chain!(
        input, r1: le_u32 ~ r2: le_u32,
        || {
            VslRecordHeader {
                tag: (r1 >> VSL_LENOFFSET) as u8,
                len: (r1 & VSL_LENMASK) as u16,
                marker: (r2 & VSL_MARKERMASK >> VSL_IDENTOFFSET) as u8,
                ident: r2 & VSL_IDENTMASK,
            }
        })
}

#[derive(Debug)]
struct VslRecord<'b> {
    pub tag: u8,
    pub marker: u8,
    pub ident: u32,
    pub data: &'b str,
    pub body: &'b[u8]
}

fn is_zero(i: u8) -> bool {
    i == 0
}

fn vsl_record<'b>(input: &'b[u8]) -> nom::IResult<&'b[u8], VslRecord<'b>, u32> {
    chain!(
        input,
        header: vsl_record_header ~ body: take!(header.len) ~ take_while!(is_zero),
        || {
            VslRecord { tag: header.tag, marker: header.marker, ident: header.ident, data: "foobar", body: body }
        })
}

fn vsl_records<'b>(input: &'b[u8]) -> nom::IResult<&'b[u8], Vec<VslRecord<'b>>, u32> {
    many1!(input, vsl_record)
}

#[derive(Debug)]
enum VslError<I, E> {
    IO(io::Error),
    NomErr(nom::Err<I, E>),
    NomNeeded(nom::Needed)
}

impl<I, E> From<io::Error> for VslError<I, E> {
    fn from(e: io::Error) -> VslError<I, E> {
        VslError::IO(e)
    }
}

impl<I, E> From<nom::Err<I, E>> for VslError<I, E> {
    fn from(e: nom::Err<I, E>) -> VslError<I, E> {
        VslError::NomErr(e)
    }
}

impl<I, E> From<nom::Needed> for VslError<I, E> {
    fn from(e: nom::Needed) -> VslError<I, E> {
        VslError::NomNeeded(e)
    }
}

trait ToVslResult<I, O, E> {
    fn into_vsl_result(self) -> Result<O, VslError<I, E>>;
}

impl<I, O, E> ToVslResult<I, O, E> for nom::IResult<I, O, E> {
    fn into_vsl_result(self) -> Result<O, VslError<I, E>> {
        match self {
            nom::IResult::Done(_, out) => Ok(out),
            nom::IResult::Error(e) => Err(From::from(e)),
            nom::IResult::Incomplete(n) => Err(From::from(n)),
        }
    }
}

impl<I, E> Display for VslError<I, E> where I: Debug, E: Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &VslError::IO(ref e) => write!(f, "Failed to read VSL data: {}", e),
            &VslError::NomErr(ref e) => write!(f, "Failed to parse VSL data: {}", e),
            &VslError::NomNeeded(ref e) => write!(f, "Not enought data to parse VSL: {:?}", e),
        }
    }
}

fn read_data_tag<'b, R: Read>(reader: &mut R, buf: &'b mut [u8; 4]) -> Result<VslTag, VslError<&'b[u8], u32>> {
    try!(reader.read_exact(buf));
    vsl_tag(buf).into_vsl_result()
}

fn main() {
    let stdin = stdin();
    let mut stdin = stdin.lock();

    let mut buf = [0u8; 4];
    let tag = read_data_tag(&mut stdin, &mut buf).expect("Failed to parse data tag");

    println!("Tag: {:?}", &tag);
    match tag {
        VslTag::BinaryVsl => {
            let mut buf = Vec::new();
            stdin.read_to_end(&mut buf);

            let records = vsl_records(buf.as_slice()).into_vsl_result();
            println!("Record: {:?}", &records);
        }
    }
}
<commit_msg>custom debugging for VSL Record<commit_after>#[macro_use]
extern crate nom;

use std::io::stdin;
use std::io::Read;
use std::io;
use std::fmt::{self, Display, Debug};
use std::ffi::{CStr, FromBytesWithNulError};
//use std::io::BufRead;
//use nom::{Producer, Move, Input, Consumer, ConsumerState};
use nom::{le_u32};

/*
pub struct BufReadProducer<R: Read + BufRead> {
    reader: R
}

impl<R: Read + BufRead> BufReadProducer<R> {
    pub fn new(reader: R) -> BufReadProducer<R> {
        BufReadProducer { reader: reader }
    }
}

impl<'x, R: Read + BufRead> Producer<'x, &'x [u8], Move> for BufReadProducer<R> {
    fn apply<'a,O,E>(&'x mut self, consumer: &'a mut Consumer<&'x[u8],O,E,Move>) -> &'a ConsumerState<O,E,Move> {
        match consumer.state() {
            &ConsumerState::Continue(ref m) => {
                println!("{:?}", m);
                match *m {
                    Move::Await(_) => (),
                    Move::Consume(bytes) => self.reader.consume(bytes),
                    Move::Seek(position) => panic!("Can't seek BufReadProducer: {:?}", position)
                }

            },
            _  => return consumer.state()
        }

        match self.reader.fill_buf() {
            //TODO: it will probably not give any more data if buf is full -
            //infinite loop!?
            Ok(ref data) => consumer.handle(Input::Element(data)),
            Err(_) => consumer.handle(Input::Eof(None))
        }
    }

    fn run<'a: 'x,O,E: 'x>(&'x mut self, consumer: &'a mut Consumer<&'x[u8],O,E,Move>)   -> Option<&O> {
        //TODO: keep calling apply until we get Done or Err
        //TODO: handle Eof
        if let &ConsumerState::Done(_,ref o) = self.apply(consumer) {
            Some(o)
        } else {
            None
        }
    }
}

consumer_from_parser!(VslConsumer<VslRecordHeader>, vsl_record_header);
consumer_from_parser!(VslTagConsumer<()>, vsl_tag);
*/

/*
 * Shared memory log format
 *
 * The log member points to an array of 32bit unsigned integers containing
 * log records.
 *
 * Each logrecord consist of:
 *    [n]               = ((type & 0xff) << 24) | (length & 0xffff)
 *    [n + 1]           = ((marker & 0x03) << 30) | (identifier & 0x3fffffff)
 *    [n + 2] ... [m]   = content (NUL-terminated)
 *
 * Logrecords are NUL-terminated so that string functions can be run
 * directly on the shmlog data.
 *
 * Notice that the constants in these macros cannot be changed without
 * changing corresponding magic numbers in varnishd/cache/cache_shmlog.c
 */

const VSL_LENOFFSET: u32 = 24;
const VSL_LENMASK: u32 = 0xffff;
const VSL_MARKERMASK: u32 = 0x03;
//const VSL_CLIENTMARKER: u32 = 1 << 30;
//const VSL_BACKENDMARKER: u32 = 1 << 31;
const VSL_IDENTOFFSET: u32 = 30;
const VSL_IDENTMASK: u32 = !(3 << VSL_IDENTOFFSET);

#[derive(Debug)]
enum VslTag {
    BinaryVsl
}

named!(vsl_tag<&[u8], VslTag>, chain!(
        tag!(b"VSL\0"),
        || {
            VslTag::BinaryVsl
        }));

#[derive(Debug)]
struct VslRecordHeader {
    pub tag: u8,
    pub len: u16,
    pub marker: u8,
    pub ident: u32,
}

fn vsl_record_header<'b>(input: &'b[u8]) -> nom::IResult<&'b[u8], VslRecordHeader, u32> {
    chain!(
        input, r1: le_u32 ~ r2: le_u32,
        || {
            VslRecordHeader {
                tag: (r1 >> VSL_LENOFFSET) as u8,
                len: (r1 & VSL_LENMASK) as u16,
                marker: (r2 & VSL_MARKERMASK >> VSL_IDENTOFFSET) as u8,
                ident: r2 & VSL_IDENTMASK,
            }
        })
}

struct VslRecord<'b> {
    pub tag: u8,
    pub marker: u8,
    pub ident: u32,
    pub data: &'b[u8],
}

impl<'b> VslRecord<'b> {
    fn body(&'b self) -> Result<&'b CStr, FromBytesWithNulError> {
        CStr::from_bytes_with_nul(self.data)
    }
}

impl<'b> Debug for VslRecord<'b> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        f.debug_struct("VSL Record")
            .field("tag", &self.tag)
            .field("marker", &self.marker)
            .field("ident", &self.ident)
            .field("body", &self.body())
            .finish()
    }
}

fn is_zero(i: u8) -> bool { i == 0 }

fn vsl_record<'b>(input: &'b[u8]) -> nom::IResult<&'b[u8], VslRecord<'b>, u32> {
    chain!(
        input,
        header: vsl_record_header ~ data: take!(header.len) ~ take_while!(is_zero),
        || {
            VslRecord { tag: header.tag, marker: header.marker, ident: header.ident, data: data }
        })
}

fn vsl_records<'b>(input: &'b[u8]) -> nom::IResult<&'b[u8], Vec<VslRecord<'b>>, u32> {
    many1!(input, vsl_record)
}

#[derive(Debug)]
enum VslError<I, E> {
    IO(io::Error),
    NomErr(nom::Err<I, E>),
    NomNeeded(nom::Needed)
}

impl<I, E> From<io::Error> for VslError<I, E> {
    fn from(e: io::Error) -> VslError<I, E> {
        VslError::IO(e)
    }
}

impl<I, E> From<nom::Err<I, E>> for VslError<I, E> {
    fn from(e: nom::Err<I, E>) -> VslError<I, E> {
        VslError::NomErr(e)
    }
}

impl<I, E> From<nom::Needed> for VslError<I, E> {
    fn from(e: nom::Needed) -> VslError<I, E> {
        VslError::NomNeeded(e)
    }
}

trait ToVslResult<I, O, E> {
    fn into_vsl_result(self) -> Result<O, VslError<I, E>>;
}

impl<I, O, E> ToVslResult<I, O, E> for nom::IResult<I, O, E> {
    fn into_vsl_result(self) -> Result<O, VslError<I, E>> {
        match self {
            nom::IResult::Done(_, out) => Ok(out),
            nom::IResult::Error(e) => Err(From::from(e)),
            nom::IResult::Incomplete(n) => Err(From::from(n)),
        }
    }
}

impl<I, E> Display for VslError<I, E> where I: Debug, E: Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &VslError::IO(ref e) => write!(f, "Failed to read VSL data: {}", e),
            &VslError::NomErr(ref e) => write!(f, "Failed to parse VSL data: {}", e),
            &VslError::NomNeeded(ref e) => write!(f, "Not enought data to parse VSL: {:?}", e),
        }
    }
}

fn read_data_tag<'b, R: Read>(reader: &mut R, buf: &'b mut [u8; 4]) -> Result<VslTag, VslError<&'b[u8], u32>> {
    try!(reader.read_exact(buf));
    vsl_tag(buf).into_vsl_result()
}

fn main() {
    let stdin = stdin();
    let mut stdin = stdin.lock();

    let mut buf = [0u8; 4];
    let tag = read_data_tag(&mut stdin, &mut buf).expect("Failed to parse data tag");

    println!("Tag: {:?}", &tag);
    match tag {
        VslTag::BinaryVsl => {
            let mut buf = Vec::new();
            stdin.read_to_end(&mut buf).unwrap();

            let records = vsl_records(buf.as_slice()).into_vsl_result();
            println!("Record: {:?}", &records);
        }
    }
}
<|endoftext|>