<commit_before>use std::io;
use std::path::{Path, PathBuf};
use std::process::{Command, Output};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread::{self, JoinHandle};
use std::time::Duration;

const REPO_URL: &'static str = "https://github.com/nrc/rustaceans.org.git";

pub struct Updater {
    data_dir: PathBuf,
    keep_going: Arc<AtomicBool>,
    worker: JoinHandle<()>,
}

impl Updater {
    pub fn start<P: AsRef<Path>>(root: P) -> io::Result<Updater> {
        let Output { status, stdout, .. } = git().arg("--version").output()?;
        if !status.success() {
            return Err(io::Error::new(io::ErrorKind::Other, "failed to check git version"));
        }
        info!("found git: {}", String::from_utf8_lossy(&stdout).trim());

        let repo_dir = root.as_ref().join("data");
        if !repo_dir.is_dir() {
            // Clone the repo
            info!("cloning rustaceans data");
            let status = git().arg("clone").arg(REPO_URL).arg(&repo_dir).status()?;
            if !status.success() {
                return Err(io::Error::new(io::ErrorKind::Other, "failed to clone data repository"));
            }
        }

        let keep_going = Arc::new(AtomicBool::new(true));

        let worker = {
            let repo_dir = repo_dir.clone();
            let keep_going = keep_going.clone();
            thread::spawn(move || while keep_going.load(Ordering::SeqCst) {
                thread::sleep(Duration::from_secs(5 * 60));
                info!("updating rustaceans data");
                match git().arg("pull").arg("--ff-only").current_dir(&repo_dir).status() {
                    Ok(status) if status.success() => {},
                    Ok(status) => error!("update failed with exit status {}", status),
                    Err(e) => error!("update failed with error: {}", e),
                }
                info!("updated successfully");
            })
        };

        Ok(Updater {
            data_dir: repo_dir.join("data"),
            keep_going: keep_going,
            worker: worker,
        })
    }

    pub fn data_dir(&self) -> &Path {
        &self.data_dir
    }

    #[allow(dead_code)]  // FIXME(#15)
    pub fn stop(self) -> thread::Result<()> {
        self.keep_going.store(false, Ordering::SeqCst);
        self.worker.join()
    }
}

fn git() -> Command {
    Command::new("git")
}
<commit_msg>Remove graceful shutdown code<commit_after>use std::io;
use std::path::{Path, PathBuf};
use std::process::{Command, Output};
use std::thread;
use std::time::Duration;

const REPO_URL: &'static str = "https://github.com/nrc/rustaceans.org.git";

pub struct Updater {
    data_dir: PathBuf,
}

impl Updater {
    pub fn start<P: AsRef<Path>>(root: P) -> io::Result<Updater> {
        let Output { status, stdout, .. } = git().arg("--version").output()?;
        if !status.success() {
            return Err(io::Error::new(io::ErrorKind::Other, "failed to check git version"));
        }
        info!("found git: {}", String::from_utf8_lossy(&stdout).trim());

        let repo_dir = root.as_ref().join("data");
        if !repo_dir.is_dir() {
            // Clone the repo
            info!("cloning rustaceans data");
            let status = git().arg("clone").arg(REPO_URL).arg(&repo_dir).status()?;
            if !status.success() {
                return Err(io::Error::new(io::ErrorKind::Other, "failed to clone data repository"));
            }
        }

        {
            let repo_dir = repo_dir.clone();
            thread::spawn(move || loop {
                thread::sleep(Duration::from_secs(5 * 60));
                info!("updating rustaceans data");
                match git().arg("pull").arg("--ff-only").current_dir(&repo_dir).status() {
                    Ok(status) if status.success() => {},
                    Ok(status) => error!("update failed with exit status {}", status),
                    Err(e) => error!("update failed with error: {}", e),
                }
                info!("updated successfully");
            });
        }

        Ok(Updater { data_dir: repo_dir.join("data") })
    }

    pub fn data_dir(&self) -> &Path {
        &self.data_dir
    }
}

fn git() -> Command {
    Command::new("git")
}
<|endoftext|>


<commit_before>extern crate proc_macro;

use proc_macro::TokenStream;
use proc_macro2::{Span, TokenStream as TokenStream2};
use quote::{quote, ToTokens, TokenStreamExt};
use syn::{AttributeArgs, Ident, NestedMeta};

enum ResourceType {
    Async,
    Sync,
}

impl ToTokens for ResourceType {
    fn to_tokens(&self, stream: &mut TokenStream2) {
        let ident = match self {
            ResourceType::Async => "to",
            ResourceType::Sync => "to",
        };
        let ident = Ident::new(ident, Span::call_site());
        stream.append(ident);
    }
}

#[derive(PartialEq)]
pub enum GuardType {
    Get,
    Post,
    Put,
    Delete,
    Head,
    Connect,
    Options,
    Trace,
    Patch,
}

impl GuardType {
    fn as_str(&self) -> &'static str {
        match self {
            GuardType::Get => "Get",
            GuardType::Post => "Post",
            GuardType::Put => "Put",
            GuardType::Delete => "Delete",
            GuardType::Head => "Head",
            GuardType::Connect => "Connect",
            GuardType::Options => "Options",
            GuardType::Trace => "Trace",
            GuardType::Patch => "Patch",
        }
    }
}

impl ToTokens for GuardType {
    fn to_tokens(&self, stream: &mut TokenStream2) {
        let ident = self.as_str();
        let ident = Ident::new(ident, Span::call_site());
        stream.append(ident);
    }
}

struct Args {
    path: syn::LitStr,
    guards: Vec<Ident>,
}

impl Args {
    fn new(args: AttributeArgs) -> syn::Result<Self> {
        let mut path = None;
        let mut guards = Vec::new();
        for arg in args {
            match arg {
                NestedMeta::Lit(syn::Lit::Str(lit)) => match path {
                    None => {
                        path = Some(lit);
                    }
                    _ => {
                        return Err(syn::Error::new_spanned(
                            lit,
                            "Multiple paths specified! Should be only one!",
                        ));
                    }
                },
                NestedMeta::Meta(syn::Meta::NameValue(nv)) => {
                    if nv.path.is_ident("guard") {
                        if let syn::Lit::Str(lit) = nv.lit {
                            guards.push(Ident::new(&lit.value(), Span::call_site()));
                        } else {
                            return Err(syn::Error::new_spanned(
                                nv.lit,
                                "Attribute guard expects literal string!",
                            ));
                        }
                    } else {
                        return Err(syn::Error::new_spanned(
                            nv.path,
                            "Unknown attribute key is specified. Allowed: guard",
                        ));
                    }
                }
                arg => {
                    return Err(syn::Error::new_spanned(arg, "Unknown attribute"));
                }
            }
        }
        Ok(Args {
            path: path.unwrap(),
            guards,
        })
    }
}

pub struct Route {
    name: syn::Ident,
    args: Args,
    ast: syn::ItemFn,
    resource_type: ResourceType,
    guard: GuardType,
}

fn guess_resource_type(typ: &syn::Type) -> ResourceType {
    let mut guess = ResourceType::Sync;

    if let syn::Type::ImplTrait(typ) = typ {
        for bound in typ.bounds.iter() {
            if let syn::TypeParamBound::Trait(bound) = bound {
                for bound in bound.path.segments.iter() {
                    if bound.ident == "Future" {
                        guess = ResourceType::Async;
                        break;
                    } else if bound.ident == "Responder" {
                        guess = ResourceType::Sync;
                        break;
                    }
                }
            }
        }
    }

    guess
}

impl Route {
    pub fn new(
        args: AttributeArgs,
        input: TokenStream,
        guard: GuardType,
    ) -> syn::Result<Self> {
        if args.is_empty() {
            return Err(syn::Error::new(
                Span::call_site(),
                format!(
                    r#"invalid server definition, expected #[{}("<some path>")]"#,
                    guard.as_str().to_ascii_lowercase()
                ),
            ));
        }
        let ast: syn::ItemFn = syn::parse(input)?;
        let name = ast.sig.ident.clone();

        let args = Args::new(args)?;

        let resource_type = if ast.sig.asyncness.is_some() {
            ResourceType::Async
        } else {
            match ast.sig.output {
                syn::ReturnType::Default => {
                    return Err(syn::Error::new_spanned(
                        ast,
                        "Function has no return type. Cannot be used as handler",
                    ));
                }
                syn::ReturnType::Type(_, ref typ) => guess_resource_type(typ.as_ref()),
            }
        };

        Ok(Self {
            name,
            args,
            ast,
            resource_type,
            guard,
        })
    }

    pub fn generate(&self) -> TokenStream {
        let name = &self.name;
        let guard = &self.guard;
        let ast = &self.ast;
        let path = &self.args.path;
        let extra_guards = &self.args.guards;
        let resource_type = &self.resource_type;
        let stream = quote! {
            #[allow(non_camel_case_types)]
            pub struct #name;

            impl actix_web::dev::HttpServiceFactory for #name {
                fn register(self, config: &mut actix_web::dev::AppService) {
                    #ast

                    let resource = actix_web::Resource::new(#path)
                        .guard(actix_web::guard::#guard())
                        #(.guard(actix_web::guard::fn_guard(#extra_guards)))*
                        .#resource_type(#name);

                    actix_web::dev::HttpServiceFactory::register(resource, config)
                }
            }
        };
        stream.into()
    }
}
<commit_msg>Set name for each generated resource<commit_after>extern crate proc_macro;

use proc_macro::TokenStream;
use proc_macro2::{Span, TokenStream as TokenStream2};
use quote::{quote, ToTokens, TokenStreamExt};
use syn::{AttributeArgs, Ident, NestedMeta};

enum ResourceType {
    Async,
    Sync,
}

impl ToTokens for ResourceType {
    fn to_tokens(&self, stream: &mut TokenStream2) {
        let ident = match self {
            ResourceType::Async => "to",
            ResourceType::Sync => "to",
        };
        let ident = Ident::new(ident, Span::call_site());
        stream.append(ident);
    }
}

#[derive(PartialEq)]
pub enum GuardType {
    Get,
    Post,
    Put,
    Delete,
    Head,
    Connect,
    Options,
    Trace,
    Patch,
}

impl GuardType {
    fn as_str(&self) -> &'static str {
        match self {
            GuardType::Get => "Get",
            GuardType::Post => "Post",
            GuardType::Put => "Put",
            GuardType::Delete => "Delete",
            GuardType::Head => "Head",
            GuardType::Connect => "Connect",
            GuardType::Options => "Options",
            GuardType::Trace => "Trace",
            GuardType::Patch => "Patch",
        }
    }
}

impl ToTokens for GuardType {
    fn to_tokens(&self, stream: &mut TokenStream2) {
        let ident = self.as_str();
        let ident = Ident::new(ident, Span::call_site());
        stream.append(ident);
    }
}

struct Args {
    path: syn::LitStr,
    guards: Vec<Ident>,
}

impl Args {
    fn new(args: AttributeArgs) -> syn::Result<Self> {
        let mut path = None;
        let mut guards = Vec::new();
        for arg in args {
            match arg {
                NestedMeta::Lit(syn::Lit::Str(lit)) => match path {
                    None => {
                        path = Some(lit);
                    }
                    _ => {
                        return Err(syn::Error::new_spanned(
                            lit,
                            "Multiple paths specified! Should be only one!",
                        ));
                    }
                },
                NestedMeta::Meta(syn::Meta::NameValue(nv)) => {
                    if nv.path.is_ident("guard") {
                        if let syn::Lit::Str(lit) = nv.lit {
                            guards.push(Ident::new(&lit.value(), Span::call_site()));
                        } else {
                            return Err(syn::Error::new_spanned(
                                nv.lit,
                                "Attribute guard expects literal string!",
                            ));
                        }
                    } else {
                        return Err(syn::Error::new_spanned(
                            nv.path,
                            "Unknown attribute key is specified. Allowed: guard",
                        ));
                    }
                }
                arg => {
                    return Err(syn::Error::new_spanned(arg, "Unknown attribute"));
                }
            }
        }
        Ok(Args {
            path: path.unwrap(),
            guards,
        })
    }
}

pub struct Route {
    name: syn::Ident,
    args: Args,
    ast: syn::ItemFn,
    resource_type: ResourceType,
    guard: GuardType,
}

fn guess_resource_type(typ: &syn::Type) -> ResourceType {
    let mut guess = ResourceType::Sync;

    if let syn::Type::ImplTrait(typ) = typ {
        for bound in typ.bounds.iter() {
            if let syn::TypeParamBound::Trait(bound) = bound {
                for bound in bound.path.segments.iter() {
                    if bound.ident == "Future" {
                        guess = ResourceType::Async;
                        break;
                    } else if bound.ident == "Responder" {
                        guess = ResourceType::Sync;
                        break;
                    }
                }
            }
        }
    }

    guess
}

impl Route {
    pub fn new(
        args: AttributeArgs,
        input: TokenStream,
        guard: GuardType,
    ) -> syn::Result<Self> {
        if args.is_empty() {
            return Err(syn::Error::new(
                Span::call_site(),
                format!(
                    r#"invalid server definition, expected #[{}("<some path>")]"#,
                    guard.as_str().to_ascii_lowercase()
                ),
            ));
        }
        let ast: syn::ItemFn = syn::parse(input)?;
        let name = ast.sig.ident.clone();

        let args = Args::new(args)?;

        let resource_type = if ast.sig.asyncness.is_some() {
            ResourceType::Async
        } else {
            match ast.sig.output {
                syn::ReturnType::Default => {
                    return Err(syn::Error::new_spanned(
                        ast,
                        "Function has no return type. Cannot be used as handler",
                    ));
                }
                syn::ReturnType::Type(_, ref typ) => guess_resource_type(typ.as_ref()),
            }
        };

        Ok(Self {
            name,
            args,
            ast,
            resource_type,
            guard,
        })
    }

    pub fn generate(&self) -> TokenStream {
        let name = &self.name;
        let resource_name = name.to_string();
        let guard = &self.guard;
        let ast = &self.ast;
        let path = &self.args.path;
        let extra_guards = &self.args.guards;
        let resource_type = &self.resource_type;
        let stream = quote! {
            #[allow(non_camel_case_types)]
            pub struct #name;

            impl actix_web::dev::HttpServiceFactory for #name {
                fn register(self, config: &mut actix_web::dev::AppService) {
                    #ast
                    let resource = actix_web::Resource::new(#path)
                        .name(#resource_name)
                        .guard(actix_web::guard::#guard())
                        #(.guard(actix_web::guard::fn_guard(#extra_guards)))*
                        .#resource_type(#name);

                    actix_web::dev::HttpServiceFactory::register(resource, config)
                }
            }
        };
        stream.into()
    }
}
<|endoftext|>


<commit_before>mod rust_source;

use rust_source::rust_source::{a, d};

fn test_uper_c_source_a() {
    let mut encoded = [0; 42];
    let mut a: a::A = Default::default();

    // Encode.
    a.a = -1;
    a.b = -2;
    a.c = -3;
    a.d = -4;
    a.e = 1;
    a.f = 2;
    a.g = 3;
    a.h = 4;
    a.i = true;
    a.j.buf = [5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5];

    assert_eq!(a.to_bytes(&mut encoded).unwrap(), encoded.len());
    assert_eq!(encoded[..],
               [
                   0x7f, 0x7f, 0xfe, 0x7f, 0xff, 0xff, 0xfd, 0x7f, 0xff, 0xff,
                   0xff, 0xff, 0xff, 0xff, 0xfc, 0x01, 0x00, 0x02, 0x00, 0x00,
                   0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
                   0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
                   0x82, 0x80
               ][..]);

    // Decode.
    a = Default::default();

    assert_eq!(a.from_bytes(&encoded).unwrap(), encoded.len());
    assert_eq!(a,
               a::A {
                   a: -1,
                   b: -2,
                   c: -3,
                   d: -4,
                   e: 1,
                   f: 2,
                   g: 3,
                   h: 4,
                   i: true,
                   j: a::AJ {
                       buf: [5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5]
                   }
               });
}

fn test_uper_c_source_d_all_present() {
    let mut encoded = [0; 10];
    let mut d: d::D = Default::default();

    // Encode.
    d.length = 1;
    d.elements[0].a.b = d::DElemAB::C(0);
    d.elements[0].a.e.length = 3;
    d.elements[0].g.h = d::DElemGH::J;
    d.elements[0].g.l.length = 2;
    d.elements[0].g.l.buf = [0x54, 0x55];
    d.elements[0].m.is_n_present = true;
    d.elements[0].m.n = false;
    d.elements[0].m.o = 2;
    d.elements[0].m.is_p_present = true;
    d.elements[0].m.p = d::DElemMP {
        q: d::DElemMPQ {
            buf: [3, 3, 3, 3, 3]
        },
        is_r_present: true,
        r: true
    };

    assert_eq!(d.to_bytes(&mut encoded).unwrap(), encoded.len());
    assert_eq!(encoded[..],
               [
                   0x00, 0xd5, 0x15, 0x7a, 0x40, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0
               ][..]);

    // Decode.
    d = Default::default();

    assert_eq!(d.from_bytes(&encoded).unwrap(), encoded.len());

    assert_eq!(d.length, 1);
    assert_eq!(d.elements[0].a.b, d::DElemAB::C(0));
    assert_eq!(d.elements[0].a.e.length, 3);
    assert_eq!(d.elements[0].g.h, d::DElemGH::J);
    assert_eq!(d.elements[0].g.l.length, 2);
    assert_eq!(d.elements[0].g.l.buf, [0x54, 0x55]);
    assert_eq!(d.elements[0].m.is_n_present, true);
    assert_eq!(d.elements[0].m.n, false);
    assert_eq!(d.elements[0].m.o, 2);
    assert_eq!(d.elements[0].m.is_p_present, true);
    assert_eq!(d.elements[0].m.p, d::DElemMP {
        q: d::DElemMPQ {
            buf: [3, 3, 3, 3, 3]
        },
        is_r_present: true,
        r: true
    });
}

fn main() {
    test_uper_c_source_a();
    test_uper_c_source_d_all_present();
}
<commit_msg>More Rust tests.<commit_after>mod rust_source;

use rust_source::rust_source::{a, d};

fn test_uper_c_source_a() {
    let mut encoded = [0; 42];
    let mut a: a::A = Default::default();

    // Encode.
    a.a = -1;
    a.b = -2;
    a.c = -3;
    a.d = -4;
    a.e = 1;
    a.f = 2;
    a.g = 3;
    a.h = 4;
    a.i = true;
    a.j.buf = [5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5];

    assert_eq!(a.to_bytes(&mut encoded).unwrap(), encoded.len());
    assert_eq!(encoded[..],
               [
                   0x7f, 0x7f, 0xfe, 0x7f, 0xff, 0xff, 0xfd, 0x7f, 0xff, 0xff,
                   0xff, 0xff, 0xff, 0xff, 0xfc, 0x01, 0x00, 0x02, 0x00, 0x00,
                   0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
                   0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
                   0x82, 0x80
               ][..]);

    // Decode.
    a = Default::default();

    assert_eq!(a.from_bytes(&encoded).unwrap(), encoded.len());
    assert_eq!(a,
               a::A {
                   a: -1,
                   b: -2,
                   c: -3,
                   d: -4,
                   e: 1,
                   f: 2,
                   g: 3,
                   h: 4,
                   i: true,
                   j: a::AJ {
                       buf: [5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5]
                   }
               });
}

fn test_uper_c_source_a_encode_error_no_mem() {
    let mut encoded = [0; 41];
    let mut a: a::A = Default::default();

    a.a = -1;
    a.b = -2;
    a.c = -3;
    a.d = -4;
    a.e = 1;
    a.f = 2;
    a.g = 3;
    a.h = 4;
    a.i = true;
    a.j.buf = [5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5];

    assert_eq!(a.to_bytes(&mut encoded), Err("Out of memory."));
}

fn test_uper_c_source_a_decode_error_out_of_data() {
    let encoded = [
        0x7f, 0x7f, 0xfe, 0x7f, 0xff, 0xff, 0xfd, 0x7f, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xfc, 0x01, 0x00, 0x02, 0x00, 0x00,
        0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
        0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
        0x82
    ];
    let mut a: a::A = Default::default();

    assert_eq!(a.from_bytes(&encoded), Err("Out of data."));
}

fn test_uper_c_source_d_all_present() {
    let mut encoded = [0; 10];
    let mut d: d::D = Default::default();

    // Encode.
    d.length = 1;
    d.elements[0].a.b = d::DElemAB::C(0);
    d.elements[0].a.e.length = 3;
    d.elements[0].g.h = d::DElemGH::J;
    d.elements[0].g.l.length = 2;
    d.elements[0].g.l.buf = [0x54, 0x55];
    d.elements[0].m.is_n_present = true;
    d.elements[0].m.n = false;
    d.elements[0].m.o = 2;
    d.elements[0].m.is_p_present = true;
    d.elements[0].m.p.q.buf = [3, 3, 3, 3, 3];
    d.elements[0].m.p.is_r_present = true;
    d.elements[0].m.p.r = true;

    assert_eq!(d.to_bytes(&mut encoded).unwrap(), encoded.len());
    assert_eq!(encoded[..],
               [
                   0x00, 0xd5, 0x15, 0x7a, 0x40, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0
               ][..]);

    // Decode.
    d = Default::default();

    assert_eq!(d.from_bytes(&encoded).unwrap(), encoded.len());

    assert_eq!(d.length, 1);
    assert_eq!(d.elements[0].a.b, d::DElemAB::C(0));
    assert_eq!(d.elements[0].a.e.length, 3);
    assert_eq!(d.elements[0].g.h, d::DElemGH::J);
    assert_eq!(d.elements[0].g.l.length, 2);
    assert_eq!(d.elements[0].g.l.buf, [0x54, 0x55]);
    assert_eq!(d.elements[0].m.is_n_present, true);
    assert_eq!(d.elements[0].m.n, false);
    assert_eq!(d.elements[0].m.o, 2);
    assert_eq!(d.elements[0].m.is_p_present, true);
    assert_eq!(d.elements[0].m.p.q.buf, [3, 3, 3, 3, 3]);
    assert_eq!(d.elements[0].m.p.is_r_present, true);
    assert_eq!(d.elements[0].m.p.r, true);
}

fn test_uper_c_source_d_some_missing() {
    let mut encoded = [0; 8];
    let mut d: d::D = Default::default();

    // Encode.
    d.length = 1;
    d.elements[0].a.b = d::DElemAB::D(false);
    d.elements[0].a.e.length = 3;
    d.elements[0].g.h = d::DElemGH::K;
    d.elements[0].g.l.length = 1;
    d.elements[0].g.l.buf[0] = 0x54;
    d.elements[0].m.is_n_present = false;
    // Default value 3.
    d.elements[0].m.o = 3;
    d.elements[0].m.is_p_present = true;
    d.elements[0].m.p.q.buf = [3, 3, 3, 3, 3];
    d.elements[0].m.p.is_r_present = false;

    assert_eq!(d.to_bytes(&mut encoded).unwrap(), encoded.len());
    assert_eq!(encoded[..],
               [
                   0x09, 0x15, 0x08, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c
               ][..]);

    // Decode.
    d = Default::default();

    assert_eq!(d.from_bytes(&encoded).unwrap(), encoded.len());

    assert_eq!(d.length, 1);
    assert_eq!(d.elements[0].a.b, d::DElemAB::D(false));
    assert_eq!(d.elements[0].a.e.length, 3);
    assert_eq!(d.elements[0].g.h, d::DElemGH::K);
    assert_eq!(d.elements[0].g.l.length, 1);
    assert_eq!(d.elements[0].g.l.buf[0], 0x54);
    assert_eq!(d.elements[0].m.is_n_present, false);
    assert_eq!(d.elements[0].m.o, 3);
    assert_eq!(d.elements[0].m.is_p_present, true);
    assert_eq!(d.elements[0].m.p.q.buf, [3, 3, 3, 3, 3]);
    assert_eq!(d.elements[0].m.p.is_r_present, false);
}

fn main() {
    test_uper_c_source_a();
    test_uper_c_source_a_encode_error_no_mem();
    test_uper_c_source_a_decode_error_out_of_data();

    test_uper_c_source_d_all_present();
    test_uper_c_source_d_some_missing();
}
<|endoftext|>


<commit_before>mod r5rs {
    #[deriving(Eq)]
    enum LDatum {
        LIdent(~str),
        LString(~str),
        LChar(char),
    }

    struct Parser {
        priv reader: @io::Reader,
        priv buf: char,
        priv has_buf: bool,
        line: uint,
        col: uint,
    }

    pub fn Parser(reader: @io::Reader) -> Parser {
        Parser {
            reader: reader,
            has_buf: false,
            buf: 0 as char,
            line: 1,
            col: 1,
        }
    }

    priv fn id_init(c: char) -> bool {
        match(c) {
            '!' | '$' | '%' | '&' | '*' | '/' | ':' | '<' | '=' | '>' | '?' | '^' | '_' | '~' | 'a' .. 'z' | 'A' .. 'Z' => true,
            _ => false,
        }
    }

    pub impl Parser {
        fn parse(&mut self) -> Result<LDatum, ~str> {
            do result::chain(self.parse_datum()) |v| {
                self.consume_whitespace();

                if(self.eof()) {
                    Ok(v)
                } else {
                    Err(~"trailing input")
                }
            }
        }
    }

    priv impl Parser {
        fn eof(&mut self) -> bool {
            !self.has_buf && self.reader.eof()
        }

        fn consume(&mut self) -> char {
            if(self.has_buf) {
                self.has_buf = false;
            } else {
                self.buf = self.reader.read_char();
            }

            if(self.buf == '\n') {
                self.line += 1;
                self.col = 1;
            } else {
                self.col += 1;
            }

            self.buf
        }

        fn lookahead(&mut self) -> char {
            if(!self.has_buf) {
                self.has_buf = true;
                self.buf = self.reader.read_char();
            }
            self.buf
        }

        fn consume_whitespace(&mut self) {
            while(!self.eof()) {
                match(self.lookahead()) {
                    ' '| '\t' | '\r' | '\n' => { self.consume(); },
                    _ => break
                }
            }
        }

        fn parse_datum(&mut self) -> Result<LDatum, ~str> {
            self.consume_whitespace();

            if(self.eof()) {
                return Err(~"unexpected EOF");
            }

            let c = self.consume();
            match(c) {
                _ if id_init(c) =>
                    Ok(LIdent(self.parse_ident(c))),
                '"' => {
                        match(self.parse_string()) {
                            Ok(s) => Ok(LString(s)),
                            Err(e) => Err(e),
                        }
                    },
                '#' => {
                        self.parse_sharp()
                    },
                _ =>
                    Err(~"unexpected character: " + str::from_char(c)),
            }
        }

        fn parse_sharp(&mut self) -> Result<LDatum, ~str> {
            if(self.eof()) {
                return Err(~"unexpected EOF");
            }

            let c = self.consume();
            match(c) {
                '\\' =>
                    do result::map(&self.parse_char()) |&c| {
                        LChar(c)
                    },
                _ =>
                    Err(~"unexpected character: " + str::from_char(c)),
            }
        }

        fn parse_char(&mut self) -> Result<char, ~str> {
            if(self.eof()) {
                Err(~"unexpected EOF")
            } else {
                Ok(self.consume())
            }
        }

        fn parse_ident(&mut self, init: char) -> ~str {
            do io::with_str_writer |wr| {
                wr.write_char(init);

                while(!self.eof()) {
                    let c = self.lookahead();

                    match(c) {
                        '0' .. '9' | '+' | '-' | '.' | '@' => wr.write_char(c),
                        _ if id_init(c) => wr.write_char(c),
                        _ => break,
                    }

                    self.consume();
                }
            }
        }

        fn parse_string(&mut self) -> Result<~str, ~str> {
            let mut escape_fail = false;

            let val = do io::with_str_writer |wr| {
                while(!self.eof()) {
                    let c = self.consume();
                    match(c) {
                        '\\' => if self.eof() {
                                    escape_fail = true;
                                } else {
                                    wr.write_char(self.consume());
                                },
                        '"' => break,
                        _ => wr.write_char(c),
                    }
                }
            };

            if(escape_fail) {
                Err(~"unexpected EOF")
            } else {
                Ok(val)
            }
        }
    }

    #[test]
    fn test_parse_ident() {
        let test_src = ~"a3!";

        do io::with_str_reader(test_src) |rdr| {
            let mut parser = Parser(rdr);
            let val = parser.parse();
            assert_eq!(Ok(LIdent(~"a3!")), val);
        }
    }

    #[test]
    fn test_parse_string() {
        let test_src = ~"\"ab\\\"c\"";

        do io::with_str_reader(test_src) |rdr| {
            let mut parser = Parser(rdr);
            let val = parser.parse();
            assert_eq!(Ok(LString(~"ab\"c")), val);
        }
    }

    #[test]
    fn test_parse_char() {
        let test_src = ~"#\\h";

        do io::with_str_reader(test_src) |rdr| {
            let mut parser = Parser(rdr);
            let val = parser.parse();
            assert_eq!(Ok(LChar('h')), val);
        }
    }
}
<commit_msg>parse #t, #f, #\space, #\newline<commit_after>mod r5rs {
    #[deriving(Eq)]
    enum LDatum {
        LIdent(~str),
        LString(~str),
        LChar(char),
        LBool(bool),
    }

    struct Parser {
        priv reader: @io::Reader,
        priv buf: char,
        priv has_buf: bool,
        line: uint,
        col: uint,
    }

    pub fn Parser(reader: @io::Reader) -> Parser {
        Parser {
            reader: reader,
            has_buf: false,
            buf: 0 as char,
            line: 1,
            col: 1,
        }
    }

    priv fn id_init(c: char) -> bool {
        match(c) {
            '!' | '$' | '%' | '&' | '*' | '/' | ':' | '<' | '=' | '>' | '?' | '^' | '_' | '~' | 'a' .. 'z' | 'A' .. 'Z' => true,
            _ => false,
        }
    }

    pub impl Parser {
        fn parse(&mut self) -> Result<LDatum, ~str> {
            do result::chain(self.parse_datum()) |v| {
                self.consume_whitespace();

                if(self.eof()) {
                    Ok(v)
                } else {
                    Err(~"trailing input")
                }
            }
        }
    }

    priv impl Parser {
        fn eof(&mut self) -> bool {
            !self.has_buf && self.reader.eof()
        }

        fn consume(&mut self) -> char {
            if(self.has_buf) {
                self.has_buf = false;
            } else {
                self.buf = self.reader.read_char();
            }

            if(self.buf == '\n') {
                self.line += 1;
                self.col = 1;
            } else {
                self.col += 1;
            }

            self.buf
        }

        fn lookahead(&mut self) -> char {
            if(!self.has_buf) {
                self.has_buf = true;
                self.buf = self.reader.read_char();
            }
            self.buf
        }

        fn consume_whitespace(&mut self) {
            while(!self.eof()) {
                match(self.lookahead()) {
                    ' '| '\t' | '\r' | '\n' => { self.consume(); },
                    _ => break
                }
            }
        }

        fn parse_datum(&mut self) -> Result<LDatum, ~str> {
            self.consume_whitespace();

            if(self.eof()) {
                return Err(~"unexpected EOF");
            }

            let c = self.consume();
            match(c) {
                _ if id_init(c) =>
                    Ok(LIdent(self.parse_ident(c))),
                '"' => {
                        match(self.parse_string()) {
                            Ok(s) => Ok(LString(s)),
                            Err(e) => Err(e),
                        }
                    },
                '#' => {
                        self.parse_sharp()
                    },
                _ =>
                    Err(~"unexpected character: " + str::from_char(c)),
            }
        }

        fn parse_sharp(&mut self) -> Result<LDatum, ~str> {
            if(self.eof()) {
                return Err(~"unexpected EOF");
            }

            let c = self.consume();
            match(c) {
                '\\' =>
                    do result::map(&self.parse_char()) |&c| {
                        LChar(c)
                    },
                't' =>
                    Ok(LBool(true)),
                'f' =>
                    Ok(LBool(false)),
                _ =>
                    Err(~"unexpected character: " + str::from_char(c)),
            }
        }

        fn parse_char(&mut self) -> Result<char, ~str> {
            if(self.eof()) {
                return Err(~"unexpected EOF");
            }

            let lit =
            do io::with_str_writer |wr| {
                while(!self.eof()) {
                    match(self.lookahead()) {
                        ' ' | '\t' | '\r' | '\n' => break,
                        _ => wr.write_char(self.consume()),
                    }
                }
            };

            if(lit.len() == 1) {
                Ok(lit.char_at(0))
            } else if(lit == ~"space") {
                Ok(' ')
            } else if(lit == ~"newline") {
                Ok('\n')
            } else {
                Err(~"unknown character literal " + lit)
            }
        }

        fn parse_ident(&mut self, init: char) -> ~str {
            do io::with_str_writer |wr| {
                wr.write_char(init);

                while(!self.eof()) {
                    let c = self.lookahead();

                    match(c) {
                        '0' .. '9' | '+' | '-' | '.' | '@' => wr.write_char(c),
                        _ if id_init(c) => wr.write_char(c),
                        _ => break,
                    }

                    self.consume();
                }
            }
        }

        fn parse_string(&mut self) -> Result<~str, ~str> {
            let mut escape_fail = false;

            let val = do io::with_str_writer |wr| {
                while(!self.eof()) {
                    let c = self.consume();
                    match(c) {
                        '\\' => if self.eof() {
                                    escape_fail = true;
                                } else {
                                    wr.write_char(self.consume());
                                },
                        '"' => break,
                        _ => wr.write_char(c),
                    }
                }
            };

            if(escape_fail) {
                Err(~"unexpected EOF")
            } else {
                Ok(val)
            }
        }
    }

    #[test]
    fn test_parse_ident() {
        let test_src = ~"a3!";

        do io::with_str_reader(test_src) |rdr| {
            let mut parser = Parser(rdr);
            let val = parser.parse();
            assert_eq!(Ok(LIdent(~"a3!")), val);
        }
    }

    #[test]
    fn test_parse_string() {
        let test_src = ~"\"ab\\\"c\"";

        do io::with_str_reader(test_src) |rdr| {
            let mut parser = Parser(rdr);
            let val = parser.parse();
            assert_eq!(Ok(LString(~"ab\"c")), val);
        }
    }

    #[test]
    fn test_parse_char() {
        let test_src = ~"#\\h";

        do io::with_str_reader(test_src) |rdr| {
            let mut parser = Parser(rdr);
            let val = parser.parse();
            assert_eq!(Ok(LChar('h')), val);
        }
    }

    #[test]
    fn test_parse_space() {
        let test_src = ~"#\\space";

        do io::with_str_reader(test_src) |rdr| {
            let mut parser = Parser(rdr);
            let val = parser.parse();
            assert_eq!(Ok(LChar(' ')), val);
        }
    }

    #[test]
    fn test_parse_bool() {
        let test_src = ~"#t";

        do io::with_str_reader(test_src) |rdr| {
            let mut parser = Parser(rdr);
            let val = parser.parse();
            assert_eq!(Ok(LBool(true)), val);
        }
    }
}
<|endoftext|>


<commit_before>#[feature(macro_rules)];

use std::result::{Result,Ok,Err};

#[deriving(Eq,Show)]
enum SmtpCommand<'a> {
  MAIL(&'a str),
  RCPT(&'a str),
  DATA,
}

#[deriving(Eq,Show)]
enum ParseError {
  SyntaxError(&'static str),
  InvalidLineEnding,
  UnknownCommand,
}

fn ascii_eq_ignore_case(a: &[u8], b: &[u8]) -> bool {
  if a.len() == b.len() {
    a.to_ascii().eq_ignore_case(b.to_ascii())
  }
  else {
    false
  }
}

struct SliceReader<'a> {
  data: &'a[u8]
}

impl<'a> SliceReader<'a> {

  fn new(data: &'a[u8]) -> SliceReader<'a> {
      SliceReader { data: data }
  }

  fn len(&self) -> uint { self.data.len() }
  fn is_empty(&self) -> bool { self.len() == 0 }
  fn data(&self) -> &'a[u8] { self.data }

  /// Remove `n` (but no more than len()) items from the back and return them.
  fn pop_back(&mut self, n: uint) -> &'a[u8] {
    if n > self.len() { debug!("pop_back(): n > len"); }
    let n = std::cmp::min(n, self.len());
    let (front, back) = self.split_at(self.len() - n);
    self.data = front;
    return back;
  }

  /// Remove `n` (but no more than len()) items from the front and return them.
  fn pop_front(&mut self, n: uint) -> &'a[u8] {
    if n > self.len() { debug!("pop_front(): n > len"); }
    let n = std::cmp::min(n, self.len());

    let (front, back) = self.split_at(n);
    self.data = back;
    return front;
  }

  fn pop_while(&mut self, cond: |u8| -> bool) -> &'a[u8] {
    let mut cnt = 0;
    for &b in self.data.iter() {
      if cond(b) {
        cnt += 1;
      } else {
        break;
      }
    }
    self.pop_front(cnt)
  }

  fn split_at(&self, pos: uint) -> (&'a[u8], &'a[u8]) {
    assert!(pos <= self.data.len());
    (self.data.slice(0, pos), self.data.slice(pos, self.data.len()))
  }
}

fn parse_command<'a>(line: &'a[u8]) -> Result<SmtpCommand<'a>, ParseError>  {
    let mut line = SliceReader::new(line);

    if line.len() < 2 {
      return Err(InvalidLineEnding);
    }

    let crlf = line.pop_back(2);
    if crlf != bytes!("\r\n") {
      return Err(InvalidLineEnding);
    }

    let cmd = line.pop_front(4);
    if ascii_eq_ignore_case(cmd, bytes!("MAIL")) {
        if line.pop_while(|b| b == (' ' as u8) ).len() == 0 {
            return Err(SyntaxError("Invalid MAIL command: Missing SP"));
        }

        if ascii_eq_ignore_case(line.pop_front(5), bytes!("FROM:")) {
            let addr = line.pop_while(|b| b != (' ' as u8));
            if line.is_empty() {
                // XXX: Verify mail addr
                Ok(MAIL(std::str::from_utf8(addr).unwrap()))
            }
            else {
                Err(SyntaxError("Invalid MAIL command"))
            }
        }
        else {
            Err(SyntaxError("Invalid MAIL command"))
        }
    }
    else if ascii_eq_ignore_case(cmd, bytes!("DATA")) {
      if line.is_empty() {
          Ok(DATA)
      }
      else {
          Err(SyntaxError("Invalid DATA command"))
      }
    }
    else {
      Err(UnknownCommand)
    }
}

macro_rules! assert_match(
    ($given:expr , $pattern:pat) => ({
        let given_val = $given;
        match given_val {
          $pattern => {}
          _ => {
             fail!("assertion failed: `value does not match pattern`");
          }
        }
    })
)

macro_rules! test_parse_command (
  ($str:expr, $pat:pat) => (
    match bytes!($str) {
      cmd => assert_match!(parse_command(cmd), $pat)
    }
  )
)

#[test]
fn test_commands() {
  //test_parse_command!("", Err(InvalidLineEnding));
  test_parse_command!("\r", Err(InvalidLineEnding));
  test_parse_command!("\n", Err(InvalidLineEnding));
  test_parse_command!("\n\r", Err(InvalidLineEnding));
  test_parse_command!("MAIL FROM:<mneumann@ntecs.de>", Err(InvalidLineEnding));
  test_parse_command!("MAIL FROM:<mneumann@ntecs.de>\r", Err(InvalidLineEnding));
  test_parse_command!("MAIL FROM:<mneumann@ntecs.de>\n", Err(InvalidLineEnding));
  test_parse_command!("MAIL FROM:<mneumann@ntecs.de>\n\r", Err(InvalidLineEnding));

  test_parse_command!("MAIL FROM:<mneumann@ntecs.de blah\r\n", Err(SyntaxError("Invalid MAIL command")));

  test_parse_command!("MAIL FROM:<mneumann@ntecs.de>\r\n", Ok(MAIL("<mneumann@ntecs.de>")));

  test_parse_command!("DATA\r\n", Ok(DATA));
  test_parse_command!("data\r\n", Ok(DATA));
  test_parse_command!("data test\r\n", Err(SyntaxError("Invalid DATA command")));
}

fn main() {
  let buf = bytes!("MAIL FROM:<mneumann@ntecs.de>\r\n");
  let cmd = parse_command(buf);
  println!("{}", cmd);
}
<commit_msg>StringReader -> StringScanner. Make generic<commit_after>#[feature(macro_rules)];

use std::result::{Result,Ok,Err};

#[deriving(Eq,Show)]
enum SmtpCommand<'a> {
  MAIL(&'a str),
  RCPT(&'a str),
  DATA,
}

#[deriving(Eq,Show)]
enum ParseError {
  SyntaxError(&'static str),
  InvalidLineEnding,
  UnknownCommand,
}

fn ascii_eq_ignore_case(a: &[u8], b: &[u8]) -> bool {
  if a.len() == b.len() {
    a.to_ascii().eq_ignore_case(b.to_ascii())
  }
  else {
    false
  }
}

struct SliceScanner<'a, T> {
  data: &'a[T]
}

impl<'a, T:Sized+Send> SliceScanner<'a, T> {

  fn new(data: &'a[T]) -> SliceScanner<'a, T> {
      SliceScanner { data: data }
  }

  fn len(&self) -> uint { self.data.len() }
  fn is_empty(&self) -> bool { self.len() == 0 }
  fn data(&self) -> &'a[T] { self.data }

  /// Remove `n` (but no more than len()) items from the back and return them.
  fn pop_back(&mut self, n: uint) -> &'a[T] {
    if n > self.len() { debug!("pop_back(): n > len"); }
    let n = std::cmp::min(n, self.len());
    let (front, back) = self.split_at(self.len() - n);
    self.data = front;
    return back;
  }

  /// Remove `n` (but no more than len()) items from the front and return them.
  fn pop_front(&mut self, n: uint) -> &'a[T] {
    if n > self.len() { debug!("pop_front(): n > len"); }
    let n = std::cmp::min(n, self.len());

    let (front, back) = self.split_at(n);
    self.data = back;
    return front;
  }

  fn count_while(&self, cond: |&T| -> bool) -> uint {
    let mut cnt = 0;
    for b in self.data.iter() {
      if cond(b) {
        cnt += 1;
      } else {
        break;
      }
    }
    return cnt
  }

  fn pop_while(&mut self, cond: |&T| -> bool) -> &'a[T] {
    let cnt = self.count_while(cond);
    self.pop_front(cnt)
  }

  fn split_at(&self, pos: uint) -> (&'a[T], &'a[T]) {
    assert!(pos <= self.data.len());
    (self.data.slice(0, pos), self.data.slice(pos, self.data.len()))
  }
}

fn parse_command<'a>(line: &'a[u8]) -> Result<SmtpCommand<'a>, ParseError>  {
    let mut line = SliceScanner::new(line);

    let crlf = line.pop_back(2);
    if crlf != bytes!("\r\n") {
      return Err(InvalidLineEnding);
    }

    let cmd = line.pop_front(4);
    if ascii_eq_ignore_case(cmd, bytes!("MAIL")) {
        if line.pop_while(|&b| b == (' ' as u8) ).len() == 0 {
            return Err(SyntaxError("Invalid MAIL command: Missing SP"));
        }

        if ascii_eq_ignore_case(line.pop_front(5), bytes!("FROM:")) {
            let addr = line.pop_while(|&b| b != (' ' as u8));
            if line.is_empty() {
                // XXX: Verify mail addr
                Ok(MAIL(std::str::from_utf8(addr).unwrap()))
            }
            else {
                Err(SyntaxError("Invalid MAIL command"))
            }
        }
        else {
            Err(SyntaxError("Invalid MAIL command"))
        }
    }
    else if ascii_eq_ignore_case(cmd, bytes!("DATA")) {
      if line.is_empty() {
          Ok(DATA)
      }
      else {
          Err(SyntaxError("Invalid DATA command"))
      }
    }
    else {
      Err(UnknownCommand)
    }
}

macro_rules! assert_match(
    ($given:expr , $pattern:pat) => ({
        let given_val = $given;
        match given_val {
          $pattern => {}
          _ => {
             fail!("assertion failed: `value does not match pattern`");
          }
        }
    })
)

macro_rules! test_parse_command (
  ($str:expr, $pat:pat) => (
    match bytes!($str) {
      cmd => assert_match!(parse_command(cmd), $pat)
    }
  )
)

#[test]
fn test_commands() {
  //test_parse_command!("", Err(InvalidLineEnding));
  test_parse_command!("\r", Err(InvalidLineEnding));
  test_parse_command!("\n", Err(InvalidLineEnding));
  test_parse_command!("\n\r", Err(InvalidLineEnding));
  test_parse_command!("MAIL FROM:<mneumann@ntecs.de>", Err(InvalidLineEnding));
  test_parse_command!("MAIL FROM:<mneumann@ntecs.de>\r", Err(InvalidLineEnding));
  test_parse_command!("MAIL FROM:<mneumann@ntecs.de>\n", Err(InvalidLineEnding));
  test_parse_command!("MAIL FROM:<mneumann@ntecs.de>\n\r", Err(InvalidLineEnding));

  test_parse_command!("MAIL FROM:<mneumann@ntecs.de blah\r\n", Err(SyntaxError("Invalid MAIL command")));

  test_parse_command!("MAIL FROM:<mneumann@ntecs.de>\r\n", Ok(MAIL("<mneumann@ntecs.de>")));

  test_parse_command!("DATA\r\n", Ok(DATA));
  test_parse_command!("data\r\n", Ok(DATA));
  test_parse_command!("data test\r\n", Err(SyntaxError("Invalid DATA command")));
}

fn main() {
  let buf = bytes!("MAIL FROM:<mneumann@ntecs.de>\r\n");
  let cmd = parse_command(buf);
  println!("{}", cmd);
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::*;
use rand::{Rng, SeedableRng};
use std::{
    io::{self, Write},
    process,
};
use structopt::{clap::arg_enum, StructOpt};
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
// TODO going to remove random seed once cluster deployment supports re-run genesis
use rand::rngs::OsRng;

#[derive(Debug, StructOpt)]
#[structopt(about = "Forged in Fire")]
pub struct Options {
    /// The FILTER string is tested against the name of all tests, and only those tests whose names
    /// contain the filter are run.
    filter: Option<String>,
    #[structopt(long = "exact")]
    /// Exactly match filters rather than by substring
    filter_exact: bool,
    #[structopt(short = "q", long)]
    /// Output minimal information
    quiet: bool,
    #[structopt(long)]
    /// List all tests
    list: bool,
    #[structopt(long)]
    /// List or run ignored tests
    ignored: bool,
    #[structopt(long)]
    /// Include ignored tests when listing or running tests
    include_ignored: bool,
    /// Configure formatting of output:
    ///   pretty = Print verbose output;
    ///   terse = Display one character per test;
    ///   (json is unsupported, exists for compatibility with the default test harness)
    #[structopt(long, possible_values = &Format::variants(), default_value, case_insensitive = true)]
    format: Format,
}

impl Options {
    pub fn from_args() -> Self {
        StructOpt::from_args()
    }
}

arg_enum! {
    #[derive(Debug, Eq, PartialEq)]
    pub enum Format {
        Pretty,
        Terse,
        Json,
    }
}

impl Default for Format {
    fn default() -> Self {
        Format::Pretty
    }
}

pub fn forge_main<F: Factory>(tests: ForgeConfig<'_>, factory: F, options: &Options) -> Result<()> {
    let forge = Forge::new(options, tests, factory);

    if options.list {
        forge.list()?;

        return Ok(());
    }

    match forge.run() {
        Ok(()) => Ok(()),
        Err(_) => process::exit(101), // Exit with a non-zero exit code if tests failed
    }
}

pub struct ForgeConfig<'cfg> {
    pub public_usage_tests: &'cfg [&'cfg dyn PublicUsageTest],
    pub admin_tests: &'cfg [&'cfg dyn AdminTest],
    pub network_tests: &'cfg [&'cfg dyn NetworkTest],
}

impl<'cfg> ForgeConfig<'cfg> {
    pub fn number_of_tests(&self) -> usize {
        self.public_usage_tests.len() + self.admin_tests.len() + self.network_tests.len()
    }

    pub fn all_tests(&self) -> impl Iterator<Item = &'cfg dyn Test> + 'cfg {
        self.public_usage_tests
            .iter()
            .map(|t| t as &dyn Test)
            .chain(self.admin_tests.iter().map(|t| t as &dyn Test))
            .chain(self.network_tests.iter().map(|t| t as &dyn Test))
    }
}

pub struct Forge<'cfg, F> {
    options: &'cfg Options,
    tests: ForgeConfig<'cfg>,
    factory: F,
}

impl<'cfg, F: Factory> Forge<'cfg, F> {
    pub fn new(options: &'cfg Options, tests: ForgeConfig<'cfg>, factory: F) -> Self {
        Self {
            options,
            tests,
            factory,
        }
    }

    pub fn list(&self) -> Result<()> {
        for test in self.tests.all_tests() {
            println!("{}: test", test.name());
        }

        if self.options.format == Format::Pretty {
            println!();
            println!("{} tests", self.tests.all_tests().count());
        }

        Ok(())
    }

    pub fn run(&self) -> Result<()> {
        let mut summary = TestSummary::new(self.filter_tests(self.tests.all_tests()).count(), 0);
        summary.write_starting_msg()?;

        let mut rng = ::rand::rngs::StdRng::from_seed(OsRng.gen());
        let mut swarm = self.factory.launch_swarm(1);

        // Run PublicUsageTests
        for test in self.filter_tests(self.tests.public_usage_tests.iter()) {
            let mut public_ctx = PublicUsageContext::new(
                CoreContext::from_rng(&mut rng),
                swarm.chain_info().into_public_info(),
            );
            let result = run_test(|| test.run(&mut public_ctx));
            summary.handle_result(test.name().to_owned(), result)?;
        }

        // Run AdminTests
        for test in self.filter_tests(self.tests.admin_tests.iter()) {
            let mut admin_ctx =
                AdminContext::new(CoreContext::from_rng(&mut rng), swarm.chain_info());
            let result = run_test(|| test.run(&mut admin_ctx));
            summary.handle_result(test.name().to_owned(), result)?;
        }

        for test in self.filter_tests(self.tests.network_tests.iter()) {
            let report = TestReport::new();
            let mut network_ctx =
                NetworkContext::new(CoreContext::from_rng(&mut rng), &mut *swarm, report);
            let result = run_test(|| test.run(&mut network_ctx));
            summary.handle_result(test.name().to_owned(), result)?;
        }

        summary.write_summary()?;

        if summary.success() {
            Ok(())
        } else {
            Err(anyhow::anyhow!("Tests Failed"))
        }
    }

    fn filter_tests<'a, T: Test, I: Iterator<Item = T> + 'a>(
        &'a self,
        tests: I,
    ) -> impl Iterator<Item = T> + 'a {
        tests.filter(move |test| {
            if let Some(filter) = &self.options.filter {
                if self.options.filter_exact {
                    test.name() == &filter[..]
                } else {
                    test.name().contains(&filter[..])
                }
            } else {
                true
            }
        })
    }
}

enum TestResult {
    Ok,
    Failed,
    FailedWithMsg(String),
}

fn run_test<F: FnOnce() -> Result<()>>(f: F) -> TestResult {
    match ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(f)) {
        Ok(Ok(())) => TestResult::Ok,
        Ok(Err(e)) => TestResult::FailedWithMsg(format!("{:?}", e)),
        Err(_) => TestResult::Failed,
    }
}

struct TestSummary {
    stdout: StandardStream,
    total: usize,
    filtered_out: usize,
    passed: usize,
    failed: Vec<String>,
}

impl TestSummary {
    fn new(total: usize, filtered_out: usize) -> Self {
        Self {
            stdout: StandardStream::stdout(ColorChoice::Auto),
            total,
            filtered_out,
            passed: 0,
            failed: Vec::new(),
        }
    }

    fn handle_result(&mut self, name: String, result: TestResult) -> io::Result<()> {
        write!(self.stdout, "test {} ... ", name)?;
        match result {
            TestResult::Ok => {
                self.passed += 1;
                self.write_ok()?;
            }
            TestResult::Failed => {
                self.failed.push(name);
                self.write_failed()?;
            }
            TestResult::FailedWithMsg(msg) => {
                self.failed.push(name);
                self.write_failed()?;
                writeln!(self.stdout)?;

                write!(self.stdout, "Error: {}", msg)?;
            }
        }
        writeln!(self.stdout)?;
        Ok(())
    }

    fn write_ok(&mut self) -> io::Result<()> {
        self.stdout
            .set_color(ColorSpec::new().set_fg(Some(Color::Green)))?;
        write!(self.stdout, "ok")?;
        self.stdout.reset()?;
        Ok(())
    }

    fn write_failed(&mut self) -> io::Result<()> {
        self.stdout
            .set_color(ColorSpec::new().set_fg(Some(Color::Red)))?;
        write!(self.stdout, "FAILED")?;
        self.stdout.reset()?;
        Ok(())
    }

    fn write_starting_msg(&mut self) -> io::Result<()> {
        writeln!(self.stdout)?;
        writeln!(
            self.stdout,
            "running {} tests",
            self.total - self.filtered_out
        )?;
        Ok(())
    }

    fn write_summary(&mut self) -> io::Result<()> {
        // Print out the failing tests
        if !self.failed.is_empty() {
            writeln!(self.stdout)?;
            writeln!(self.stdout, "failures:")?;
            for name in &self.failed {
                writeln!(self.stdout, "    {}", name)?;
            }
        }

        writeln!(self.stdout)?;
        write!(self.stdout, "test result: ")?;
        if self.failed.is_empty() {
            self.write_ok()?;
        } else {
            self.write_failed()?;
        }
        writeln!(
            self.stdout,
            ". {} passed; {} failed; {} filtered out",
            self.passed,
            self.failed.len(),
            self.filtered_out
        )?;
        writeln!(self.stdout)?;
        Ok(())
    }

    fn success(&self) -> bool {
        self.failed.is_empty()
    }
}
<commit_msg>forge: filter tests before listing<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::*;
use rand::{Rng, SeedableRng};
use std::{
    io::{self, Write},
    process,
};
use structopt::{clap::arg_enum, StructOpt};
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
// TODO going to remove random seed once cluster deployment supports re-run genesis
use rand::rngs::OsRng;

#[derive(Debug, StructOpt)]
#[structopt(about = "Forged in Fire")]
pub struct Options {
    /// The FILTER string is tested against the name of all tests, and only those tests whose names
    /// contain the filter are run.
    filter: Option<String>,
    #[structopt(long = "exact")]
    /// Exactly match filters rather than by substring
    filter_exact: bool,
    #[structopt(short = "q", long)]
    /// Output minimal information
    quiet: bool,
    #[structopt(long)]
    /// List all tests
    list: bool,
    #[structopt(long)]
    /// List or run ignored tests
    ignored: bool,
    #[structopt(long)]
    /// Include ignored tests when listing or running tests
    include_ignored: bool,
    /// Configure formatting of output:
    ///   pretty = Print verbose output;
    ///   terse = Display one character per test;
    ///   (json is unsupported, exists for compatibility with the default test harness)
    #[structopt(long, possible_values = &Format::variants(), default_value, case_insensitive = true)]
    format: Format,
}

impl Options {
    pub fn from_args() -> Self {
        StructOpt::from_args()
    }
}

arg_enum! {
    #[derive(Debug, Eq, PartialEq)]
    pub enum Format {
        Pretty,
        Terse,
        Json,
    }
}

impl Default for Format {
    fn default() -> Self {
        Format::Pretty
    }
}

pub fn forge_main<F: Factory>(tests: ForgeConfig<'_>, factory: F, options: &Options) -> Result<()> {
    let forge = Forge::new(options, tests, factory);

    if options.list {
        forge.list()?;

        return Ok(());
    }

    match forge.run() {
        Ok(()) => Ok(()),
        Err(_) => process::exit(101), // Exit with a non-zero exit code if tests failed
    }
}

pub struct ForgeConfig<'cfg> {
    pub public_usage_tests: &'cfg [&'cfg dyn PublicUsageTest],
    pub admin_tests: &'cfg [&'cfg dyn AdminTest],
    pub network_tests: &'cfg [&'cfg dyn NetworkTest],
}

impl<'cfg> ForgeConfig<'cfg> {
    pub fn number_of_tests(&self) -> usize {
        self.public_usage_tests.len() + self.admin_tests.len() + self.network_tests.len()
    }

    pub fn all_tests(&self) -> impl Iterator<Item = &'cfg dyn Test> + 'cfg {
        self.public_usage_tests
            .iter()
            .map(|t| t as &dyn Test)
            .chain(self.admin_tests.iter().map(|t| t as &dyn Test))
            .chain(self.network_tests.iter().map(|t| t as &dyn Test))
    }
}

pub struct Forge<'cfg, F> {
    options: &'cfg Options,
    tests: ForgeConfig<'cfg>,
    factory: F,
}

impl<'cfg, F: Factory> Forge<'cfg, F> {
    pub fn new(options: &'cfg Options, tests: ForgeConfig<'cfg>, factory: F) -> Self {
        Self {
            options,
            tests,
            factory,
        }
    }

    pub fn list(&self) -> Result<()> {
        for test in self.filter_tests(self.tests.all_tests()) {
            println!("{}: test", test.name());
        }

        if self.options.format == Format::Pretty {
            println!();
            println!(
                "{} tests",
                self.filter_tests(self.tests.all_tests()).count()
            );
        }

        Ok(())
    }

    pub fn run(&self) -> Result<()> {
        let mut summary = TestSummary::new(self.filter_tests(self.tests.all_tests()).count(), 0);
        summary.write_starting_msg()?;

        let mut rng = ::rand::rngs::StdRng::from_seed(OsRng.gen());
        let mut swarm = self.factory.launch_swarm(1);

        // Run PublicUsageTests
        for test in self.filter_tests(self.tests.public_usage_tests.iter()) {
            let mut public_ctx = PublicUsageContext::new(
                CoreContext::from_rng(&mut rng),
                swarm.chain_info().into_public_info(),
            );
            let result = run_test(|| test.run(&mut public_ctx));
            summary.handle_result(test.name().to_owned(), result)?;
        }

        // Run AdminTests
        for test in self.filter_tests(self.tests.admin_tests.iter()) {
            let mut admin_ctx =
                AdminContext::new(CoreContext::from_rng(&mut rng), swarm.chain_info());
            let result = run_test(|| test.run(&mut admin_ctx));
            summary.handle_result(test.name().to_owned(), result)?;
        }

        for test in self.filter_tests(self.tests.network_tests.iter()) {
            let report = TestReport::new();
            let mut network_ctx =
                NetworkContext::new(CoreContext::from_rng(&mut rng), &mut *swarm, report);
            let result = run_test(|| test.run(&mut network_ctx));
            summary.handle_result(test.name().to_owned(), result)?;
        }

        summary.write_summary()?;

        if summary.success() {
            Ok(())
        } else {
            Err(anyhow::anyhow!("Tests Failed"))
        }
    }

    fn filter_tests<'a, T: Test, I: Iterator<Item = T> + 'a>(
        &'a self,
        tests: I,
    ) -> impl Iterator<Item = T> + 'a {
        tests.filter(move |test| {
            if let Some(filter) = &self.options.filter {
                if self.options.filter_exact {
                    test.name() == &filter[..]
                } else {
                    test.name().contains(&filter[..])
                }
            } else {
                true
            }
        })
    }
}

enum TestResult {
    Ok,
    Failed,
    FailedWithMsg(String),
}

fn run_test<F: FnOnce() -> Result<()>>(f: F) -> TestResult {
    match ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(f)) {
        Ok(Ok(())) => TestResult::Ok,
        Ok(Err(e)) => TestResult::FailedWithMsg(format!("{:?}", e)),
        Err(_) => TestResult::Failed,
    }
}

struct TestSummary {
    stdout: StandardStream,
    total: usize,
    filtered_out: usize,
    passed: usize,
    failed: Vec<String>,
}

impl TestSummary {
    fn new(total: usize, filtered_out: usize) -> Self {
        Self {
            stdout: StandardStream::stdout(ColorChoice::Auto),
            total,
            filtered_out,
            passed: 0,
            failed: Vec::new(),
        }
    }

    fn handle_result(&mut self, name: String, result: TestResult) -> io::Result<()> {
        write!(self.stdout, "test {} ... ", name)?;
        match result {
            TestResult::Ok => {
                self.passed += 1;
                self.write_ok()?;
            }
            TestResult::Failed => {
                self.failed.push(name);
                self.write_failed()?;
            }
            TestResult::FailedWithMsg(msg) => {
                self.failed.push(name);
                self.write_failed()?;
                writeln!(self.stdout)?;

                write!(self.stdout, "Error: {}", msg)?;
            }
        }
        writeln!(self.stdout)?;
        Ok(())
    }

    fn write_ok(&mut self) -> io::Result<()> {
        self.stdout
            .set_color(ColorSpec::new().set_fg(Some(Color::Green)))?;
        write!(self.stdout, "ok")?;
        self.stdout.reset()?;
        Ok(())
    }

    fn write_failed(&mut self) -> io::Result<()> {
        self.stdout
            .set_color(ColorSpec::new().set_fg(Some(Color::Red)))?;
        write!(self.stdout, "FAILED")?;
        self.stdout.reset()?;
        Ok(())
    }

    fn write_starting_msg(&mut self) -> io::Result<()> {
        writeln!(self.stdout)?;
        writeln!(
            self.stdout,
            "running {} tests",
            self.total - self.filtered_out
        )?;
        Ok(())
    }

    fn write_summary(&mut self) -> io::Result<()> {
        // Print out the failing tests
        if !self.failed.is_empty() {
            writeln!(self.stdout)?;
            writeln!(self.stdout, "failures:")?;
            for name in &self.failed {
                writeln!(self.stdout, "    {}", name)?;
            }
        }

        writeln!(self.stdout)?;
        write!(self.stdout, "test result: ")?;
        if self.failed.is_empty() {
            self.write_ok()?;
        } else {
            self.write_failed()?;
        }
        writeln!(
            self.stdout,
            ". {} passed; {} failed; {} filtered out",
            self.passed,
            self.failed.len(),
            self.filtered_out
        )?;
        writeln!(self.stdout)?;
        Ok(())
    }

    fn success(&self) -> bool {
        self.failed.is_empty()
    }
}
<|endoftext|>


<commit_before>#![cfg(feature = "sync")]
extern crate dotenv;
extern crate screeps_api;

use screeps_api::error::{ApiError, ErrorKind};
use screeps_api::SyncApi;

#[test]
fn test_login_failure() {
    let mut api = SyncApi::new().unwrap();

    match api.login("username", "password") {
        Err(err) => match *err.kind() {
            ErrorKind::Unauthorized => (),
            _ => panic!("expected unauthorized error, found other error {}", err),
        },
        Ok(()) => panic!("expected unauthorized error, found success"),
    }
}

#[test]
fn test_room_terrain() {
    let mut api = SyncApi::new().unwrap();

    api.room_terrain(Some("shard0"), "W0N0").unwrap();
    api.room_terrain(Some("shard0"), "W3N9").unwrap();
}

#[test]
fn test_shard_list() {
    let mut api = SyncApi::new().unwrap();

    let list = api.shard_list().unwrap();
    assert!(list.len() >= 2);
}

#[test]
fn test_room_terrain_invalid_room() {
    let mut api = SyncApi::new().unwrap();

    match api.room_terrain(Some("shard0"), "asdffdsa") {
        Err(err) => match *err.kind() {
            ErrorKind::Api(ApiError::InvalidRoom) => (),
            _ => panic!("expected invalid room api error, found {}", err),
        },
        Ok(_) => panic!("expected invalid room api error, found successful result."),
    };
}

#[test]
fn test_room_terrain_invalid_shard() {
    let mut api = SyncApi::new().unwrap();

    match api.room_terrain(Some("sharasdfd0"), "asdffdsa") {
        Err(err) => match *err.kind() {
            ErrorKind::Api(ApiError::InvalidShard) => (),
            _ => panic!("expected invalid shard api error, found {}", err),
        },
        Ok(_) => panic!("expected invalid room api error, found successful result."),
    };
}

#[test]
fn test_recent_pvp() {
    let mut api = SyncApi::new().unwrap();

    let pvp_results_a = api.recent_pvp(screeps_api::RecentPvpDetails::within(15))
        .unwrap();

    let reported_up_to = pvp_results_a
        .shards
        .iter()
        .map(|&(_, ref data)| data.reported_up_to)
        .max()
        .unwrap();

    let _ = api.recent_pvp(screeps_api::RecentPvpDetails::since(reported_up_to - 10))
        .unwrap();
}
<commit_msg>Remove login failure test as we no longe rhave the ability to login via username/password.<commit_after>#![cfg(feature = "sync")]
extern crate dotenv;
extern crate screeps_api;

use screeps_api::error::{ApiError, ErrorKind};
use screeps_api::SyncApi;

#[test]
fn test_room_terrain() {
    let mut api = SyncApi::new().unwrap();

    api.room_terrain(Some("shard0"), "W0N0").unwrap();
    api.room_terrain(Some("shard0"), "W3N9").unwrap();
}

#[test]
fn test_shard_list() {
    let mut api = SyncApi::new().unwrap();

    let list = api.shard_list().unwrap();
    assert!(list.len() >= 2);
}

#[test]
fn test_room_terrain_invalid_room() {
    let mut api = SyncApi::new().unwrap();

    match api.room_terrain(Some("shard0"), "asdffdsa") {
        Err(err) => match *err.kind() {
            ErrorKind::Api(ApiError::InvalidRoom) => (),
            _ => panic!("expected invalid room api error, found {}", err),
        },
        Ok(_) => panic!("expected invalid room api error, found successful result."),
    };
}

#[test]
fn test_room_terrain_invalid_shard() {
    let mut api = SyncApi::new().unwrap();

    match api.room_terrain(Some("sharasdfd0"), "asdffdsa") {
        Err(err) => match *err.kind() {
            ErrorKind::Api(ApiError::InvalidShard) => (),
            _ => panic!("expected invalid shard api error, found {}", err),
        },
        Ok(_) => panic!("expected invalid room api error, found successful result."),
    };
}

#[test]
fn test_recent_pvp() {
    let mut api = SyncApi::new().unwrap();

    let pvp_results_a = api.recent_pvp(screeps_api::RecentPvpDetails::within(15))
        .unwrap();

    let reported_up_to = pvp_results_a
        .shards
        .iter()
        .map(|&(_, ref data)| data.reported_up_to)
        .max()
        .unwrap();

    let _ = api.recent_pvp(screeps_api::RecentPvpDetails::since(reported_up_to - 10))
        .unwrap();
}
<|endoftext|>


<commit_before>use std::rc::Rc;

use xcb;
use cairo::{self, XCBSurface};
use cairo_sys;

use text::Text;

fn get_root_visual_type(conn: &xcb::Connection, screen: &xcb::Screen) -> xcb::Visualtype {
    for root in conn.get_setup().roots() {
        for allowed_depth in root.allowed_depths() {
            for visual in allowed_depth.visuals() {
                if visual.visual_id() == screen.root_visual() {
                    return visual;
                }
            }
        }
    }
    panic!("No visual type found");
}

// TODO: impl Drop?
pub struct Window {
    conn: Rc<xcb::Connection>,
    screen_idx: usize,
    id: u32,
    surface: cairo::Surface,
}

impl Window {
    pub fn new(conn: Rc<xcb::Connection>, screen_idx: usize) -> Window {
        let id = conn.generate_id();

        let surface = {
            let screen = conn.get_setup()
                .roots()
                .nth(screen_idx)
                .expect("invalid screen");
            let values = [(xcb::CW_BACK_PIXEL, screen.black_pixel()),
                          (xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE)];

            let (width, height) = (screen.width_in_pixels(), 100);

            xcb::create_window(&conn,
                               xcb::COPY_FROM_PARENT as u8,
                               id,
                               screen.root(),
                               0,
                               0,
                               width,
                               height,
                               10,
                               xcb::WINDOW_CLASS_INPUT_OUTPUT as u16,
                               screen.root_visual(),
                               &values);

            let surface = unsafe {
                let cairo_conn = cairo::XCBConnection::from_raw_none(conn.get_raw_conn() as
                                                                     *mut cairo_sys::xcb_connection_t);
                let visual =
                    cairo::XCBVisualType::from_raw_none(&mut get_root_visual_type(&conn, &screen).base as
                                                        *mut xcb::ffi::xcb_visualtype_t as
                                                        *mut cairo_sys::xcb_visualtype_t);
                let drawable = cairo::XCBDrawable(id);
                cairo::Surface::create(&cairo_conn, &drawable, &visual, width as i32, height as i32)
                // TODO: Update surface width/height when window size changes.
            };

            surface
        };

        xcb::map_window(&conn, id);
        conn.flush();

        Window {
            conn,
            screen_idx,
            id,
            surface,
        }
    }

    fn screen<'a>(&'a self) -> xcb::Screen<'a> {
        self.conn
            .get_setup()
            .roots()
            .nth(self.screen_idx)
            .expect("Invalid screen")
    }

    pub fn expose(&self, texts: Vec<Text>) {
        self.render_text_blocks(texts);
        self.conn.flush();
    }

    fn render_text_blocks(&self, texts: Vec<Text>) {
        // Layout each block of text. After this, we can query the width of each
        // block, which will allow us to do more complex layout below.
        let mut layouts: Vec<_> = texts.into_iter().map(|t| t.layout(&self.surface)).collect();

        // Calculate how much free space we have after laying out all the
        // non-stretch blocks. Split the remaining space (if any) between the
        // stretch blocks. If there isn't enough space for the non-stretch blocks
        // do nothing and allow it to overflow.
        {
            let mut width = 0.0;
            let mut stretched = Vec::new();
            for layout in layouts.iter_mut() {
                if !layout.stretch() {
                    width += layout.width();
                } else {
                    stretched.push(layout);
                }
            }

            let remaining_width = self.screen().width_in_pixels() as f64 - width;
            let remaining_width = if remaining_width < 0.0 {
                0.0
            } else {
                remaining_width
            };
            let width_per_stretched = remaining_width / (stretched.len() as f64);
            for layout in stretched.iter_mut() {
                layout.set_width(width_per_stretched);
            }
        }

        // TODO: Set the height of the window and the height of each text block(?)
        // to the height of the largest bit of text.

        // Finally, just render each block of text in turn.
        let mut x = 0.0;
        for layout in &layouts {
            layout.render(x, 0.0);
            x += layout.width();
        }
    }
}
<commit_msg>Don't save window.id, as we won't use it.<commit_after>use std::rc::Rc;

use xcb;
use cairo::{self, XCBSurface};
use cairo_sys;

use text::Text;

fn get_root_visual_type(conn: &xcb::Connection, screen: &xcb::Screen) -> xcb::Visualtype {
    for root in conn.get_setup().roots() {
        for allowed_depth in root.allowed_depths() {
            for visual in allowed_depth.visuals() {
                if visual.visual_id() == screen.root_visual() {
                    return visual;
                }
            }
        }
    }
    panic!("No visual type found");
}

// TODO: impl Drop?
pub struct Window {
    conn: Rc<xcb::Connection>,
    screen_idx: usize,
    surface: cairo::Surface,
}

impl Window {
    pub fn new(conn: Rc<xcb::Connection>, screen_idx: usize) -> Window {
        let id = conn.generate_id();

        let surface = {
            let screen = conn.get_setup()
                .roots()
                .nth(screen_idx)
                .expect("invalid screen");
            let values = [(xcb::CW_BACK_PIXEL, screen.black_pixel()),
                          (xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE)];

            let (width, height) = (screen.width_in_pixels(), 100);

            xcb::create_window(&conn,
                               xcb::COPY_FROM_PARENT as u8,
                               id,
                               screen.root(),
                               0,
                               0,
                               width,
                               height,
                               10,
                               xcb::WINDOW_CLASS_INPUT_OUTPUT as u16,
                               screen.root_visual(),
                               &values);

            let surface = unsafe {
                let cairo_conn = cairo::XCBConnection::from_raw_none(conn.get_raw_conn() as
                                                                     *mut cairo_sys::xcb_connection_t);
                let visual =
                    cairo::XCBVisualType::from_raw_none(&mut get_root_visual_type(&conn, &screen).base as
                                                        *mut xcb::ffi::xcb_visualtype_t as
                                                        *mut cairo_sys::xcb_visualtype_t);
                let drawable = cairo::XCBDrawable(id);
                cairo::Surface::create(&cairo_conn, &drawable, &visual, width as i32, height as i32)
                // TODO: Update surface width/height when window size changes.
            };

            surface
        };

        xcb::map_window(&conn, id);
        conn.flush();

        Window {
            conn,
            screen_idx,
            surface,
        }
    }

    fn screen<'a>(&'a self) -> xcb::Screen<'a> {
        self.conn
            .get_setup()
            .roots()
            .nth(self.screen_idx)
            .expect("Invalid screen")
    }

    pub fn expose(&self, texts: Vec<Text>) {
        self.render_text_blocks(texts);
        self.conn.flush();
    }

    fn render_text_blocks(&self, texts: Vec<Text>) {
        // Layout each block of text. After this, we can query the width of each
        // block, which will allow us to do more complex layout below.
        let mut layouts: Vec<_> = texts.into_iter().map(|t| t.layout(&self.surface)).collect();

        // Calculate how much free space we have after laying out all the
        // non-stretch blocks. Split the remaining space (if any) between the
        // stretch blocks. If there isn't enough space for the non-stretch blocks
        // do nothing and allow it to overflow.
        {
            let mut width = 0.0;
            let mut stretched = Vec::new();
            for layout in layouts.iter_mut() {
                if !layout.stretch() {
                    width += layout.width();
                } else {
                    stretched.push(layout);
                }
            }

            let remaining_width = self.screen().width_in_pixels() as f64 - width;
            let remaining_width = if remaining_width < 0.0 {
                0.0
            } else {
                remaining_width
            };
            let width_per_stretched = remaining_width / (stretched.len() as f64);
            for layout in stretched.iter_mut() {
                layout.set_width(width_per_stretched);
            }
        }

        // TODO: Set the height of the window and the height of each text block(?)
        // to the height of the largest bit of text.

        // Finally, just render each block of text in turn.
        let mut x = 0.0;
        for layout in &layouts {
            layout.render(x, 0.0);
            x += layout.width();
        }
    }
}
<|endoftext|>


<commit_before>//! Lexer analyzes raw input string and produces lexemes (tokens).
//! It is just a bridge to `rustc_lexer`.

use crate::{
    SyntaxError, SyntaxErrorKind,
    SyntaxKind::{self, *},
    TextRange, TextUnit,
};

/// A token of Rust source.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Token {
    /// The kind of token.
    pub kind: SyntaxKind,
    /// The length of the token.
    pub len: TextUnit,
}

/// Represents the result of parsing one token. Beware that the token may be malformed.
#[derive(Debug)]
pub struct ParsedToken {
    /// Parsed token.
    pub token: Token,
    /// If error is present then parsed token is malformed.
    pub error: Option<SyntaxError>,
}

#[derive(Debug, Default)]
/// Represents the result of parsing source code of Rust language.
pub struct ParsedTokens {
    /// Parsed tokens in order they appear in source code.
    pub tokens: Vec<Token>,
    /// Collection of all occured tokenization errors.
    /// In general `self.errors.len() <= self.tokens.len()`
    pub errors: Vec<SyntaxError>,
}
impl ParsedTokens {
    /// Append `token` and `error` (if pressent) to the result.
    pub fn push(&mut self, ParsedToken { token, error }: ParsedToken) {
        self.tokens.push(token);
        if let Some(error) = error {
            self.errors.push(error)
        }
    }
}

/// Same as `tokenize_append()`, just a shortcut for creating `ParsedTokens`
/// and returning the result the usual way.
pub fn tokenize(text: &str) -> ParsedTokens {
    let mut parsed = ParsedTokens::default();
    tokenize_append(text, &mut parsed);
    parsed
}

/// Break a string up into its component tokens.
/// Writes to `ParsedTokens` which are basically a pair `(Vec<Token>, Vec<SyntaxError>)`.
/// Beware that it checks for shebang first and its length contributes to resulting
/// tokens offsets.
pub fn tokenize_append(text: &str, parsed: &mut ParsedTokens) {
    // non-empty string is a precondtion of `rustc_lexer::strip_shebang()`.
    if text.is_empty() {
        return;
    }

    let mut offset: usize = rustc_lexer::strip_shebang(text)
        .map(|shebang_len| {
            parsed.tokens.push(Token { kind: SHEBANG, len: TextUnit::from_usize(shebang_len) });
            shebang_len
        })
        .unwrap_or(0);

    let text_without_shebang = &text[offset..];

    for rustc_token in rustc_lexer::tokenize(text_without_shebang) {
        parsed.push(rustc_token_to_parsed_token(&rustc_token, text, TextUnit::from_usize(offset)));
        offset += rustc_token.len;
    }
}

/// Returns the first encountered token at the beginning of the string.
/// If the string contains zero or *two or more tokens* returns `None`.
///
/// The main difference between `first_token()` and `single_token()` is that
/// the latter returns `None` if the string contains more than one token.
pub fn single_token(text: &str) -> Option<ParsedToken> {
    first_token(text).filter(|parsed| parsed.token.len.to_usize() == text.len())
}

/// Returns the first encountered token at the beginning of the string.
/// If the string contains zero tokens returns `None`.
///
/// The main difference between `first_token() and single_token()` is that
/// the latter returns `None` if the string contains more than one token.
pub fn first_token(text: &str) -> Option<ParsedToken> {
    // non-empty string is a precondtion of `rustc_lexer::first_token()`.
    if text.is_empty() {
        None
    } else {
        let rustc_token = rustc_lexer::first_token(text);
        Some(rustc_token_to_parsed_token(&rustc_token, text, TextUnit::from(0)))
    }
}

/// Describes the values of `SyntaxErrorKind::TokenizeError` enum variant.
/// It describes all the types of errors that may happen during the tokenization
/// of Rust source.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum TokenizeError {
    /// Base prefix was provided, but there were no digits
    /// after it, e.g. `0x`.
    EmptyInt,
    /// Float exponent lacks digits e.g. `e+`, `E+`, `e-`, `E-`,
    EmptyExponent,

    /// Block comment lacks trailing delimiter `*/`
    UnterminatedBlockComment,
    /// Character literal lacks trailing delimiter `'`
    UnterminatedChar,
    /// Characterish byte literal lacks trailing delimiter `'`
    UnterminatedByte,
    /// String literal lacks trailing delimiter `"`
    UnterminatedString,
    /// Byte string literal lacks trailing delimiter `"`
    UnterminatedByteString,
    /// Raw literal lacks trailing delimiter e.g. `"##`
    UnterminatedRawString,
    /// Raw byte string literal lacks trailing delimiter e.g. `"##`
    UnterminatedRawByteString,

    /// Raw string lacks a quote after the pound characters e.g. `r###`
    UnstartedRawString,
    /// Raw byte string lacks a quote after the pound characters e.g. `br###`
    UnstartedRawByteString,

    /// Lifetime starts with a number e.g. `'4ever`
    LifetimeStartsWithNumber,
}

/// Mapper function that converts `rustc_lexer::Token` with some additional context
/// to `ParsedToken`
fn rustc_token_to_parsed_token(
    rustc_token: &rustc_lexer::Token,
    text: &str,
    token_start_offset: TextUnit,
) -> ParsedToken {
    // We drop some useful infromation here (see patterns with double dots `..`)
    // Storing that info in `SyntaxKind` is not possible due to its layout requirements of
    // being `u16` that come from `rowan::SyntaxKind` type and changes to `rowan::SyntaxKind`
    // would mean hell of a rewrite

    let token_range =
        TextRange::offset_len(token_start_offset, TextUnit::from_usize(rustc_token.len));

    let token_text = &text[token_range];

    let (syntax_kind, error) = {
        use rustc_lexer::TokenKind as TK;
        use TokenizeError as TE;

        match rustc_token.kind {
            TK::LineComment => ok(COMMENT),
            TK::BlockComment { terminated } => {
                ok_if(terminated, COMMENT, TE::UnterminatedBlockComment)
            }
            TK::Whitespace => ok(WHITESPACE),
            TK::Ident => ok(if token_text == "_" {
                UNDERSCORE
            } else {
                SyntaxKind::from_keyword(token_text).unwrap_or(IDENT)
            }),
            TK::RawIdent => ok(IDENT),
            TK::Literal { kind, .. } => match_literal_kind(&kind),
            TK::Lifetime { starts_with_number } => {
                ok_if(!starts_with_number, LIFETIME, TE::LifetimeStartsWithNumber)
            }
            TK::Semi => ok(SEMI),
            TK::Comma => ok(COMMA),
            TK::Dot => ok(DOT),
            TK::OpenParen => ok(L_PAREN),
            TK::CloseParen => ok(R_PAREN),
            TK::OpenBrace => ok(L_CURLY),
            TK::CloseBrace => ok(R_CURLY),
            TK::OpenBracket => ok(L_BRACK),
            TK::CloseBracket => ok(R_BRACK),
            TK::At => ok(AT),
            TK::Pound => ok(POUND),
            TK::Tilde => ok(TILDE),
            TK::Question => ok(QUESTION),
            TK::Colon => ok(COLON),
            TK::Dollar => ok(DOLLAR),
            TK::Eq => ok(EQ),
            TK::Not => ok(EXCL),
            TK::Lt => ok(L_ANGLE),
            TK::Gt => ok(R_ANGLE),
            TK::Minus => ok(MINUS),
            TK::And => ok(AMP),
            TK::Or => ok(PIPE),
            TK::Plus => ok(PLUS),
            TK::Star => ok(STAR),
            TK::Slash => ok(SLASH),
            TK::Caret => ok(CARET),
            TK::Percent => ok(PERCENT),
            TK::Unknown => ok(ERROR),
        }
    };

    return ParsedToken {
        token: Token { kind: syntax_kind, len: token_range.len() },
        error: error
            .map(|error| SyntaxError::new(SyntaxErrorKind::TokenizeError(error), token_range)),
    };

    type ParsedSyntaxKind = (SyntaxKind, Option<TokenizeError>);

    fn match_literal_kind(kind: &rustc_lexer::LiteralKind) -> ParsedSyntaxKind {
        use rustc_lexer::LiteralKind as LK;
        use TokenizeError as TE;

        match *kind {
            LK::Int { empty_int, .. } => ok_if(!empty_int, INT_NUMBER, TE::EmptyInt),
            LK::Float { empty_exponent, .. } => {
                ok_if(!empty_exponent, FLOAT_NUMBER, TE::EmptyExponent)
            }
            LK::Char { terminated } => ok_if(terminated, CHAR, TE::UnterminatedChar),
            LK::Byte { terminated } => ok_if(terminated, BYTE, TE::UnterminatedByte),
            LK::Str { terminated } => ok_if(terminated, STRING, TE::UnterminatedString),
            LK::ByteStr { terminated } => {
                ok_if(terminated, BYTE_STRING, TE::UnterminatedByteString)
            }

            LK::RawStr { started: true, terminated, .. } => {
                ok_if(terminated, RAW_STRING, TE::UnterminatedRawString)
            }
            LK::RawStr { started: false, .. } => err(RAW_STRING, TE::UnstartedRawString),

            LK::RawByteStr { started: true, terminated, .. } => {
                ok_if(terminated, RAW_BYTE_STRING, TE::UnterminatedRawByteString)
            }
            LK::RawByteStr { started: false, .. } => {
                err(RAW_BYTE_STRING, TE::UnstartedRawByteString)
            }
        }
    }
    const fn ok(syntax_kind: SyntaxKind) -> ParsedSyntaxKind {
        (syntax_kind, None)
    }
    const fn err(syntax_kind: SyntaxKind, error: TokenizeError) -> ParsedSyntaxKind {
        (syntax_kind, Some(error))
    }
    fn ok_if(cond: bool, syntax_kind: SyntaxKind, error: TokenizeError) -> ParsedSyntaxKind {
        if cond {
            ok(syntax_kind)
        } else {
            err(syntax_kind, error)
        }
    }
}
<commit_msg>add better docs for tokenize errors<commit_after>//! Lexer analyzes raw input string and produces lexemes (tokens).
//! It is just a bridge to `rustc_lexer`.

use crate::{
    SyntaxError, SyntaxErrorKind,
    SyntaxKind::{self, *},
    TextRange, TextUnit,
};

/// A token of Rust source.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Token {
    /// The kind of token.
    pub kind: SyntaxKind,
    /// The length of the token.
    pub len: TextUnit,
}

/// Represents the result of parsing one token. Beware that the token may be malformed.
#[derive(Debug)]
pub struct ParsedToken {
    /// Parsed token.
    pub token: Token,
    /// If error is present then parsed token is malformed.
    pub error: Option<SyntaxError>,
}

#[derive(Debug, Default)]
/// Represents the result of parsing source code of Rust language.
pub struct ParsedTokens {
    /// Parsed tokens in order they appear in source code.
    pub tokens: Vec<Token>,
    /// Collection of all occured tokenization errors.
    /// In general `self.errors.len() <= self.tokens.len()`
    pub errors: Vec<SyntaxError>,
}
impl ParsedTokens {
    /// Append `token` and `error` (if pressent) to the result.
    pub fn push(&mut self, ParsedToken { token, error }: ParsedToken) {
        self.tokens.push(token);
        if let Some(error) = error {
            self.errors.push(error)
        }
    }
}

/// Same as `tokenize_append()`, just a shortcut for creating `ParsedTokens`
/// and returning the result the usual way.
pub fn tokenize(text: &str) -> ParsedTokens {
    let mut parsed = ParsedTokens::default();
    tokenize_append(text, &mut parsed);
    parsed
}

/// Break a string up into its component tokens.
/// Writes to `ParsedTokens` which are basically a pair `(Vec<Token>, Vec<SyntaxError>)`.
/// Beware that it checks for shebang first and its length contributes to resulting
/// tokens offsets.
pub fn tokenize_append(text: &str, parsed: &mut ParsedTokens) {
    // non-empty string is a precondtion of `rustc_lexer::strip_shebang()`.
    if text.is_empty() {
        return;
    }

    let mut offset: usize = rustc_lexer::strip_shebang(text)
        .map(|shebang_len| {
            parsed.tokens.push(Token { kind: SHEBANG, len: TextUnit::from_usize(shebang_len) });
            shebang_len
        })
        .unwrap_or(0);

    let text_without_shebang = &text[offset..];

    for rustc_token in rustc_lexer::tokenize(text_without_shebang) {
        parsed.push(rustc_token_to_parsed_token(&rustc_token, text, TextUnit::from_usize(offset)));
        offset += rustc_token.len;
    }
}

/// Returns the first encountered token at the beginning of the string.
/// If the string contains zero or *two or more tokens* returns `None`.
///
/// The main difference between `first_token()` and `single_token()` is that
/// the latter returns `None` if the string contains more than one token.
pub fn single_token(text: &str) -> Option<ParsedToken> {
    first_token(text).filter(|parsed| parsed.token.len.to_usize() == text.len())
}

/// Returns the first encountered token at the beginning of the string.
/// If the string contains zero tokens returns `None`.
///
/// The main difference between `first_token() and single_token()` is that
/// the latter returns `None` if the string contains more than one token.
pub fn first_token(text: &str) -> Option<ParsedToken> {
    // non-empty string is a precondtion of `rustc_lexer::first_token()`.
    if text.is_empty() {
        None
    } else {
        let rustc_token = rustc_lexer::first_token(text);
        Some(rustc_token_to_parsed_token(&rustc_token, text, TextUnit::from(0)))
    }
}

/// Describes the values of `SyntaxErrorKind::TokenizeError` enum variant.
/// It describes all the types of errors that may happen during the tokenization
/// of Rust source.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum TokenizeError {
    /// Base prefix was provided, but there were no digits
    /// after it, e.g. `0x`, `0b`.
    EmptyInt,
    /// Float exponent lacks digits e.g. `12.34e+`, `12.3E+`, `12e-`, `1_E-`,
    EmptyExponent,

    /// Block comment lacks trailing delimiter `*/`
    UnterminatedBlockComment,
    /// Character literal lacks trailing delimiter `'`
    UnterminatedChar,
    /// Characterish byte literal lacks trailing delimiter `'`
    UnterminatedByte,
    /// String literal lacks trailing delimiter `"`
    UnterminatedString,
    /// Byte string literal lacks trailing delimiter `"`
    UnterminatedByteString,
    /// Raw literal lacks trailing delimiter e.g. `"##`
    UnterminatedRawString,
    /// Raw byte string literal lacks trailing delimiter e.g. `"##`
    UnterminatedRawByteString,

    /// Raw string lacks a quote after the pound characters e.g. `r###`
    UnstartedRawString,
    /// Raw byte string lacks a quote after the pound characters e.g. `br###`
    UnstartedRawByteString,

    /// Lifetime starts with a number e.g. `'4ever`
    LifetimeStartsWithNumber,
}

/// Mapper function that converts `rustc_lexer::Token` with some additional context
/// to `ParsedToken`
fn rustc_token_to_parsed_token(
    rustc_token: &rustc_lexer::Token,
    text: &str,
    token_start_offset: TextUnit,
) -> ParsedToken {
    // We drop some useful infromation here (see patterns with double dots `..`)
    // Storing that info in `SyntaxKind` is not possible due to its layout requirements of
    // being `u16` that come from `rowan::SyntaxKind` type and changes to `rowan::SyntaxKind`
    // would mean hell of a rewrite

    let token_range =
        TextRange::offset_len(token_start_offset, TextUnit::from_usize(rustc_token.len));

    let token_text = &text[token_range];

    let (syntax_kind, error) = {
        use rustc_lexer::TokenKind as TK;
        use TokenizeError as TE;

        match rustc_token.kind {
            TK::LineComment => ok(COMMENT),
            TK::BlockComment { terminated } => {
                ok_if(terminated, COMMENT, TE::UnterminatedBlockComment)
            }
            TK::Whitespace => ok(WHITESPACE),
            TK::Ident => ok(if token_text == "_" {
                UNDERSCORE
            } else {
                SyntaxKind::from_keyword(token_text).unwrap_or(IDENT)
            }),
            TK::RawIdent => ok(IDENT),
            TK::Literal { kind, .. } => match_literal_kind(&kind),
            TK::Lifetime { starts_with_number } => {
                ok_if(!starts_with_number, LIFETIME, TE::LifetimeStartsWithNumber)
            }
            TK::Semi => ok(SEMI),
            TK::Comma => ok(COMMA),
            TK::Dot => ok(DOT),
            TK::OpenParen => ok(L_PAREN),
            TK::CloseParen => ok(R_PAREN),
            TK::OpenBrace => ok(L_CURLY),
            TK::CloseBrace => ok(R_CURLY),
            TK::OpenBracket => ok(L_BRACK),
            TK::CloseBracket => ok(R_BRACK),
            TK::At => ok(AT),
            TK::Pound => ok(POUND),
            TK::Tilde => ok(TILDE),
            TK::Question => ok(QUESTION),
            TK::Colon => ok(COLON),
            TK::Dollar => ok(DOLLAR),
            TK::Eq => ok(EQ),
            TK::Not => ok(EXCL),
            TK::Lt => ok(L_ANGLE),
            TK::Gt => ok(R_ANGLE),
            TK::Minus => ok(MINUS),
            TK::And => ok(AMP),
            TK::Or => ok(PIPE),
            TK::Plus => ok(PLUS),
            TK::Star => ok(STAR),
            TK::Slash => ok(SLASH),
            TK::Caret => ok(CARET),
            TK::Percent => ok(PERCENT),
            TK::Unknown => ok(ERROR),
        }
    };

    return ParsedToken {
        token: Token { kind: syntax_kind, len: token_range.len() },
        error: error
            .map(|error| SyntaxError::new(SyntaxErrorKind::TokenizeError(error), token_range)),
    };

    type ParsedSyntaxKind = (SyntaxKind, Option<TokenizeError>);

    fn match_literal_kind(kind: &rustc_lexer::LiteralKind) -> ParsedSyntaxKind {
        use rustc_lexer::LiteralKind as LK;
        use TokenizeError as TE;

        match *kind {
            LK::Int { empty_int, .. } => ok_if(!empty_int, INT_NUMBER, TE::EmptyInt),
            LK::Float { empty_exponent, .. } => {
                ok_if(!empty_exponent, FLOAT_NUMBER, TE::EmptyExponent)
            }
            LK::Char { terminated } => ok_if(terminated, CHAR, TE::UnterminatedChar),
            LK::Byte { terminated } => ok_if(terminated, BYTE, TE::UnterminatedByte),
            LK::Str { terminated } => ok_if(terminated, STRING, TE::UnterminatedString),
            LK::ByteStr { terminated } => {
                ok_if(terminated, BYTE_STRING, TE::UnterminatedByteString)
            }

            LK::RawStr { started: true, terminated, .. } => {
                ok_if(terminated, RAW_STRING, TE::UnterminatedRawString)
            }
            LK::RawStr { started: false, .. } => err(RAW_STRING, TE::UnstartedRawString),

            LK::RawByteStr { started: true, terminated, .. } => {
                ok_if(terminated, RAW_BYTE_STRING, TE::UnterminatedRawByteString)
            }
            LK::RawByteStr { started: false, .. } => {
                err(RAW_BYTE_STRING, TE::UnstartedRawByteString)
            }
        }
    }
    const fn ok(syntax_kind: SyntaxKind) -> ParsedSyntaxKind {
        (syntax_kind, None)
    }
    const fn err(syntax_kind: SyntaxKind, error: TokenizeError) -> ParsedSyntaxKind {
        (syntax_kind, Some(error))
    }
    fn ok_if(cond: bool, syntax_kind: SyntaxKind, error: TokenizeError) -> ParsedSyntaxKind {
        if cond {
            ok(syntax_kind)
        } else {
            err(syntax_kind, error)
        }
    }
}
<|endoftext|>