<commit_before>use crate::structures::CommandFun;
use proc_macro2::Span;
use proc_macro2::TokenStream as TokenStream2;
use quote::{quote, ToTokens};
use syn::{
    braced, bracketed,
    parse::{Error, Parse, ParseBuffer, ParseStream, Result},
    parse_quote,
    spanned::Spanned,
    token::{Brace, Bracket, Mut},
    Ident, Lit, ReturnType, Token, Type,
};

pub trait LitExt {
    fn to_str(&self) -> String;
    fn to_bool(&self) -> bool;
    fn to_ident(&self) -> Ident;
}

impl LitExt for Lit {
    fn to_str(&self) -> String {
        match self {
            Lit::Str(s) => s.value(),
            Lit::ByteStr(s) => unsafe { String::from_utf8_unchecked(s.value()) },
            Lit::Char(c) => c.value().to_string(),
            Lit::Byte(b) => (b.value() as char).to_string(),
            _ => panic!("values must be a (byte)string or a char"),
        }
    }

    fn to_bool(&self) -> bool {
        if let Lit::Bool(b) = self {
            b.value
        } else {
            self.to_str()
                .parse()
                .unwrap_or_else(|_| panic!("expected bool from {:?}", self))
        }
    }

    #[inline]
    fn to_ident(&self) -> Ident {
        Ident::new(&self.to_str(), Span::call_site())
    }
}

pub trait IdentExt2: Sized {
    fn to_uppercase(&self) -> Self;
    fn with_suffix(&self, suf: &str) -> Ident;
}

impl IdentExt2 for Ident {
    fn to_uppercase(&self) -> Self {
        let ident = self.to_string();
        let ident = ident.to_uppercase();

        Ident::new(&ident, Span::call_site())
    }

    fn with_suffix(&self, suf: &str) -> Ident {
        Ident::new(
            &format!("{}_{}", self.to_uppercase(), suf),
            Span::call_site(),
        )
    }
}

pub trait ParseStreamExt {
    /// Do not advance unless the parse was successful.
    fn try_parse<T: Parse>(&self) -> Result<T>;
}

impl<'a> ParseStreamExt for ParseBuffer<'a> {
    fn try_parse<T: Parse>(&self) -> Result<T> {
        let stream = self.fork();
        let res = T::parse(&stream);
        if res.is_ok() {
            T::parse(self)?;
        }

        res
    }
}

pub struct AsOption<T>(pub Option<T>);

impl<T: ToTokens> ToTokens for AsOption<T> {
    fn to_tokens(&self, stream: &mut TokenStream2) {
        match &self.0 {
            Some(o) => stream.extend(quote!(Some(#o))),
            None => stream.extend(quote!(None)),
        }
    }
}

#[derive(Debug)]
pub struct Argument {
    pub mutable: Option<Mut>,
    pub name: Ident,
    pub kind: Type,
}

impl ToTokens for Argument {
    fn to_tokens(&self, stream: &mut TokenStream2) {
        let Argument {
            mutable,
            name,
            kind,
        } = self;

        stream.extend(quote! {
            #mutable #name: #kind
        });
    }
}

#[derive(Debug)]
pub struct Field<T> {
    pub name: Ident,
    pub value: T,
}

impl<T: Parse> Parse for Field<T> {
    fn parse(input: ParseStream) -> Result<Self> {
        let name = input.parse()?;
        input.parse::<Token![:]>()?;

        let value = input.parse()?;

        Ok(Field { name, value })
    }
}

#[derive(Debug)]
pub enum RefOrInstance<T> {
    Ref(Ident),
    Instance(T),
}

impl<T: Parse> Parse for RefOrInstance<T> {
    fn parse(input: ParseStream) -> Result<Self> {
        if input.peek(Ident) {
            Ok(RefOrInstance::Ref(input.parse()?))
        } else {
            Ok(RefOrInstance::Instance(input.parse()?))
        }
    }
}

impl<T: Default> Default for RefOrInstance<T> {
    #[inline]
    fn default() -> Self {
        RefOrInstance::Instance(T::default())
    }
}

#[derive(Debug)]
pub struct IdentAccess(pub Ident, pub Option<Ident>);

impl Parse for IdentAccess {
    fn parse(input: ParseStream) -> Result<Self> {
        let name = input.parse()?;

        let name2 = if input.peek(Token![.]) {
            input.parse::<Token![.]>()?;

            Some(input.parse()?)
        } else {
            None
        };

        Ok(IdentAccess(name, name2))
    }
}

#[derive(Debug)]
pub enum Expr {
    Lit(Lit),
    Access(IdentAccess),
    Object(Object),
    Array(Array),
}

impl Parse for Expr {
    fn parse(input: ParseStream) -> Result<Self> {
        if input.peek(Brace) {
            Ok(Expr::Object(input.parse()?))
        } else if input.peek(Bracket) {
            Ok(Expr::Array(input.parse()?))
        } else if let Ok(access) = input.try_parse::<IdentAccess>() {
            Ok(Expr::Access(access))
        } else {
            Ok(Expr::Lit(input.parse()?))
        }
    }
}

#[derive(Debug)]
pub struct Object(pub Vec<Field<Expr>>);

impl Parse for Object {
    fn parse(input: ParseStream) -> Result<Self> {
        let content;
        braced!(content in input);
        let input = content;

        let fields = input.parse_terminated::<_, Token![,]>(Field::<Expr>::parse)?;

        Ok(Object(fields.into_iter().collect()))
    }
}

#[derive(Debug)]
pub struct Array(pub Vec<Expr>);

impl Parse for Array {
    fn parse(input: ParseStream) -> Result<Self> {
        let content;
        bracketed!(content in input);
        let input = content;

        let fields = input.parse_terminated::<_, Token![,]>(Expr::parse)?;

        Ok(Array(fields.into_iter().collect()))
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DeclarFor {
    Command,
    Help,
    Check,
}

pub fn validate_declaration(fun: &mut CommandFun, dec_for: DeclarFor) -> Result<()> {
    let len = match dec_for {
        DeclarFor::Command => 3,
        DeclarFor::Help => 6,
        DeclarFor::Check => 4,
    };

    if fun.args.len() > len {
        return Err(Error::new(
            fun.args.last().unwrap().span(),
            format!("function's arity exceeds more than {} arguments", len),
        ));
    }

    let context: Type = parse_quote!(&mut Context);
    let message: Type = parse_quote!(&Message);
    let args: Type = parse_quote!(Args);
    let args2: Type = parse_quote!(&mut Args);
    let options: Type = parse_quote!(&CommandOptions);
    let hoptions: Type = parse_quote!(&'static HelpOptions);
    let groups: Type = parse_quote!(&[&'static CommandGroup]);
    let owners: Type = parse_quote!(HashSet<UserId, impl BuildHasher>);

    let context_path: Type = parse_quote!(&mut serenity::prelude::Context);
    let message_path: Type = parse_quote!(&serenity::model::channel::Message);
    let args_path: Type = parse_quote!(serenity::framework::standard::Args);
    let args2_path: Type = parse_quote!(&mut serenity::framework::standard::Args);
    let options_path: Type = parse_quote!(&'static serenity::framework::standard::CommandOptions);
    let hoptions_path: Type = parse_quote!(&'static serenity::framework::standard::HelpOptions);
    let groups_path: Type = parse_quote!(&[&'static serenity::framework::standard::CommandGroup]);
    let owners_path: Type = parse_quote!(std::collections::HashSet<serenity::model::id::UserId, std::hash::BuildHasher>);

    let ctx_error = "first argument's type should be `&mut Context`";
    let msg_error = "second argument's type should be `&Message`";
    let args_error = "third argument's type should be `Args`";
    let args2_error = "third argument's type should be `&mut Args`";
    let options_error = "fourth argument's type should be `&'static CommandOptions`";
    let hoptions_error = "fourth argument's type should be `&'static HelpOptions`";
    let groups_error = "fifth argument's type should be `&[&'static CommandGroup]`";
    let owners_error = "sixth argument's type should be `HashSet<UserId, impl BuildHasher>`";

    #[allow(unused_assignments)]
    macro_rules! spoof_or_check {
        ($(($($help:tt)?) [$($mut:tt)?] $type:ident, $name:literal, $error:ident, $path:ident);*) => {{
            macro_rules! arg {
                () => {
                    None
                };
                (mut) => {
                    Some(parse_quote!(mut))
                }
            }

            macro_rules! help {
                ($b:block) => {
                    $b
                };
                (help $b:block) => {
                    if dec_for == DeclarFor::Help {
                        $b
                    }
                }
            }

            let mut index = 0;
            $(
                help!($($help)? {
                    match fun.args.get(index) {
                        Some(x) => {
                            if x.kind != $type {
                                return Err(Error::new(fun.args[index].span(), $error));
                            }
                        },
                        None => fun.args.push(Argument {
                            mutable: arg!($($mut)?),
                            name: Ident::new($name, Span::call_site()),
                            kind: $path,
                        }),
                    }
                });

                index += 1;
            )*

            let _ = index;
        }};
    }

    if dec_for != DeclarFor::Check {
        spoof_or_check! {
            ()     []    context, "_ctx",     ctx_error,     context_path;
            ()     []    message, "_msg",     msg_error,     message_path;
            ()     [mut] args,    "_args",    args_error,    args_path;
            (help) []    options, "_options", options_error, options_path;
            (help) []    groups,  "_groups",  groups_error,  groups_path;
            (help) []    owners,  "_owners",  owners_error,  owners_path
        }
    } else {
        spoof_or_check! {
            ()     []    context, "_ctx",     ctx_error,     context_path;
            ()     []    message, "_msg",     msg_error,     message_path;
            ()     []    args2,   "_args",    args2_error,   args2_path;
            ()     []    options, "_options", options_error, options_path
        }
    }

    Ok(())
}

pub fn validate_return_type(fun: &mut CommandFun, want: Type) -> Result<()> {
    let span = fun.ret.span();
    let kind = match fun.ret {
        ReturnType::Type(_, ref kind) => kind,
        _ => unreachable!(),
    };

    if &**kind != &want {
        return Err(Error::new(
            span,
            &format!(
                "expected a result as a return type, but got `{}`",
                quote!(#kind)
            ),
        ));
    }

    Ok(())
}
<commit_msg>Use the correct options<commit_after>use crate::structures::CommandFun;
use proc_macro2::Span;
use proc_macro2::TokenStream as TokenStream2;
use quote::{quote, ToTokens};
use syn::{
    braced, bracketed,
    parse::{Error, Parse, ParseBuffer, ParseStream, Result},
    parse_quote,
    spanned::Spanned,
    token::{Brace, Bracket, Mut},
    Ident, Lit, ReturnType, Token, Type,
};

pub trait LitExt {
    fn to_str(&self) -> String;
    fn to_bool(&self) -> bool;
    fn to_ident(&self) -> Ident;
}

impl LitExt for Lit {
    fn to_str(&self) -> String {
        match self {
            Lit::Str(s) => s.value(),
            Lit::ByteStr(s) => unsafe { String::from_utf8_unchecked(s.value()) },
            Lit::Char(c) => c.value().to_string(),
            Lit::Byte(b) => (b.value() as char).to_string(),
            _ => panic!("values must be a (byte)string or a char"),
        }
    }

    fn to_bool(&self) -> bool {
        if let Lit::Bool(b) = self {
            b.value
        } else {
            self.to_str()
                .parse()
                .unwrap_or_else(|_| panic!("expected bool from {:?}", self))
        }
    }

    #[inline]
    fn to_ident(&self) -> Ident {
        Ident::new(&self.to_str(), Span::call_site())
    }
}

pub trait IdentExt2: Sized {
    fn to_uppercase(&self) -> Self;
    fn with_suffix(&self, suf: &str) -> Ident;
}

impl IdentExt2 for Ident {
    fn to_uppercase(&self) -> Self {
        let ident = self.to_string();
        let ident = ident.to_uppercase();

        Ident::new(&ident, Span::call_site())
    }

    fn with_suffix(&self, suf: &str) -> Ident {
        Ident::new(
            &format!("{}_{}", self.to_uppercase(), suf),
            Span::call_site(),
        )
    }
}

pub trait ParseStreamExt {
    /// Do not advance unless the parse was successful.
    fn try_parse<T: Parse>(&self) -> Result<T>;
}

impl<'a> ParseStreamExt for ParseBuffer<'a> {
    fn try_parse<T: Parse>(&self) -> Result<T> {
        let stream = self.fork();
        let res = T::parse(&stream);
        if res.is_ok() {
            T::parse(self)?;
        }

        res
    }
}

pub struct AsOption<T>(pub Option<T>);

impl<T: ToTokens> ToTokens for AsOption<T> {
    fn to_tokens(&self, stream: &mut TokenStream2) {
        match &self.0 {
            Some(o) => stream.extend(quote!(Some(#o))),
            None => stream.extend(quote!(None)),
        }
    }
}

#[derive(Debug)]
pub struct Argument {
    pub mutable: Option<Mut>,
    pub name: Ident,
    pub kind: Type,
}

impl ToTokens for Argument {
    fn to_tokens(&self, stream: &mut TokenStream2) {
        let Argument {
            mutable,
            name,
            kind,
        } = self;

        stream.extend(quote! {
            #mutable #name: #kind
        });
    }
}

#[derive(Debug)]
pub struct Field<T> {
    pub name: Ident,
    pub value: T,
}

impl<T: Parse> Parse for Field<T> {
    fn parse(input: ParseStream) -> Result<Self> {
        let name = input.parse()?;
        input.parse::<Token![:]>()?;

        let value = input.parse()?;

        Ok(Field { name, value })
    }
}

#[derive(Debug)]
pub enum RefOrInstance<T> {
    Ref(Ident),
    Instance(T),
}

impl<T: Parse> Parse for RefOrInstance<T> {
    fn parse(input: ParseStream) -> Result<Self> {
        if input.peek(Ident) {
            Ok(RefOrInstance::Ref(input.parse()?))
        } else {
            Ok(RefOrInstance::Instance(input.parse()?))
        }
    }
}

impl<T: Default> Default for RefOrInstance<T> {
    #[inline]
    fn default() -> Self {
        RefOrInstance::Instance(T::default())
    }
}

#[derive(Debug)]
pub struct IdentAccess(pub Ident, pub Option<Ident>);

impl Parse for IdentAccess {
    fn parse(input: ParseStream) -> Result<Self> {
        let name = input.parse()?;

        let name2 = if input.peek(Token![.]) {
            input.parse::<Token![.]>()?;

            Some(input.parse()?)
        } else {
            None
        };

        Ok(IdentAccess(name, name2))
    }
}

#[derive(Debug)]
pub enum Expr {
    Lit(Lit),
    Access(IdentAccess),
    Object(Object),
    Array(Array),
}

impl Parse for Expr {
    fn parse(input: ParseStream) -> Result<Self> {
        if input.peek(Brace) {
            Ok(Expr::Object(input.parse()?))
        } else if input.peek(Bracket) {
            Ok(Expr::Array(input.parse()?))
        } else if let Ok(access) = input.try_parse::<IdentAccess>() {
            Ok(Expr::Access(access))
        } else {
            Ok(Expr::Lit(input.parse()?))
        }
    }
}

#[derive(Debug)]
pub struct Object(pub Vec<Field<Expr>>);

impl Parse for Object {
    fn parse(input: ParseStream) -> Result<Self> {
        let content;
        braced!(content in input);
        let input = content;

        let fields = input.parse_terminated::<_, Token![,]>(Field::<Expr>::parse)?;

        Ok(Object(fields.into_iter().collect()))
    }
}

#[derive(Debug)]
pub struct Array(pub Vec<Expr>);

impl Parse for Array {
    fn parse(input: ParseStream) -> Result<Self> {
        let content;
        bracketed!(content in input);
        let input = content;

        let fields = input.parse_terminated::<_, Token![,]>(Expr::parse)?;

        Ok(Array(fields.into_iter().collect()))
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DeclarFor {
    Command,
    Help,
    Check,
}

pub fn validate_declaration(fun: &mut CommandFun, dec_for: DeclarFor) -> Result<()> {
    let len = match dec_for {
        DeclarFor::Command => 3,
        DeclarFor::Help => 6,
        DeclarFor::Check => 4,
    };

    if fun.args.len() > len {
        return Err(Error::new(
            fun.args.last().unwrap().span(),
            format!("function's arity exceeds more than {} arguments", len),
        ));
    }

    let context: Type = parse_quote!(&mut Context);
    let message: Type = parse_quote!(&Message);
    let args: Type = parse_quote!(Args);
    let args2: Type = parse_quote!(&mut Args);
    let options: Type = parse_quote!(&CommandOptions);
    let hoptions: Type = parse_quote!(&'static HelpOptions);
    let groups: Type = parse_quote!(&[&'static CommandGroup]);
    let owners: Type = parse_quote!(HashSet<UserId, impl BuildHasher>);

    let context_path: Type = parse_quote!(&mut serenity::prelude::Context);
    let message_path: Type = parse_quote!(&serenity::model::channel::Message);
    let args_path: Type = parse_quote!(serenity::framework::standard::Args);
    let args2_path: Type = parse_quote!(&mut serenity::framework::standard::Args);
    let options_path: Type = parse_quote!(&'static serenity::framework::standard::CommandOptions);
    let hoptions_path: Type = parse_quote!(&'static serenity::framework::standard::HelpOptions);
    let groups_path: Type = parse_quote!(&[&'static serenity::framework::standard::CommandGroup]);
    let owners_path: Type = parse_quote!(std::collections::HashSet<serenity::model::id::UserId, std::hash::BuildHasher>);

    let ctx_error = "first argument's type should be `&mut Context`";
    let msg_error = "second argument's type should be `&Message`";
    let args_error = "third argument's type should be `Args`";
    let args2_error = "third argument's type should be `&mut Args`";
    let options_error = "fourth argument's type should be `&'static CommandOptions`";
    let hoptions_error = "fourth argument's type should be `&'static HelpOptions`";
    let groups_error = "fifth argument's type should be `&[&'static CommandGroup]`";
    let owners_error = "sixth argument's type should be `HashSet<UserId, impl BuildHasher>`";

    #[allow(unused_assignments)]
    macro_rules! spoof_or_check {
        ($(($($help:tt)?) [$($mut:tt)?] $type:ident, $name:literal, $error:ident, $path:ident);*) => {{
            macro_rules! arg {
                () => {
                    None
                };
                (mut) => {
                    Some(parse_quote!(mut))
                }
            }

            macro_rules! help {
                ($b:block) => {
                    $b
                };
                (help $b:block) => {
                    if dec_for == DeclarFor::Help {
                        $b
                    }
                }
            }

            let mut index = 0;
            $(
                help!($($help)? {
                    match fun.args.get(index) {
                        Some(x) => {
                            if x.kind != $type {
                                return Err(Error::new(fun.args[index].span(), $error));
                            }
                        },
                        None => fun.args.push(Argument {
                            mutable: arg!($($mut)?),
                            name: Ident::new($name, Span::call_site()),
                            kind: $path,
                        }),
                    }
                });

                index += 1;
            )*

            let _ = index;
        }};
    }

    if dec_for != DeclarFor::Check {
        spoof_or_check! {
            ()     []    context,  "_ctx",     ctx_error,      context_path;
            ()     []    message,  "_msg",     msg_error,      message_path;
            ()     [mut] args,     "_args",    args_error,     args_path;
            (help) []    hoptions, "_hoptions", hoptions_error, hoptions_path;
            (help) []    groups,   "_groups",  groups_error,   groups_path;
            (help) []    owners,   "_owners",  owners_error,   owners_path
        }
    } else {
        spoof_or_check! {
            ()     []    context, "_ctx",     ctx_error,     context_path;
            ()     []    message, "_msg",     msg_error,     message_path;
            ()     []    args2,   "_args",    args2_error,   args2_path;
            ()     []    options, "_options", options_error, options_path
        }
    }

    Ok(())
}

pub fn validate_return_type(fun: &mut CommandFun, want: Type) -> Result<()> {
    let span = fun.ret.span();
    let kind = match fun.ret {
        ReturnType::Type(_, ref kind) => kind,
        _ => unreachable!(),
    };

    if &**kind != &want {
        return Err(Error::new(
            span,
            &format!(
                "expected a result as a return type, but got `{}`",
                quote!(#kind)
            ),
        ));
    }

    Ok(())
}
<|endoftext|>


<commit_before><commit_msg>add a bit<commit_after><|endoftext|>


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

//! A cell that with volatile setter and getter.

#![feature(core_intrinsics)]
#![no_std]

#[cfg(feature="replayer")] #[macro_use(expect)] extern crate expectest;
#[cfg(feature="replayer")] #[macro_use] extern crate std;

#[cfg(feature="replayer")] use std::vec::Vec;
#[cfg(feature="replayer")] use expectest::prelude::*;
#[cfg(feature="replayer")] use expectest::core::Matcher;
#[cfg(feature="replayer")] use std::string::String;
#[cfg(feature="replayer")] use std::fmt;
#[cfg(feature="replayer")] use core::cmp::PartialEq;
#[cfg(feature="replayer")] use core::clone::Clone;
#[cfg(feature="replayer")] use core::cell::RefCell;

#[cfg(not(feature="replayer"))] use core::intrinsics::{volatile_load, volatile_store};
#[cfg(feature="replayer")] use core::intrinsics::transmute;

// TODO(farcaller): why this needs copy/clone?
/// This structure is used to represent a hardware register.
/// It is mostly used by the ioreg family of macros.
#[derive(Copy, Clone)]
#[repr(C)]
pub struct VolatileCell<T> {
  value: T,
}

impl<T> VolatileCell<T> {
  /// Create a cell with initial value.
  pub fn new(value: T) -> VolatileCell<T> {
    VolatileCell {
      value: value,
    }
  }

  /// Get register value.
  #[cfg(not(feature="replayer"))]
  #[inline]
  pub fn get(&self) -> T {
    unsafe {
      volatile_load(&self.value)
    }
  }

  /// Set register value.
  #[cfg(not(feature="replayer"))]
  #[inline]
  pub fn set(&self, value: T) {
    unsafe {
      volatile_store(&self.value as *const T as *mut T, value)
    }
  }
}

#[cfg(feature="replayer")]
impl VolatileCell<u32> {
  pub fn get(&self) -> u32 {
    unsafe {
      GLOBAL_REPLAYER.with(|gr| { gr.borrow_mut().get_cell(transmute(&self.value)) })
    }
  }

  pub fn set(&self, value: u32) {
    unsafe {
      GLOBAL_REPLAYER.with(|gr| { gr.borrow_mut().set_cell(transmute(&self.value), value) })
    }
  }
}

#[cfg(feature="replayer")]
impl VolatileCell<u16> {
  pub fn get(&self) -> u16 {
    unsafe {
      GLOBAL_REPLAYER.with(|gr| { gr.borrow_mut().get_cell(transmute(&self.value)) }) as u16
    }
  }

  pub fn set(&self, value: u16) {
    unsafe {
      GLOBAL_REPLAYER.with(|gr| { gr.borrow_mut().set_cell(transmute(&self.value), value as u32) })
    }
  }
}

#[cfg(feature="replayer")]
impl VolatileCell<u8> {
  pub fn get(&self) -> u8 {
    unsafe {
      GLOBAL_REPLAYER.with(|gr| { gr.borrow_mut().get_cell(transmute(&self.value)) }) as u8
    }
  }

  pub fn set(&self, value: u8) {
    unsafe {
      GLOBAL_REPLAYER.with(|gr| { gr.borrow_mut().set_cell(transmute(&self.value), value as u32) })
    }
  }
}

#[cfg(feature="replayer")]
struct ReplayRecord {
  is_read: bool,
  address: usize,
  value: u32,

  replayed: bool,
  did_read: bool,
  actual_address: usize,
  actual_value: u32,

  loc: expectest::core::SourceLocation,
}

#[cfg(feature="replayer")]
impl core::fmt::Display for ReplayRecord {
  fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
    match self.is_read {
      true  => write!(f, "read 0x{:x} from 0x{:x}", self.value, self.address),
      false => write!(f, "write 0x{:x} to 0x{:x}", self.value, self.address),
    }
  }
}

#[cfg(feature="replayer")]
pub struct VolatileCellReplayer {
  replays: Vec<ReplayRecord>,
  current_replay: usize,
}

#[cfg(feature="replayer")]
impl VolatileCellReplayer {
  pub fn new() -> VolatileCellReplayer {
    VolatileCellReplayer {
      replays: Vec::new(),
      current_replay: 0,
    }
  }

  pub fn expect_read(&mut self, address: usize, value: u32,
      loc: expectest::core::SourceLocation) {
    self.replays.push(ReplayRecord {
      is_read: true,
      address: address,
      value: value,
      replayed: false,
      did_read: false,
      actual_address: 0,
      actual_value: 0,
      loc: loc,
    });
  }

  pub fn expect_write(&mut self, address: usize, value: u32,
      loc: expectest::core::SourceLocation) {
    self.replays.push(ReplayRecord {
      is_read: false,
      address: address,
      value: value,
      replayed: false,
      did_read: false,
      actual_address: 0,
      actual_value: 0,
      loc: loc,
    });
  }

  pub fn verify(&self, loc: expectest::core::SourceLocation) {
    expect(self.current_replay).location(loc).to(
      be_equal_to_with_context(
          self.replays.len(),
          format!("expected {} replays, performed {}",
              self.replays.len(), self.current_replay)));

    for ref replay in &*self.replays {
      expect(replay.replayed).location(replay.loc).to(be_equal_to_with_context(true,
        format!("expected replay {} to be performed, was not", replay)));
      expect(replay.is_read).location(replay.loc).to(be_equal_to_with_context(replay.did_read,
        format!("expected replay to be {} replay, was {} replay",
          if replay.is_read {"read"} else {"write"},
          if replay.is_read {"write"} else {"read"})));
      expect(replay.address).location(replay.loc).to(be_equal_to_with_context(replay.actual_address,
        format!("expected replay address 0x{:x}, was 0x{:x}", replay.address, replay.actual_address)));
      if !replay.is_read {
        expect(replay.value).location(replay.loc).to(be_equal_to_with_context(replay.actual_value,
          format!("expected replay to write 0x{:x}, written 0x{:x}", replay.value, replay.actual_value)));
      }
    }
  }

  pub fn get_cell(&mut self, address: usize) -> u32 {
    if self.current_replay >= self.replays.len() {
      panic!("get_cell(0x{:x}) faled, current replay: {}, total replays: {}",
        address, self.current_replay+1, self.replays.len());
    }
    let replay: &mut ReplayRecord = &mut self.replays[self.current_replay];
    replay.replayed = true;
    replay.did_read = true;
    replay.actual_address = address;

    self.current_replay += 1;

    replay.value
  }

  pub fn set_cell(&mut self, address: usize, value: u32) {
    if self.current_replay >= self.replays.len() {
      panic!("set_cell(0x{:x}, 0x{:x}) faled, current replay: {}, total replays: {}",
        address, value, self.current_replay+1, self.replays.len());
    }
    let replay: &mut ReplayRecord = &mut self.replays[self.current_replay];
    replay.replayed = true;
    replay.did_read = false;
    replay.actual_address = address;
    replay.actual_value = value;

    self.current_replay += 1;
  }
}

#[cfg(feature="replayer")]
thread_local!(static GLOBAL_REPLAYER: RefCell<VolatileCellReplayer> = RefCell::new(VolatileCellReplayer::new()));

#[cfg(feature="replayer")]
pub fn set_replayer(replayer: VolatileCellReplayer) {
  GLOBAL_REPLAYER.with(|gr| {
    let mut bm = gr.borrow_mut();
    *bm = replayer;
  });
}

#[cfg(feature="replayer")]
pub fn with_mut_replayer<F>(f: F) where F: core::ops::FnOnce(&mut VolatileCellReplayer) {
  GLOBAL_REPLAYER.with(|gr| {
    let mut bm = gr.borrow_mut();
    f(&mut *bm);
  });
}

#[cfg(feature="replayer")]
struct BeEqualToWithContext<E> {
    expected: E,
    context: String,
}

#[cfg(feature="replayer")]
fn be_equal_to_with_context<E>(expected: E, context: String) -> BeEqualToWithContext<E> {
    BeEqualToWithContext {
        expected: expected,
        context: context,
    }
}

#[cfg(feature="replayer")]
impl<A, E> Matcher<A, E> for BeEqualToWithContext<E>
    where
        A: PartialEq<E> + fmt::Debug,
        E: fmt::Debug {

    fn failure_message(&self, _: expectest::core::Join, _: &A) -> String {
        self.context.clone()
    }

    fn matches(&self, actual: &A) -> bool {
        *actual == self.expected
    }
}

#[macro_export]
macro_rules! expect_volatile_read {
  ($addr: expr, $val: expr) => (
    $crate::with_mut_replayer(|r| {
      r.expect_read($addr, $val, expectest::core::SourceLocation::new(file!(), line!()));
    })
  );
}

#[macro_export]
macro_rules! expect_volatile_write {
  ($addr: expr, $val: expr) => (
    $crate::with_mut_replayer(|r| {
      r.expect_write($addr, $val, expectest::core::SourceLocation::new(file!(), line!()));
    })
  );
}

#[macro_export]
macro_rules! expect_replayer_valid {
  () => (
    $crate::with_mut_replayer(|r| {
      r.verify(expectest::core::SourceLocation::new(file!(), line!()));
    })
  );
}

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

//! A cell that with volatile setter and getter.

#![feature(core_intrinsics)]
#![no_std]

#[cfg(feature="replayer")] #[macro_use(expect)] extern crate expectest;
#[cfg(feature="replayer")] #[macro_use] extern crate std;

#[cfg(feature="replayer")] use std::vec::Vec;
#[cfg(feature="replayer")] use expectest::prelude::*;
#[cfg(feature="replayer")] use expectest::core::Matcher;
#[cfg(feature="replayer")] use std::string::String;
#[cfg(feature="replayer")] use std::fmt;
#[cfg(feature="replayer")] use core::cmp::PartialEq;
#[cfg(feature="replayer")] use core::clone::Clone;
#[cfg(feature="replayer")] use core::cell::RefCell;

#[cfg(not(feature="replayer"))] use core::intrinsics::{volatile_load, volatile_store};
#[cfg(feature="replayer")] use core::intrinsics::transmute;

// TODO(farcaller): why this needs copy/clone?
/// This structure is used to represent a hardware register.
/// It is mostly used by the ioreg family of macros.
#[derive(Copy, Clone)]
#[repr(C)]
pub struct VolatileCell<T> where T: Copy {
  value: T,
}

impl<T: Copy> VolatileCell<T> {
  /// Create a cell with initial value.
  pub fn new(value: T) -> VolatileCell<T> {
    VolatileCell {
      value: value,
    }
  }

  /// Get register value.
  #[cfg(not(feature="replayer"))]
  #[inline]
  pub fn get(&self) -> T {
    unsafe {
      volatile_load(&self.value)
    }
  }

  /// Set register value.
  #[cfg(not(feature="replayer"))]
  #[inline]
  pub fn set(&self, value: T) {
    unsafe {
      volatile_store(&self.value as *const T as *mut T, value)
    }
  }
}

#[cfg(feature="replayer")]
impl VolatileCell<u32> {
  pub fn get(&self) -> u32 {
    unsafe {
      GLOBAL_REPLAYER.with(|gr| { gr.borrow_mut().get_cell(transmute(&self.value)) })
    }
  }

  pub fn set(&self, value: u32) {
    unsafe {
      GLOBAL_REPLAYER.with(|gr| { gr.borrow_mut().set_cell(transmute(&self.value), value) })
    }
  }
}

#[cfg(feature="replayer")]
impl VolatileCell<u16> {
  pub fn get(&self) -> u16 {
    unsafe {
      GLOBAL_REPLAYER.with(|gr| { gr.borrow_mut().get_cell(transmute(&self.value)) }) as u16
    }
  }

  pub fn set(&self, value: u16) {
    unsafe {
      GLOBAL_REPLAYER.with(|gr| { gr.borrow_mut().set_cell(transmute(&self.value), value as u32) })
    }
  }
}

#[cfg(feature="replayer")]
impl VolatileCell<u8> {
  pub fn get(&self) -> u8 {
    unsafe {
      GLOBAL_REPLAYER.with(|gr| { gr.borrow_mut().get_cell(transmute(&self.value)) }) as u8
    }
  }

  pub fn set(&self, value: u8) {
    unsafe {
      GLOBAL_REPLAYER.with(|gr| { gr.borrow_mut().set_cell(transmute(&self.value), value as u32) })
    }
  }
}

#[cfg(feature="replayer")]
struct ReplayRecord {
  is_read: bool,
  address: usize,
  value: u32,

  replayed: bool,
  did_read: bool,
  actual_address: usize,
  actual_value: u32,

  loc: expectest::core::SourceLocation,
}

#[cfg(feature="replayer")]
impl core::fmt::Display for ReplayRecord {
  fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
    match self.is_read {
      true  => write!(f, "read 0x{:x} from 0x{:x}", self.value, self.address),
      false => write!(f, "write 0x{:x} to 0x{:x}", self.value, self.address),
    }
  }
}

#[cfg(feature="replayer")]
pub struct VolatileCellReplayer {
  replays: Vec<ReplayRecord>,
  current_replay: usize,
}

#[cfg(feature="replayer")]
impl VolatileCellReplayer {
  pub fn new() -> VolatileCellReplayer {
    VolatileCellReplayer {
      replays: Vec::new(),
      current_replay: 0,
    }
  }

  pub fn expect_read(&mut self, address: usize, value: u32,
      loc: expectest::core::SourceLocation) {
    self.replays.push(ReplayRecord {
      is_read: true,
      address: address,
      value: value,
      replayed: false,
      did_read: false,
      actual_address: 0,
      actual_value: 0,
      loc: loc,
    });
  }

  pub fn expect_write(&mut self, address: usize, value: u32,
      loc: expectest::core::SourceLocation) {
    self.replays.push(ReplayRecord {
      is_read: false,
      address: address,
      value: value,
      replayed: false,
      did_read: false,
      actual_address: 0,
      actual_value: 0,
      loc: loc,
    });
  }

  pub fn verify(&self, loc: expectest::core::SourceLocation) {
    expect(self.current_replay).location(loc).to(
      be_equal_to_with_context(
          self.replays.len(),
          format!("expected {} replays, performed {}",
              self.replays.len(), self.current_replay)));

    for ref replay in &*self.replays {
      expect(replay.replayed).location(replay.loc).to(be_equal_to_with_context(true,
        format!("expected replay {} to be performed, was not", replay)));
      expect(replay.is_read).location(replay.loc).to(be_equal_to_with_context(replay.did_read,
        format!("expected replay to be {} replay, was {} replay",
          if replay.is_read {"read"} else {"write"},
          if replay.is_read {"write"} else {"read"})));
      expect(replay.address).location(replay.loc).to(be_equal_to_with_context(replay.actual_address,
        format!("expected replay address 0x{:x}, was 0x{:x}", replay.address, replay.actual_address)));
      if !replay.is_read {
        expect(replay.value).location(replay.loc).to(be_equal_to_with_context(replay.actual_value,
          format!("expected replay to write 0x{:x}, written 0x{:x}", replay.value, replay.actual_value)));
      }
    }
  }

  pub fn get_cell(&mut self, address: usize) -> u32 {
    if self.current_replay >= self.replays.len() {
      panic!("get_cell(0x{:x}) faled, current replay: {}, total replays: {}",
        address, self.current_replay+1, self.replays.len());
    }
    let replay: &mut ReplayRecord = &mut self.replays[self.current_replay];
    replay.replayed = true;
    replay.did_read = true;
    replay.actual_address = address;

    self.current_replay += 1;

    replay.value
  }

  pub fn set_cell(&mut self, address: usize, value: u32) {
    if self.current_replay >= self.replays.len() {
      panic!("set_cell(0x{:x}, 0x{:x}) faled, current replay: {}, total replays: {}",
        address, value, self.current_replay+1, self.replays.len());
    }
    let replay: &mut ReplayRecord = &mut self.replays[self.current_replay];
    replay.replayed = true;
    replay.did_read = false;
    replay.actual_address = address;
    replay.actual_value = value;

    self.current_replay += 1;
  }
}

#[cfg(feature="replayer")]
thread_local!(static GLOBAL_REPLAYER: RefCell<VolatileCellReplayer> = RefCell::new(VolatileCellReplayer::new()));

#[cfg(feature="replayer")]
pub fn set_replayer(replayer: VolatileCellReplayer) {
  GLOBAL_REPLAYER.with(|gr| {
    let mut bm = gr.borrow_mut();
    *bm = replayer;
  });
}

#[cfg(feature="replayer")]
pub fn with_mut_replayer<F>(f: F) where F: core::ops::FnOnce(&mut VolatileCellReplayer) {
  GLOBAL_REPLAYER.with(|gr| {
    let mut bm = gr.borrow_mut();
    f(&mut *bm);
  });
}

#[cfg(feature="replayer")]
struct BeEqualToWithContext<E> {
    expected: E,
    context: String,
}

#[cfg(feature="replayer")]
fn be_equal_to_with_context<E>(expected: E, context: String) -> BeEqualToWithContext<E> {
    BeEqualToWithContext {
        expected: expected,
        context: context,
    }
}

#[cfg(feature="replayer")]
impl<A, E> Matcher<A, E> for BeEqualToWithContext<E>
    where
        A: PartialEq<E> + fmt::Debug,
        E: fmt::Debug {

    fn failure_message(&self, _: expectest::core::Join, _: &A) -> String {
        self.context.clone()
    }

    fn matches(&self, actual: &A) -> bool {
        *actual == self.expected
    }
}

#[macro_export]
macro_rules! expect_volatile_read {
  ($addr: expr, $val: expr) => (
    $crate::with_mut_replayer(|r| {
      r.expect_read($addr, $val, expectest::core::SourceLocation::new(file!(), line!()));
    })
  );
}

#[macro_export]
macro_rules! expect_volatile_write {
  ($addr: expr, $val: expr) => (
    $crate::with_mut_replayer(|r| {
      r.expect_write($addr, $val, expectest::core::SourceLocation::new(file!(), line!()));
    })
  );
}

#[macro_export]
macro_rules! expect_replayer_valid {
  () => (
    $crate::with_mut_replayer(|r| {
      r.verify(expectest::core::SourceLocation::new(file!(), line!()));
    })
  );
}

#[macro_export]
macro_rules! init_replayer {
  () => (
    set_replayer(VolatileCellReplayer::new());
  );
}
<|endoftext|>


<commit_before>use crate::constants::*;

#[derive(Clone, Debug, PartialEq)]
pub enum Style {
    Old,
    OldInverse,
    New,
    NewInverse,
    Error,
}

#[derive(Clone, Debug, PartialEq)]
pub struct StyledToken {
    token: String,
    style: Style,
}

impl StyledToken {
    pub fn new(token: String, style: Style) -> StyledToken {
        return StyledToken { token, style };
    }

    pub fn is_whitespace(&self) -> bool {
        let mut chars_iterator = self.token.chars();
        let first_char = chars_iterator.next().unwrap();
        if chars_iterator.next().is_some() {
            // Multiple chars found in this token, but whitespace will only be
            // one per token.
            return false;
        }

        return first_char.is_whitespace();
    }

    pub fn is_word(&self) -> bool {
        let mut chars_iterator = self.token.chars();
        let first_char = chars_iterator.next().unwrap();
        let second_char = chars_iterator.next();
        if second_char.is_some() {
            // We consist of multiple characters, that means we are a word
            return true;
        }

        // If we get here, it means our token consists of one character only. If
        // that single character is alphanumeric, we are a word, otherwise not.
        return first_char.is_alphanumeric();
    }
}

pub struct TokenCollector {
    line_prefix: StyledToken,
    tokens: Vec<StyledToken>,
    bytes_count: usize,
    rendered: bool,
}

impl Style {
    #[must_use]
    pub fn is_inverse(&self) -> bool {
        match self {
            Style::OldInverse | Style::NewInverse | Style::Error => {
                return true;
            }
            _ => {
                return false;
            }
        }
    }

    pub fn inverted(&self) -> Style {
        return match self {
            Style::Old => Style::OldInverse,
            Style::New => Style::NewInverse,
            Style::OldInverse => Style::OldInverse,
            Style::NewInverse => Style::NewInverse,
            Style::Error => Style::Error,
        };
    }

    #[must_use]
    pub fn color<'a>(&self) -> &'a str {
        match self {
            Style::Old => {
                return OLD;
            }
            Style::OldInverse => {
                return OLD;
            }
            Style::New => {
                return NEW;
            }
            Style::NewInverse => {
                return NEW;
            }
            Style::Error => {
                return ERROR;
            }
        }
    }
}

impl TokenCollector {
    #[must_use]
    pub fn create(line_prefix: StyledToken) -> Self {
        return TokenCollector {
            line_prefix,
            tokens: Vec::new(),
            bytes_count: 0,
            rendered: false,
        };
    }

    pub fn push(&mut self, token: StyledToken) {
        self.tokens.push(token);
    }

    #[must_use]
    fn render_row(&self, row: &mut [StyledToken]) -> String {
        let mut rendered = String::new();

        if self.line_prefix.style == Style::New {
            highlight_trailing_whitespace(row);
            highlight_nonleading_tab(row);
        }
        highlight_space_between_words(row);

        // Set inverse from prefix
        let mut is_inverse = self.line_prefix.style.is_inverse();
        if is_inverse {
            rendered.push_str(INVERSE_VIDEO);
        }

        // Set line color from prefix
        let mut color = self.line_prefix.style.color();
        rendered.push_str(self.line_prefix.style.color());

        // Render prefix
        rendered.push_str(&self.line_prefix.token);

        for token in row {
            if token.style.is_inverse() && !is_inverse {
                rendered.push_str(INVERSE_VIDEO);
            }
            if is_inverse && !token.style.is_inverse() {
                rendered.push_str(NOT_INVERSE_VIDEO);
            }
            is_inverse = token.style.is_inverse();

            if token.style.color() != color {
                rendered.push_str(token.style.color());
                color = token.style.color();
            }

            rendered.push_str(&token.token);
        }

        rendered.push_str(NORMAL);

        return rendered;
    }

    /// Render all the tokens into a (most of the time multiline) string
    #[must_use]
    pub fn render(&mut self) -> String {
        assert!(!self.rendered);
        let mut current_row: Vec<StyledToken> = Vec::new();
        let mut rendered = String::new();

        let tokens = std::mem::take(&mut self.tokens);

        for token in tokens {
            self.bytes_count += token.token.len();

            if token.token == "\n" {
                let rendered_row = &self.render_row(&mut current_row);
                rendered.push_str(rendered_row);
                rendered.push('\n');
                current_row.clear();
                continue;
            }

            current_row.push(token);
        }

        if !current_row.is_empty() {
            let rendered_row = &self.render_row(&mut current_row);
            rendered.push_str(rendered_row);
        }

        self.rendered = true;
        return rendered;
    }
}

fn highlight_trailing_whitespace(row: &mut [StyledToken]) {
    for token in row.iter_mut().rev() {
        if !token.is_whitespace() {
            return;
        }

        token.style = Style::Error;
    }
}

fn highlight_nonleading_tab(row: &mut [StyledToken]) {
    let mut token_iter = row.iter_mut();

    // Skip leading TABs
    loop {
        let next = token_iter.next();
        if next.is_none() {
            // Done!
            return;
        }

        let token = next.unwrap();
        if token.token != "\t" {
            // Not a TAB, this means we're out of skipping the leading TABs
            break;
        }
    }

    // Scan the rest of the line for non-leading TABs
    for token in token_iter {
        if token.token != "\t" {
            // Not a TAB, never mind
            continue;
        }

        // Non-leading TAB, mark it!
        token.style = Style::Error;
    }
}

/// Highlight single space between two highlighted words
fn highlight_space_between_words(row: &mut [StyledToken]) {
    enum FoundState {
        Nothing,
        HighlightedWord,
        WordSpace,
    }

    let mut found_state = FoundState::Nothing;
    let mut previous_token: Option<&mut StyledToken> = None;
    for token in row.iter_mut() {
        match found_state {
            FoundState::Nothing => {
                if token.style.is_inverse() && token.is_word() {
                    // Found "Monkey"
                    found_state = FoundState::HighlightedWord;
                }
            }

            FoundState::HighlightedWord => {
                if token.is_whitespace() {
                    // Found "Monkey " (note trailing space)
                    found_state = FoundState::WordSpace;
                } else if token.style.is_inverse() && token.is_word() {
                    found_state = FoundState::HighlightedWord;
                } else {
                    found_state = FoundState::Nothing;
                }
            }

            FoundState::WordSpace => {
                if token.style.is_inverse() && token.is_word() {
                    // Found "Monkey Dance"
                    if let Some(_previous_token) = previous_token {
                        _previous_token.style = _previous_token.style.inverted();
                    }

                    found_state = FoundState::HighlightedWord;
                } else {
                    found_state = FoundState::Nothing;
                }
            }
        }

        previous_token = Some(token);
    }
}

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

    #[cfg(test)]
    use pretty_assertions::assert_eq;

    #[test]
    fn test_basic() {
        let mut test_me = TokenCollector::create(StyledToken {
            token: "+".to_string(),
            style: Style::New,
        });

        test_me.push(StyledToken {
            token: "hej".to_string(),
            style: Style::New,
        });

        test_me.push(StyledToken {
            token: "\n".to_string(),
            style: Style::New,
        });

        let rendered = test_me.render();
        assert_eq!(rendered, format!("{}+hej{}\n", NEW, NORMAL));
    }

    #[test]
    fn test_add_trailing_whitespace() {
        // Just a whitespace
        let mut row = [StyledToken::new(" ".to_string(), Style::New)];
        highlight_trailing_whitespace(&mut row);
        assert_eq!(row, [StyledToken::new(" ".to_string(), Style::Error)]);

        // Trailing whitespace
        let mut row = [
            StyledToken::new("x".to_string(), Style::New),
            StyledToken::new(" ".to_string(), Style::New),
        ];
        highlight_trailing_whitespace(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("x".to_string(), Style::New),
                StyledToken::new(" ".to_string(), Style::Error),
            ]
        );

        // Leading whitespace
        let mut row = [
            StyledToken::new(" ".to_string(), Style::New),
            StyledToken::new("x".to_string(), Style::New),
        ];
        highlight_trailing_whitespace(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new(" ".to_string(), Style::New),
                StyledToken::new("x".to_string(), Style::New),
            ]
        );
    }

    #[test]
    fn test_removed_trailing_whitespace() {
        // It shouldn't be highlighted, just added ones should
        let mut test_me = TokenCollector::create(StyledToken::new("-".to_string(), Style::Old));
        test_me.push(StyledToken::new(" ".to_string(), Style::Old));
        let actual = test_me.render();

        assert_eq!(actual, format!("{}- {}", OLD, NORMAL));
    }

    #[test]
    fn test_add_nonleading_tab() {
        // Trailing TAB
        let mut row = [
            StyledToken::new("x".to_string(), Style::New),
            StyledToken::new("\t".to_string(), Style::New),
        ];
        highlight_nonleading_tab(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("x".to_string(), Style::New),
                StyledToken::new("\t".to_string(), Style::Error),
            ]
        );

        // Middle TAB
        let mut row = [
            StyledToken::new("x".to_string(), Style::New),
            StyledToken::new("\t".to_string(), Style::New),
            StyledToken::new("y".to_string(), Style::New),
        ];
        highlight_nonleading_tab(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("x".to_string(), Style::New),
                StyledToken::new("\t".to_string(), Style::Error),
                StyledToken::new("y".to_string(), Style::New),
            ]
        );

        // Leading TAB (don't highlight)
        let mut row = [
            StyledToken::new("\t".to_string(), Style::New),
            StyledToken::new("x".to_string(), Style::New),
        ];
        highlight_nonleading_tab(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("\t".to_string(), Style::New),
                StyledToken::new("x".to_string(), Style::New),
            ]
        );

        // Single TAB (don't highlight because it is leading)
        let mut row = [StyledToken::new("\t".to_string(), Style::New)];
        highlight_nonleading_tab(&mut row);
        assert_eq!(row, [StyledToken::new("\t".to_string(), Style::New),]);
    }

    #[test]
    fn test_removed_nonleading_tab() {
        // It shouldn't be highlighted, just added ones should
        let mut test_me = TokenCollector::create(StyledToken::new("-".to_string(), Style::Old));
        test_me.push(StyledToken::new("x".to_string(), Style::Old));
        test_me.push(StyledToken::new("\t".to_string(), Style::Old));
        let actual = test_me.render();

        assert_eq!(actual, format!("{}-x\t{}", OLD, NORMAL));
    }

    #[test]
    fn test_highlight_space_between_words() {
        let mut row = [
            StyledToken::new("Monkey".to_string(), Style::NewInverse),
            StyledToken::new(" ".to_string(), Style::New),
            StyledToken::new("Dance".to_string(), Style::NewInverse),
        ];

        highlight_space_between_words(&mut row);

        assert_eq!(
            row,
            [
                StyledToken::new("Monkey".to_string(), Style::NewInverse),
                StyledToken::new(" ".to_string(), Style::NewInverse),
                StyledToken::new("Dance".to_string(), Style::NewInverse),
            ]
        );
    }
}
<commit_msg>More dead code removal<commit_after>use crate::constants::*;

#[derive(Clone, Debug, PartialEq)]
pub enum Style {
    Old,
    OldInverse,
    New,
    NewInverse,
    Error,
}

#[derive(Clone, Debug, PartialEq)]
pub struct StyledToken {
    token: String,
    style: Style,
}

impl StyledToken {
    pub fn new(token: String, style: Style) -> StyledToken {
        return StyledToken { token, style };
    }

    pub fn is_whitespace(&self) -> bool {
        let mut chars_iterator = self.token.chars();
        let first_char = chars_iterator.next().unwrap();
        if chars_iterator.next().is_some() {
            // Multiple chars found in this token, but whitespace will only be
            // one per token.
            return false;
        }

        return first_char.is_whitespace();
    }

    pub fn is_word(&self) -> bool {
        let mut chars_iterator = self.token.chars();
        let first_char = chars_iterator.next().unwrap();
        let second_char = chars_iterator.next();
        if second_char.is_some() {
            // We consist of multiple characters, that means we are a word
            return true;
        }

        // If we get here, it means our token consists of one character only. If
        // that single character is alphanumeric, we are a word, otherwise not.
        return first_char.is_alphanumeric();
    }
}

pub struct TokenCollector {
    line_prefix: StyledToken,
    tokens: Vec<StyledToken>,
    rendered: bool,
}

impl Style {
    #[must_use]
    pub fn is_inverse(&self) -> bool {
        match self {
            Style::OldInverse | Style::NewInverse | Style::Error => {
                return true;
            }
            _ => {
                return false;
            }
        }
    }

    pub fn inverted(&self) -> Style {
        return match self {
            Style::Old => Style::OldInverse,
            Style::New => Style::NewInverse,
            Style::OldInverse => Style::OldInverse,
            Style::NewInverse => Style::NewInverse,
            Style::Error => Style::Error,
        };
    }

    #[must_use]
    pub fn color<'a>(&self) -> &'a str {
        match self {
            Style::Old => {
                return OLD;
            }
            Style::OldInverse => {
                return OLD;
            }
            Style::New => {
                return NEW;
            }
            Style::NewInverse => {
                return NEW;
            }
            Style::Error => {
                return ERROR;
            }
        }
    }
}

impl TokenCollector {
    #[must_use]
    pub fn create(line_prefix: StyledToken) -> Self {
        return TokenCollector {
            line_prefix,
            tokens: Vec::new(),
            rendered: false,
        };
    }

    pub fn push(&mut self, token: StyledToken) {
        self.tokens.push(token);
    }

    #[must_use]
    fn render_row(&self, row: &mut [StyledToken]) -> String {
        let mut rendered = String::new();

        if self.line_prefix.style == Style::New {
            highlight_trailing_whitespace(row);
            highlight_nonleading_tab(row);
        }
        highlight_space_between_words(row);

        // Set inverse from prefix
        let mut is_inverse = self.line_prefix.style.is_inverse();
        if is_inverse {
            rendered.push_str(INVERSE_VIDEO);
        }

        // Set line color from prefix
        let mut color = self.line_prefix.style.color();
        rendered.push_str(self.line_prefix.style.color());

        // Render prefix
        rendered.push_str(&self.line_prefix.token);

        for token in row {
            if token.style.is_inverse() && !is_inverse {
                rendered.push_str(INVERSE_VIDEO);
            }
            if is_inverse && !token.style.is_inverse() {
                rendered.push_str(NOT_INVERSE_VIDEO);
            }
            is_inverse = token.style.is_inverse();

            if token.style.color() != color {
                rendered.push_str(token.style.color());
                color = token.style.color();
            }

            rendered.push_str(&token.token);
        }

        rendered.push_str(NORMAL);

        return rendered;
    }

    /// Render all the tokens into a (most of the time multiline) string
    #[must_use]
    pub fn render(&mut self) -> String {
        assert!(!self.rendered);
        let mut current_row: Vec<StyledToken> = Vec::new();
        let mut rendered = String::new();

        let tokens = std::mem::take(&mut self.tokens);

        for token in tokens {
            if token.token == "\n" {
                let rendered_row = &self.render_row(&mut current_row);
                rendered.push_str(rendered_row);
                rendered.push('\n');
                current_row.clear();
                continue;
            }

            current_row.push(token);
        }

        if !current_row.is_empty() {
            let rendered_row = &self.render_row(&mut current_row);
            rendered.push_str(rendered_row);
        }

        self.rendered = true;
        return rendered;
    }
}

fn highlight_trailing_whitespace(row: &mut [StyledToken]) {
    for token in row.iter_mut().rev() {
        if !token.is_whitespace() {
            return;
        }

        token.style = Style::Error;
    }
}

fn highlight_nonleading_tab(row: &mut [StyledToken]) {
    let mut token_iter = row.iter_mut();

    // Skip leading TABs
    loop {
        let next = token_iter.next();
        if next.is_none() {
            // Done!
            return;
        }

        let token = next.unwrap();
        if token.token != "\t" {
            // Not a TAB, this means we're out of skipping the leading TABs
            break;
        }
    }

    // Scan the rest of the line for non-leading TABs
    for token in token_iter {
        if token.token != "\t" {
            // Not a TAB, never mind
            continue;
        }

        // Non-leading TAB, mark it!
        token.style = Style::Error;
    }
}

/// Highlight single space between two highlighted words
fn highlight_space_between_words(row: &mut [StyledToken]) {
    enum FoundState {
        Nothing,
        HighlightedWord,
        WordSpace,
    }

    let mut found_state = FoundState::Nothing;
    let mut previous_token: Option<&mut StyledToken> = None;
    for token in row.iter_mut() {
        match found_state {
            FoundState::Nothing => {
                if token.style.is_inverse() && token.is_word() {
                    // Found "Monkey"
                    found_state = FoundState::HighlightedWord;
                }
            }

            FoundState::HighlightedWord => {
                if token.is_whitespace() {
                    // Found "Monkey " (note trailing space)
                    found_state = FoundState::WordSpace;
                } else if token.style.is_inverse() && token.is_word() {
                    found_state = FoundState::HighlightedWord;
                } else {
                    found_state = FoundState::Nothing;
                }
            }

            FoundState::WordSpace => {
                if token.style.is_inverse() && token.is_word() {
                    // Found "Monkey Dance"
                    if let Some(_previous_token) = previous_token {
                        _previous_token.style = _previous_token.style.inverted();
                    }

                    found_state = FoundState::HighlightedWord;
                } else {
                    found_state = FoundState::Nothing;
                }
            }
        }

        previous_token = Some(token);
    }
}

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

    #[cfg(test)]
    use pretty_assertions::assert_eq;

    #[test]
    fn test_basic() {
        let mut test_me = TokenCollector::create(StyledToken {
            token: "+".to_string(),
            style: Style::New,
        });

        test_me.push(StyledToken {
            token: "hej".to_string(),
            style: Style::New,
        });

        test_me.push(StyledToken {
            token: "\n".to_string(),
            style: Style::New,
        });

        let rendered = test_me.render();
        assert_eq!(rendered, format!("{}+hej{}\n", NEW, NORMAL));
    }

    #[test]
    fn test_add_trailing_whitespace() {
        // Just a whitespace
        let mut row = [StyledToken::new(" ".to_string(), Style::New)];
        highlight_trailing_whitespace(&mut row);
        assert_eq!(row, [StyledToken::new(" ".to_string(), Style::Error)]);

        // Trailing whitespace
        let mut row = [
            StyledToken::new("x".to_string(), Style::New),
            StyledToken::new(" ".to_string(), Style::New),
        ];
        highlight_trailing_whitespace(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("x".to_string(), Style::New),
                StyledToken::new(" ".to_string(), Style::Error),
            ]
        );

        // Leading whitespace
        let mut row = [
            StyledToken::new(" ".to_string(), Style::New),
            StyledToken::new("x".to_string(), Style::New),
        ];
        highlight_trailing_whitespace(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new(" ".to_string(), Style::New),
                StyledToken::new("x".to_string(), Style::New),
            ]
        );
    }

    #[test]
    fn test_removed_trailing_whitespace() {
        // It shouldn't be highlighted, just added ones should
        let mut test_me = TokenCollector::create(StyledToken::new("-".to_string(), Style::Old));
        test_me.push(StyledToken::new(" ".to_string(), Style::Old));
        let actual = test_me.render();

        assert_eq!(actual, format!("{}- {}", OLD, NORMAL));
    }

    #[test]
    fn test_add_nonleading_tab() {
        // Trailing TAB
        let mut row = [
            StyledToken::new("x".to_string(), Style::New),
            StyledToken::new("\t".to_string(), Style::New),
        ];
        highlight_nonleading_tab(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("x".to_string(), Style::New),
                StyledToken::new("\t".to_string(), Style::Error),
            ]
        );

        // Middle TAB
        let mut row = [
            StyledToken::new("x".to_string(), Style::New),
            StyledToken::new("\t".to_string(), Style::New),
            StyledToken::new("y".to_string(), Style::New),
        ];
        highlight_nonleading_tab(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("x".to_string(), Style::New),
                StyledToken::new("\t".to_string(), Style::Error),
                StyledToken::new("y".to_string(), Style::New),
            ]
        );

        // Leading TAB (don't highlight)
        let mut row = [
            StyledToken::new("\t".to_string(), Style::New),
            StyledToken::new("x".to_string(), Style::New),
        ];
        highlight_nonleading_tab(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("\t".to_string(), Style::New),
                StyledToken::new("x".to_string(), Style::New),
            ]
        );

        // Single TAB (don't highlight because it is leading)
        let mut row = [StyledToken::new("\t".to_string(), Style::New)];
        highlight_nonleading_tab(&mut row);
        assert_eq!(row, [StyledToken::new("\t".to_string(), Style::New),]);
    }

    #[test]
    fn test_removed_nonleading_tab() {
        // It shouldn't be highlighted, just added ones should
        let mut test_me = TokenCollector::create(StyledToken::new("-".to_string(), Style::Old));
        test_me.push(StyledToken::new("x".to_string(), Style::Old));
        test_me.push(StyledToken::new("\t".to_string(), Style::Old));
        let actual = test_me.render();

        assert_eq!(actual, format!("{}-x\t{}", OLD, NORMAL));
    }

    #[test]
    fn test_highlight_space_between_words() {
        let mut row = [
            StyledToken::new("Monkey".to_string(), Style::NewInverse),
            StyledToken::new(" ".to_string(), Style::New),
            StyledToken::new("Dance".to_string(), Style::NewInverse),
        ];

        highlight_space_between_words(&mut row);

        assert_eq!(
            row,
            [
                StyledToken::new("Monkey".to_string(), Style::NewInverse),
                StyledToken::new(" ".to_string(), Style::NewInverse),
                StyledToken::new("Dance".to_string(), Style::NewInverse),
            ]
        );
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#![deny(clippy::all)]

use colored::Colorize;
use signedsource::{sign_file, SIGNING_TOKEN};
use std::collections::HashMap;
use std::fs;
use std::fs::File;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
#[structopt(name = "fixture-tests", about = "Fixture tests")]
struct Options {
    #[structopt(name = "DIR", parse(from_os_str))]
    dirs: Vec<PathBuf>,
}

#[derive(Debug)]
struct TestCase {
    name: String,
    input: Option<PathBuf>,
    expected: Option<PathBuf>,
}

const EXPECTED_EXTENSION: &str = "expected";

fn main() {
    let opt = Options::from_args();

    for dir in opt.dirs {
        let test_name = dir.file_name().unwrap().to_str().unwrap();
        let fixtures_dir = dir.join("fixtures");
        let paths = fs::read_dir(&fixtures_dir)
            .unwrap_or_else(|_| panic!("Fixtures dir does not exist: {:?}", &fixtures_dir));
        let mut test_cases: HashMap<String, TestCase> = HashMap::new();
        for dir_entry in paths {
            let path = dir_entry.unwrap().path();
            if path.extension().is_none() {
                continue;
            }
            let name = sanitize_identifier(path.file_stem().unwrap().to_str().unwrap());
            let mut test_case = test_cases.entry(name.clone()).or_insert_with(|| TestCase {
                name,
                input: None,
                expected: None,
            });
            if path.extension().unwrap() == EXPECTED_EXTENSION {
                if let Some(ref previous) = test_case.expected {
                    panic!("Conflicting fixture name, {:?} and {:?}", previous, path);
                }
                test_case.expected = Some(path);
            } else {
                if let Some(ref previous) = test_case.input {
                    panic!("Conflicting fixture name, {:?} and {:?}", previous, path);
                }
                test_case.input = Some(path);
            }
        }
        for mut test_case in test_cases.values_mut() {
            if test_case.expected.is_none() {
                if let Some(ref input) = test_case.input {
                    let mut expected = input.clone();
                    expected.set_extension(EXPECTED_EXTENSION);
                    File::create(&expected)
                        .unwrap()
                        .write_all(
                            "\x40nocommit\nRun snapshot tests with UPDATE_SNAPSHOTS=1 to update this new file.\n"
                            .as_bytes(),
                        )
                        .unwrap();
                    test_case.expected = Some(expected);
                }
            }
        }
        let mut test_cases: Vec<(_, _)> = test_cases.into_iter().collect();
        test_cases.sort_by_key(|entry| entry.0.to_owned());

        let test_cases = test_cases
            .into_iter()
            .map(|(_, test_case)| {
                let test_case_name = &test_case.name;
                format!(
                    r#"#[test]
fn {0}() {{
    let input = include_str!("{1}/fixtures/{2}");
    let expected = include_str!("{1}/fixtures/{3}");
    test_fixture(transform_fixture, "{2}", "{1}/fixtures/{3}", input, expected);
}}"#,
                    test_case.name,
                    &test_name,
                    test_case
                        .input
                        .unwrap_or_else(|| panic!(
                            "Expected input for test {:?} to exist",
                            test_case_name
                        ))
                        .file_name()
                        .and_then(|x| x.to_str())
                        .unwrap(),
                    test_case
                        .expected
                        .unwrap_or_else(|| panic!(
                            "Expected output for test {:?} to exist",
                            test_case_name
                        ))
                        .file_name()
                        .and_then(|x| x.to_str())
                        .unwrap()
                )
            })
            .collect::<Vec<_>>()
            .join("\n\n");

        let mut file = File::create(
            dir.parent()
                .unwrap()
                .join(format!("{}_test.rs", &test_name)),
        )
        .unwrap();

        // Slightly hacky way to find out if these fixture tests are in the OSS
        // directory. This test should work on GitHub and in the internal repo.
        let is_oss = dir
            .components()
            .any(|comp| comp == std::path::Component::Normal("crates".as_ref()));

        let header = if is_oss {
            format!(
                "/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * {signing_token}
 */
",
                signing_token = SIGNING_TOKEN,
            )
        } else {
            format!(
                "// {signing_token}
// Generated by $ cargo run -p fixture-tests -- {dir_name}
",
                signing_token = SIGNING_TOKEN,
                dir_name = dir.display(),
            )
        };

        let content = format!(
            "{header}
mod {test_name};

use {test_name}::transform_fixture;
use fixture_tests::test_fixture;

{test_cases}
",
            header = header,
            test_name = &test_name,
            test_cases = test_cases,
        );
        file.write_all(sign_file(&content).as_bytes()).unwrap();
        check_targets_file(&dir);
    }
}

fn check_targets_file(test_dir: &Path) {
    let targets_path = test_dir.parent().unwrap().parent().unwrap().join("TARGETS");
    let targets_content = match std::fs::read_to_string(&targets_path) {
        Ok(content) => content,
        Err(_) => return,
    };

    let expected_substr = format!(
        "\"tests/{}_test.rs\"",
        test_dir.file_stem().unwrap().to_str().unwrap()
    );

    if !targets_content.contains(&expected_substr) {
        eprintln!(
            "{}",
            format!(
                "WARNING: expected {:?} to contain substring {}",
                targets_path, expected_substr
            )
            .yellow()
        );
    }
}

fn sanitize_identifier(input: &str) -> String {
    input
        .chars()
        .map(|chr| match chr {
            'a'..='z' | '0'..='9' | '_' => chr,
            'A'..='Z' => chr.to_ascii_lowercase(),
            _ => '_',
        })
        .collect()
}
<commit_msg>update copyright header<commit_after>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#![deny(clippy::all)]

use colored::Colorize;
use signedsource::{sign_file, SIGNING_TOKEN};
use std::collections::HashMap;
use std::fs;
use std::fs::File;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
#[structopt(name = "fixture-tests", about = "Fixture tests")]
struct Options {
    #[structopt(name = "DIR", parse(from_os_str))]
    dirs: Vec<PathBuf>,
}

#[derive(Debug)]
struct TestCase {
    name: String,
    input: Option<PathBuf>,
    expected: Option<PathBuf>,
}

const EXPECTED_EXTENSION: &str = "expected";

fn main() {
    let opt = Options::from_args();

    for dir in opt.dirs {
        let test_name = dir.file_name().unwrap().to_str().unwrap();
        let fixtures_dir = dir.join("fixtures");
        let paths = fs::read_dir(&fixtures_dir)
            .unwrap_or_else(|_| panic!("Fixtures dir does not exist: {:?}", &fixtures_dir));
        let mut test_cases: HashMap<String, TestCase> = HashMap::new();
        for dir_entry in paths {
            let path = dir_entry.unwrap().path();
            if path.extension().is_none() {
                continue;
            }
            let name = sanitize_identifier(path.file_stem().unwrap().to_str().unwrap());
            let mut test_case = test_cases.entry(name.clone()).or_insert_with(|| TestCase {
                name,
                input: None,
                expected: None,
            });
            if path.extension().unwrap() == EXPECTED_EXTENSION {
                if let Some(ref previous) = test_case.expected {
                    panic!("Conflicting fixture name, {:?} and {:?}", previous, path);
                }
                test_case.expected = Some(path);
            } else {
                if let Some(ref previous) = test_case.input {
                    panic!("Conflicting fixture name, {:?} and {:?}", previous, path);
                }
                test_case.input = Some(path);
            }
        }
        for mut test_case in test_cases.values_mut() {
            if test_case.expected.is_none() {
                if let Some(ref input) = test_case.input {
                    let mut expected = input.clone();
                    expected.set_extension(EXPECTED_EXTENSION);
                    File::create(&expected)
                        .unwrap()
                        .write_all(
                            "\x40nocommit\nRun snapshot tests with UPDATE_SNAPSHOTS=1 to update this new file.\n"
                            .as_bytes(),
                        )
                        .unwrap();
                    test_case.expected = Some(expected);
                }
            }
        }
        let mut test_cases: Vec<(_, _)> = test_cases.into_iter().collect();
        test_cases.sort_by_key(|entry| entry.0.to_owned());

        let test_cases = test_cases
            .into_iter()
            .map(|(_, test_case)| {
                let test_case_name = &test_case.name;
                format!(
                    r#"#[test]
fn {0}() {{
    let input = include_str!("{1}/fixtures/{2}");
    let expected = include_str!("{1}/fixtures/{3}");
    test_fixture(transform_fixture, "{2}", "{1}/fixtures/{3}", input, expected);
}}"#,
                    test_case.name,
                    &test_name,
                    test_case
                        .input
                        .unwrap_or_else(|| panic!(
                            "Expected input for test {:?} to exist",
                            test_case_name
                        ))
                        .file_name()
                        .and_then(|x| x.to_str())
                        .unwrap(),
                    test_case
                        .expected
                        .unwrap_or_else(|| panic!(
                            "Expected output for test {:?} to exist",
                            test_case_name
                        ))
                        .file_name()
                        .and_then(|x| x.to_str())
                        .unwrap()
                )
            })
            .collect::<Vec<_>>()
            .join("\n\n");

        let mut file = File::create(
            dir.parent()
                .unwrap()
                .join(format!("{}_test.rs", &test_name)),
        )
        .unwrap();

        // Slightly hacky way to find out if these fixture tests are in the OSS
        // directory. This test should work on GitHub and in the internal repo.
        let is_oss = dir
            .components()
            .any(|comp| comp == std::path::Component::Normal("crates".as_ref()));

        let header = if is_oss {
            format!(
                "/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * {signing_token}
 */
",
                signing_token = SIGNING_TOKEN,
            )
        } else {
            format!(
                "// {signing_token}
// Generated by $ cargo run -p fixture-tests -- {dir_name}
",
                signing_token = SIGNING_TOKEN,
                dir_name = dir.display(),
            )
        };

        let content = format!(
            "{header}
mod {test_name};

use {test_name}::transform_fixture;
use fixture_tests::test_fixture;

{test_cases}
",
            header = header,
            test_name = &test_name,
            test_cases = test_cases,
        );
        file.write_all(sign_file(&content).as_bytes()).unwrap();
        check_targets_file(&dir);
    }
}

fn check_targets_file(test_dir: &Path) {
    let targets_path = test_dir.parent().unwrap().parent().unwrap().join("TARGETS");
    let targets_content = match std::fs::read_to_string(&targets_path) {
        Ok(content) => content,
        Err(_) => return,
    };

    let expected_substr = format!(
        "\"tests/{}_test.rs\"",
        test_dir.file_stem().unwrap().to_str().unwrap()
    );

    if !targets_content.contains(&expected_substr) {
        eprintln!(
            "{}",
            format!(
                "WARNING: expected {:?} to contain substring {}",
                targets_path, expected_substr
            )
            .yellow()
        );
    }
}

fn sanitize_identifier(input: &str) -> String {
    input
        .chars()
        .map(|chr| match chr {
            'a'..='z' | '0'..='9' | '_' => chr,
            'A'..='Z' => chr.to_ascii_lowercase(),
            _ => '_',
        })
        .collect()
}
<|endoftext|>


<commit_before>use crate::{api_client::{Client,
                         PortableText,
                         TabularText},
            common::ui::{Status,
                         UIWriter,
                         UI},
            error::{Error,
                    Result},
            PRODUCT,
            VERSION};

pub async fn start(ui: &mut UI,
                   bldr_url: &str,
                   token: &str,
                   origin: &str,
                   to_json: bool)
                   -> Result<()> {
    let api_client = Client::new(bldr_url, PRODUCT, VERSION, None).map_err(Error::APIClient)?;

    match api_client.origin_info(token, origin).await {
        Ok(resp) => {
            if to_json {
                // match as_json(&resp) {
                match resp.as_json() {
                    Ok(body) => {
                        println!("{}", body);
                        Ok(())
                    }
                    Err(e) => {
                        ui.fatal(format!("Failed to deserialize into json! {:?}.", e))?;
                        Err(Error::from(e))
                    }
                }
            } else {
                ui.status(Status::Discovering, "origin metadata".to_string())?;
                println!("Origin [{}]:", origin);
                match resp.as_tabbed() {
                    Ok(body) => {
                        println!("{}", body);
                        Ok(())
                    }
                    Err(e) => {
                        ui.fatal(format!("Failed to format origin metadata! {:?}.", e))?;
                        Err(Error::from(e))
                    }
                }
            }
        }
        Err(e) => {
            ui.fatal(format!("Failed to retrieve origin metadata! {:?}.", e))?;
            Err(Error::from(e))
        }
    }
}
<commit_msg>removing vestigial comment<commit_after>use crate::{api_client::{Client,
                         PortableText,
                         TabularText},
            common::ui::{Status,
                         UIWriter,
                         UI},
            error::{Error,
                    Result},
            PRODUCT,
            VERSION};

pub async fn start(ui: &mut UI,
                   bldr_url: &str,
                   token: &str,
                   origin: &str,
                   to_json: bool)
                   -> Result<()> {
    let api_client = Client::new(bldr_url, PRODUCT, VERSION, None).map_err(Error::APIClient)?;

    match api_client.origin_info(token, origin).await {
        Ok(resp) => {
            if to_json {
                match resp.as_json() {
                    Ok(body) => {
                        println!("{}", body);
                        Ok(())
                    }
                    Err(e) => {
                        ui.fatal(format!("Failed to deserialize into json! {:?}.", e))?;
                        Err(Error::from(e))
                    }
                }
            } else {
                ui.status(Status::Discovering, "origin metadata".to_string())?;
                println!("Origin [{}]:", origin);
                match resp.as_tabbed() {
                    Ok(body) => {
                        println!("{}", body);
                        Ok(())
                    }
                    Err(e) => {
                        ui.fatal(format!("Failed to format origin metadata! {:?}.", e))?;
                        Err(Error::from(e))
                    }
                }
            }
        }
        Err(e) => {
            ui.fatal(format!("Failed to retrieve origin metadata! {:?}.", e))?;
            Err(Error::from(e))
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015-2017 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! Domain name associated types, such as Name and Label.

mod label;
mod name;
mod try_parse_ip;
pub mod usage;

pub use self::label::{IntoLabel, Label};
pub use self::name::{IntoName, Name};
pub use self::try_parse_ip::TryParseIp;
<commit_msg>Expose LabelIter<commit_after>// Copyright 2015-2017 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! Domain name associated types, such as Name and Label.

mod label;
mod name;
mod try_parse_ip;
pub mod usage;

pub use self::label::{IntoLabel, Label};
pub use self::name::{IntoName, LabelIter, Name};
pub use self::try_parse_ip::TryParseIp;
<|endoftext|>


<commit_before>//! Implementation of the `#[simd_test]` macro
//!
//! This macro expands to a `#[test]` function which tests the local machine
//! for the appropriate cfg before calling the inner test function.

extern crate proc_macro;
extern crate proc_macro2;
#[macro_use]
extern crate quote;

use proc_macro2::{Ident, Literal, Span, TokenStream, TokenTree};
use quote::ToTokens;
use std::env;

fn string(s: &str) -> TokenTree {
    Literal::string(s).into()
}

#[proc_macro_attribute]
pub fn simd_test(
    attr: proc_macro::TokenStream,
    item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let tokens = TokenStream::from(attr).into_iter().collect::<Vec<_>>();
    if tokens.len() != 3 {
        panic!("expected #[simd_test(enable = \"feature\")]");
    }
    match &tokens[0] {
        TokenTree::Ident(tt) if *tt == "enable" => {}
        _ => panic!("expected #[simd_test(enable = \"feature\")]"),
    }
    match &tokens[1] {
        TokenTree::Punct(tt) if tt.as_char() == '=' => {}
        _ => panic!("expected #[simd_test(enable = \"feature\")]"),
    }
    let enable_feature = match &tokens[2] {
        TokenTree::Literal(tt) => tt.to_string(),
        _ => panic!("expected #[simd_test(enable = \"feature\")]"),
    };
    let enable_feature = enable_feature
        .trim_start_matches('"')
        .trim_end_matches('"');
    let target_features: Vec<String> = enable_feature
        .replace('+', "")
        .split(',')
        .map(String::from)
        .collect();

    let enable_feature = string(enable_feature);
    let item = TokenStream::from(item);
    let name = find_name(item.clone());

    let name: TokenStream = name
        .to_string()
        .parse()
        .unwrap_or_else(|_| panic!("failed to parse name: {}", name.to_string()));

    let target = env::var("TARGET").expect("TARGET environment variable should be set for rustc");
    let mut force_test = false;
    let macro_test = match target
        .split('-')
        .next()
        .unwrap_or_else(|| panic!("target triple contained no \"-\": {}", target))
    {
        "i686" | "x86_64" | "i586" => "is_x86_feature_detected",
        "arm" | "armv7" => "is_arm_feature_detected",
        "aarch64" => "is_aarch64_feature_detected",
        "powerpc" | "powerpcle" => "is_powerpc_feature_detected",
        "powerpc64" | "powerpc64le" => "is_powerpc64_feature_detected",
        "mips" | "mipsel" => {
            // FIXME:
            // On MIPS CI run-time feature detection always returns false due
            // to this qemu bug: https://bugs.launchpad.net/qemu/+bug/1754372
            //
            // This is a workaround to force the MIPS tests to always run on
            // CI.
            force_test = true;
            "is_mips_feature_detected"
        }
        "mips64" | "mips64el" => {
            // FIXME: see above
            force_test = true;
            "is_mips64_feature_detected"
        }
        t => panic!("unknown target: {}", t),
    };
    let macro_test = Ident::new(macro_test, Span::call_site());

    let mut cfg_target_features = TokenStream::new();
    for feature in target_features {
        let q = quote_spanned! {
            proc_macro2::Span::call_site() =>
            #macro_test!(#feature) &&
        };
        q.to_tokens(&mut cfg_target_features);
    }
    let q = quote! { true };
    q.to_tokens(&mut cfg_target_features);

    let test_norun = std::env::var("STDSIMD_TEST_NORUN").is_ok();
    let maybe_ignore = if test_norun {
        quote! { #[ignore] }
    } else {
        TokenStream::new()
    };

    let ret: TokenStream = quote_spanned! {
        proc_macro2::Span::call_site() =>
        #[allow(non_snake_case)]
        #[test]
        #maybe_ignore
        fn #name() {
            if #force_test | (#cfg_target_features) {
                return unsafe { #name() };
            } else {
                ::stdsimd_test::assert_skip_test_ok(stringify!(#name));
            }

            #[target_feature(enable = #enable_feature)]
            #item
        }
    };
    ret.into()
}

fn find_name(item: TokenStream) -> Ident {
    let mut tokens = item.into_iter();
    while let Some(tok) = tokens.next() {
        if let TokenTree::Ident(word) = tok {
            if word == "fn" {
                break;
            }
        }
    }

    match tokens.next() {
        Some(TokenTree::Ident(word)) => word,
        _ => panic!("failed to find function name"),
    }
}
<commit_msg>Rerun rustfmt<commit_after>//! Implementation of the `#[simd_test]` macro
//!
//! This macro expands to a `#[test]` function which tests the local machine
//! for the appropriate cfg before calling the inner test function.

extern crate proc_macro;
extern crate proc_macro2;
#[macro_use]
extern crate quote;

use proc_macro2::{Ident, Literal, Span, TokenStream, TokenTree};
use quote::ToTokens;
use std::env;

fn string(s: &str) -> TokenTree {
    Literal::string(s).into()
}

#[proc_macro_attribute]
pub fn simd_test(
    attr: proc_macro::TokenStream,
    item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let tokens = TokenStream::from(attr).into_iter().collect::<Vec<_>>();
    if tokens.len() != 3 {
        panic!("expected #[simd_test(enable = \"feature\")]");
    }
    match &tokens[0] {
        TokenTree::Ident(tt) if *tt == "enable" => {}
        _ => panic!("expected #[simd_test(enable = \"feature\")]"),
    }
    match &tokens[1] {
        TokenTree::Punct(tt) if tt.as_char() == '=' => {}
        _ => panic!("expected #[simd_test(enable = \"feature\")]"),
    }
    let enable_feature = match &tokens[2] {
        TokenTree::Literal(tt) => tt.to_string(),
        _ => panic!("expected #[simd_test(enable = \"feature\")]"),
    };
    let enable_feature = enable_feature.trim_start_matches('"').trim_end_matches('"');
    let target_features: Vec<String> = enable_feature
        .replace('+', "")
        .split(',')
        .map(String::from)
        .collect();

    let enable_feature = string(enable_feature);
    let item = TokenStream::from(item);
    let name = find_name(item.clone());

    let name: TokenStream = name
        .to_string()
        .parse()
        .unwrap_or_else(|_| panic!("failed to parse name: {}", name.to_string()));

    let target = env::var("TARGET").expect("TARGET environment variable should be set for rustc");
    let mut force_test = false;
    let macro_test = match target
        .split('-')
        .next()
        .unwrap_or_else(|| panic!("target triple contained no \"-\": {}", target))
    {
        "i686" | "x86_64" | "i586" => "is_x86_feature_detected",
        "arm" | "armv7" => "is_arm_feature_detected",
        "aarch64" => "is_aarch64_feature_detected",
        "powerpc" | "powerpcle" => "is_powerpc_feature_detected",
        "powerpc64" | "powerpc64le" => "is_powerpc64_feature_detected",
        "mips" | "mipsel" => {
            // FIXME:
            // On MIPS CI run-time feature detection always returns false due
            // to this qemu bug: https://bugs.launchpad.net/qemu/+bug/1754372
            //
            // This is a workaround to force the MIPS tests to always run on
            // CI.
            force_test = true;
            "is_mips_feature_detected"
        }
        "mips64" | "mips64el" => {
            // FIXME: see above
            force_test = true;
            "is_mips64_feature_detected"
        }
        t => panic!("unknown target: {}", t),
    };
    let macro_test = Ident::new(macro_test, Span::call_site());

    let mut cfg_target_features = TokenStream::new();
    for feature in target_features {
        let q = quote_spanned! {
            proc_macro2::Span::call_site() =>
            #macro_test!(#feature) &&
        };
        q.to_tokens(&mut cfg_target_features);
    }
    let q = quote! { true };
    q.to_tokens(&mut cfg_target_features);

    let test_norun = std::env::var("STDSIMD_TEST_NORUN").is_ok();
    let maybe_ignore = if test_norun {
        quote! { #[ignore] }
    } else {
        TokenStream::new()
    };

    let ret: TokenStream = quote_spanned! {
        proc_macro2::Span::call_site() =>
        #[allow(non_snake_case)]
        #[test]
        #maybe_ignore
        fn #name() {
            if #force_test | (#cfg_target_features) {
                return unsafe { #name() };
            } else {
                ::stdsimd_test::assert_skip_test_ok(stringify!(#name));
            }

            #[target_feature(enable = #enable_feature)]
            #item
        }
    };
    ret.into()
}

fn find_name(item: TokenStream) -> Ident {
    let mut tokens = item.into_iter();
    while let Some(tok) = tokens.next() {
        if let TokenTree::Ident(word) = tok {
            if word == "fn" {
                break;
            }
        }
    }

    match tokens.next() {
        Some(TokenTree::Ident(word)) => word,
        _ => panic!("failed to find function name"),
    }
}
<|endoftext|>