<commit_before>use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::quote;
use syn::spanned::Spanned;

#[derive(Clone, Copy, PartialEq)]
enum RuntimeFlavor {
    CurrentThread,
    Threaded,
}

impl RuntimeFlavor {
    fn from_str(s: &str) -> Result<RuntimeFlavor, String> {
        match s {
            "current_thread" => Ok(RuntimeFlavor::CurrentThread),
            "multi_thread" => Ok(RuntimeFlavor::Threaded),
            "single_thread" => Err("The single threaded runtime flavor is called `current_thread`.".to_string()),
            "basic_scheduler" => Err("The `basic_scheduler` runtime flavor has been renamed to `current_thread`.".to_string()),
            "threaded_scheduler" => Err("The `threaded_scheduler` runtime flavor has been renamed to `multi_thread`.".to_string()),
            _ => Err(format!("No such runtime flavor `{}`. The runtime flavors are `current_thread` and `multi_thread`.", s)),
        }
    }
}

struct FinalConfig {
    flavor: RuntimeFlavor,
    worker_threads: Option<usize>,
}

struct Configuration {
    rt_multi_thread_available: bool,
    default_flavor: RuntimeFlavor,
    flavor: Option<RuntimeFlavor>,
    worker_threads: Option<(usize, Span)>,
}

impl Configuration {
    fn new(is_test: bool, rt_multi_thread: bool) -> Self {
        Configuration {
            rt_multi_thread_available: rt_multi_thread,
            default_flavor: match is_test {
                true => RuntimeFlavor::CurrentThread,
                false => RuntimeFlavor::Threaded,
            },
            flavor: None,
            worker_threads: None,
        }
    }

    fn set_flavor(&mut self, runtime: syn::Lit, span: Span) -> Result<(), syn::Error> {
        if self.flavor.is_some() {
            return Err(syn::Error::new(span, "`flavor` set multiple times."));
        }

        let runtime_str = parse_string(runtime, span, "flavor")?;
        let runtime =
            RuntimeFlavor::from_str(&runtime_str).map_err(|err| syn::Error::new(span, err))?;
        self.flavor = Some(runtime);
        Ok(())
    }

    fn set_worker_threads(
        &mut self,
        worker_threads: syn::Lit,
        span: Span,
    ) -> Result<(), syn::Error> {
        if self.worker_threads.is_some() {
            return Err(syn::Error::new(
                span,
                "`worker_threads` set multiple times.",
            ));
        }

        let worker_threads = parse_int(worker_threads, span, "worker_threads")?;
        if worker_threads == 0 {
            return Err(syn::Error::new(span, "`worker_threads` may not be 0."));
        }
        self.worker_threads = Some((worker_threads, span));
        Ok(())
    }

    fn build(&self) -> Result<FinalConfig, syn::Error> {
        let flavor = self.flavor.unwrap_or(self.default_flavor);
        use RuntimeFlavor::*;
        match (flavor, self.worker_threads) {
            (CurrentThread, Some((_, worker_threads_span))) => Err(syn::Error::new(
                worker_threads_span,
                "The `worker_threads` option requires the `multi_thread` runtime flavor.",
            )),
            (CurrentThread, None) => Ok(FinalConfig {
                flavor,
                worker_threads: None,
            }),
            (Threaded, worker_threads) if self.rt_multi_thread_available => Ok(FinalConfig {
                flavor,
                worker_threads: worker_threads.map(|(val, _span)| val),
            }),
            (Threaded, _) => {
                let msg = if self.flavor.is_none() {
                    "The default runtime flavor is `multi_thread`, but the `rt-multi-thread` feature is disabled."
                } else {
                    "The runtime flavor `multi_thread` requires the `rt-multi-thread` feature."
                };
                Err(syn::Error::new(Span::call_site(), msg))
            }
        }
    }
}

fn parse_int(int: syn::Lit, span: Span, field: &str) -> Result<usize, syn::Error> {
    match int {
        syn::Lit::Int(lit) => match lit.base10_parse::<usize>() {
            Ok(value) => Ok(value),
            Err(e) => Err(syn::Error::new(
                span,
                format!("Failed to parse {} as integer: {}", field, e),
            )),
        },
        _ => Err(syn::Error::new(
            span,
            format!("Failed to parse {} as integer.", field),
        )),
    }
}

fn parse_string(int: syn::Lit, span: Span, field: &str) -> Result<String, syn::Error> {
    match int {
        syn::Lit::Str(s) => Ok(s.value()),
        syn::Lit::Verbatim(s) => Ok(s.to_string()),
        _ => Err(syn::Error::new(
            span,
            format!("Failed to parse {} as string.", field),
        )),
    }
}

fn parse_knobs(
    mut input: syn::ItemFn,
    args: syn::AttributeArgs,
    is_test: bool,
    rt_multi_thread: bool,
) -> Result<TokenStream, syn::Error> {
    let sig = &mut input.sig;
    let body = &input.block;
    let attrs = &input.attrs;
    let vis = input.vis;

    if sig.asyncness.is_none() {
        let msg = "the async keyword is missing from the function declaration";
        return Err(syn::Error::new_spanned(sig.fn_token, msg));
    }

    sig.asyncness = None;

    let macro_name = if is_test {
        "tokio::test"
    } else {
        "tokio::main"
    };
    let mut config = Configuration::new(is_test, rt_multi_thread);

    for arg in args {
        match arg {
            syn::NestedMeta::Meta(syn::Meta::NameValue(namevalue)) => {
                let ident = namevalue.path.get_ident();
                if ident.is_none() {
                    let msg = "Must have specified ident";
                    return Err(syn::Error::new_spanned(namevalue, msg));
                }
                match ident.unwrap().to_string().to_lowercase().as_str() {
                    "worker_threads" => {
                        config.set_worker_threads(namevalue.lit.clone(), namevalue.span())?;
                    }
                    "flavor" => {
                        config.set_flavor(namevalue.lit.clone(), namevalue.span())?;
                    }
                    "core_threads" => {
                        let msg = "Attribute `core_threads` is renamed to `worker_threads`";
                        return Err(syn::Error::new_spanned(namevalue, msg));
                    }
                    name => {
                        let msg = format!("Unknown attribute {} is specified; expected one of: `flavor`, `worker_threads`", name);
                        return Err(syn::Error::new_spanned(namevalue, msg));
                    }
                }
            }
            syn::NestedMeta::Meta(syn::Meta::Path(path)) => {
                let ident = path.get_ident();
                if ident.is_none() {
                    let msg = "Must have specified ident";
                    return Err(syn::Error::new_spanned(path, msg));
                }
                let name = ident.unwrap().to_string().to_lowercase();
                let msg = match name.as_str() {
                    "threaded_scheduler" | "multi_thread" => {
                        format!("Set the runtime flavor with #[{}(flavor = \"multi_thread\")].", macro_name)
                    },
                    "basic_scheduler" | "current_thread" | "single_threaded" => {
                        format!("Set the runtime flavor with #[{}(flavor = \"current_thread\")].", macro_name)
                    },
                    "flavor" | "worker_threads" => {
                        format!("The `{}` attribute requires an argument.", name)
                    },
                    name => {
                        format!("Unknown attribute {} is specified; expected one of: `flavor`, `worker_threads`", name)
                    },
                };
                return Err(syn::Error::new_spanned(path, msg));
            }
            other => {
                return Err(syn::Error::new_spanned(
                    other,
                    "Unknown attribute inside the macro",
                ));
            }
        }
    }

    let config = config.build()?;

    let mut rt = match config.flavor {
        RuntimeFlavor::CurrentThread => quote! {
            tokio::runtime::Builder::new_current_thread()
        },
        RuntimeFlavor::Threaded => quote! {
            tokio::runtime::Builder::new_multi_thread()
        },
    };
    if let Some(v) = config.worker_threads {
        rt = quote! { #rt.worker_threads(#v) };
    }

    let header = {
        if is_test {
            quote! {
                #[::core::prelude::v1::test]
            }
        } else {
            quote! {}
        }
    };

    let result = quote! {
        #header
        #(#attrs)*
        #vis #sig {
            #rt
                .enable_all()
                .build()
                .unwrap()
                .block_on(async { #body })
        }
    };

    Ok(result.into())
}

#[cfg(not(test))] // Work around for rust-lang/rust#62127
pub(crate) fn main(args: TokenStream, item: TokenStream, rt_multi_thread: bool) -> TokenStream {
    let input = syn::parse_macro_input!(item as syn::ItemFn);
    let args = syn::parse_macro_input!(args as syn::AttributeArgs);

    if input.sig.ident == "main" && !input.sig.inputs.is_empty() {
        let msg = "the main function cannot accept arguments";
        return syn::Error::new_spanned(&input.sig.ident, msg)
            .to_compile_error()
            .into();
    }

    parse_knobs(input, args, false, rt_multi_thread).unwrap_or_else(|e| e.to_compile_error().into())
}

pub(crate) fn test(args: TokenStream, item: TokenStream, rt_multi_thread: bool) -> TokenStream {
    let input = syn::parse_macro_input!(item as syn::ItemFn);
    let args = syn::parse_macro_input!(args as syn::AttributeArgs);

    for attr in &input.attrs {
        if attr.path.is_ident("test") {
            let msg = "second test attribute is supplied";
            return syn::Error::new_spanned(&attr, msg)
                .to_compile_error()
                .into();
        }
    }

    if !input.sig.inputs.is_empty() {
        let msg = "the test function cannot accept arguments";
        return syn::Error::new_spanned(&input.sig.inputs, msg)
            .to_compile_error()
            .into();
    }

    parse_knobs(input, args, true, rt_multi_thread).unwrap_or_else(|e| e.to_compile_error().into())
}
<commit_msg>macros: fix rustfmt on 1.48.0 (#3160)<commit_after>use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::quote;
use syn::spanned::Spanned;

#[derive(Clone, Copy, PartialEq)]
enum RuntimeFlavor {
    CurrentThread,
    Threaded,
}

impl RuntimeFlavor {
    fn from_str(s: &str) -> Result<RuntimeFlavor, String> {
        match s {
            "current_thread" => Ok(RuntimeFlavor::CurrentThread),
            "multi_thread" => Ok(RuntimeFlavor::Threaded),
            "single_thread" => Err("The single threaded runtime flavor is called `current_thread`.".to_string()),
            "basic_scheduler" => Err("The `basic_scheduler` runtime flavor has been renamed to `current_thread`.".to_string()),
            "threaded_scheduler" => Err("The `threaded_scheduler` runtime flavor has been renamed to `multi_thread`.".to_string()),
            _ => Err(format!("No such runtime flavor `{}`. The runtime flavors are `current_thread` and `multi_thread`.", s)),
        }
    }
}

struct FinalConfig {
    flavor: RuntimeFlavor,
    worker_threads: Option<usize>,
}

struct Configuration {
    rt_multi_thread_available: bool,
    default_flavor: RuntimeFlavor,
    flavor: Option<RuntimeFlavor>,
    worker_threads: Option<(usize, Span)>,
}

impl Configuration {
    fn new(is_test: bool, rt_multi_thread: bool) -> Self {
        Configuration {
            rt_multi_thread_available: rt_multi_thread,
            default_flavor: match is_test {
                true => RuntimeFlavor::CurrentThread,
                false => RuntimeFlavor::Threaded,
            },
            flavor: None,
            worker_threads: None,
        }
    }

    fn set_flavor(&mut self, runtime: syn::Lit, span: Span) -> Result<(), syn::Error> {
        if self.flavor.is_some() {
            return Err(syn::Error::new(span, "`flavor` set multiple times."));
        }

        let runtime_str = parse_string(runtime, span, "flavor")?;
        let runtime =
            RuntimeFlavor::from_str(&runtime_str).map_err(|err| syn::Error::new(span, err))?;
        self.flavor = Some(runtime);
        Ok(())
    }

    fn set_worker_threads(
        &mut self,
        worker_threads: syn::Lit,
        span: Span,
    ) -> Result<(), syn::Error> {
        if self.worker_threads.is_some() {
            return Err(syn::Error::new(
                span,
                "`worker_threads` set multiple times.",
            ));
        }

        let worker_threads = parse_int(worker_threads, span, "worker_threads")?;
        if worker_threads == 0 {
            return Err(syn::Error::new(span, "`worker_threads` may not be 0."));
        }
        self.worker_threads = Some((worker_threads, span));
        Ok(())
    }

    fn build(&self) -> Result<FinalConfig, syn::Error> {
        let flavor = self.flavor.unwrap_or(self.default_flavor);
        use RuntimeFlavor::*;
        match (flavor, self.worker_threads) {
            (CurrentThread, Some((_, worker_threads_span))) => Err(syn::Error::new(
                worker_threads_span,
                "The `worker_threads` option requires the `multi_thread` runtime flavor.",
            )),
            (CurrentThread, None) => Ok(FinalConfig {
                flavor,
                worker_threads: None,
            }),
            (Threaded, worker_threads) if self.rt_multi_thread_available => Ok(FinalConfig {
                flavor,
                worker_threads: worker_threads.map(|(val, _span)| val),
            }),
            (Threaded, _) => {
                let msg = if self.flavor.is_none() {
                    "The default runtime flavor is `multi_thread`, but the `rt-multi-thread` feature is disabled."
                } else {
                    "The runtime flavor `multi_thread` requires the `rt-multi-thread` feature."
                };
                Err(syn::Error::new(Span::call_site(), msg))
            }
        }
    }
}

fn parse_int(int: syn::Lit, span: Span, field: &str) -> Result<usize, syn::Error> {
    match int {
        syn::Lit::Int(lit) => match lit.base10_parse::<usize>() {
            Ok(value) => Ok(value),
            Err(e) => Err(syn::Error::new(
                span,
                format!("Failed to parse {} as integer: {}", field, e),
            )),
        },
        _ => Err(syn::Error::new(
            span,
            format!("Failed to parse {} as integer.", field),
        )),
    }
}

fn parse_string(int: syn::Lit, span: Span, field: &str) -> Result<String, syn::Error> {
    match int {
        syn::Lit::Str(s) => Ok(s.value()),
        syn::Lit::Verbatim(s) => Ok(s.to_string()),
        _ => Err(syn::Error::new(
            span,
            format!("Failed to parse {} as string.", field),
        )),
    }
}

fn parse_knobs(
    mut input: syn::ItemFn,
    args: syn::AttributeArgs,
    is_test: bool,
    rt_multi_thread: bool,
) -> Result<TokenStream, syn::Error> {
    let sig = &mut input.sig;
    let body = &input.block;
    let attrs = &input.attrs;
    let vis = input.vis;

    if sig.asyncness.is_none() {
        let msg = "the async keyword is missing from the function declaration";
        return Err(syn::Error::new_spanned(sig.fn_token, msg));
    }

    sig.asyncness = None;

    let macro_name = if is_test {
        "tokio::test"
    } else {
        "tokio::main"
    };
    let mut config = Configuration::new(is_test, rt_multi_thread);

    for arg in args {
        match arg {
            syn::NestedMeta::Meta(syn::Meta::NameValue(namevalue)) => {
                let ident = namevalue.path.get_ident();
                if ident.is_none() {
                    let msg = "Must have specified ident";
                    return Err(syn::Error::new_spanned(namevalue, msg));
                }
                match ident.unwrap().to_string().to_lowercase().as_str() {
                    "worker_threads" => {
                        config.set_worker_threads(namevalue.lit.clone(), namevalue.span())?;
                    }
                    "flavor" => {
                        config.set_flavor(namevalue.lit.clone(), namevalue.span())?;
                    }
                    "core_threads" => {
                        let msg = "Attribute `core_threads` is renamed to `worker_threads`";
                        return Err(syn::Error::new_spanned(namevalue, msg));
                    }
                    name => {
                        let msg = format!("Unknown attribute {} is specified; expected one of: `flavor`, `worker_threads`", name);
                        return Err(syn::Error::new_spanned(namevalue, msg));
                    }
                }
            }
            syn::NestedMeta::Meta(syn::Meta::Path(path)) => {
                let ident = path.get_ident();
                if ident.is_none() {
                    let msg = "Must have specified ident";
                    return Err(syn::Error::new_spanned(path, msg));
                }
                let name = ident.unwrap().to_string().to_lowercase();
                let msg = match name.as_str() {
                    "threaded_scheduler" | "multi_thread" => {
                        format!(
                            "Set the runtime flavor with #[{}(flavor = \"multi_thread\")].",
                            macro_name
                        )
                    }
                    "basic_scheduler" | "current_thread" | "single_threaded" => {
                        format!(
                            "Set the runtime flavor with #[{}(flavor = \"current_thread\")].",
                            macro_name
                        )
                    }
                    "flavor" | "worker_threads" => {
                        format!("The `{}` attribute requires an argument.", name)
                    }
                    name => {
                        format!("Unknown attribute {} is specified; expected one of: `flavor`, `worker_threads`", name)
                    }
                };
                return Err(syn::Error::new_spanned(path, msg));
            }
            other => {
                return Err(syn::Error::new_spanned(
                    other,
                    "Unknown attribute inside the macro",
                ));
            }
        }
    }

    let config = config.build()?;

    let mut rt = match config.flavor {
        RuntimeFlavor::CurrentThread => quote! {
            tokio::runtime::Builder::new_current_thread()
        },
        RuntimeFlavor::Threaded => quote! {
            tokio::runtime::Builder::new_multi_thread()
        },
    };
    if let Some(v) = config.worker_threads {
        rt = quote! { #rt.worker_threads(#v) };
    }

    let header = {
        if is_test {
            quote! {
                #[::core::prelude::v1::test]
            }
        } else {
            quote! {}
        }
    };

    let result = quote! {
        #header
        #(#attrs)*
        #vis #sig {
            #rt
                .enable_all()
                .build()
                .unwrap()
                .block_on(async { #body })
        }
    };

    Ok(result.into())
}

#[cfg(not(test))] // Work around for rust-lang/rust#62127
pub(crate) fn main(args: TokenStream, item: TokenStream, rt_multi_thread: bool) -> TokenStream {
    let input = syn::parse_macro_input!(item as syn::ItemFn);
    let args = syn::parse_macro_input!(args as syn::AttributeArgs);

    if input.sig.ident == "main" && !input.sig.inputs.is_empty() {
        let msg = "the main function cannot accept arguments";
        return syn::Error::new_spanned(&input.sig.ident, msg)
            .to_compile_error()
            .into();
    }

    parse_knobs(input, args, false, rt_multi_thread).unwrap_or_else(|e| e.to_compile_error().into())
}

pub(crate) fn test(args: TokenStream, item: TokenStream, rt_multi_thread: bool) -> TokenStream {
    let input = syn::parse_macro_input!(item as syn::ItemFn);
    let args = syn::parse_macro_input!(args as syn::AttributeArgs);

    for attr in &input.attrs {
        if attr.path.is_ident("test") {
            let msg = "second test attribute is supplied";
            return syn::Error::new_spanned(&attr, msg)
                .to_compile_error()
                .into();
        }
    }

    if !input.sig.inputs.is_empty() {
        let msg = "the test function cannot accept arguments";
        return syn::Error::new_spanned(&input.sig.inputs, msg)
            .to_compile_error()
            .into();
    }

    parse_knobs(input, args, true, rt_multi_thread).unwrap_or_else(|e| e.to_compile_error().into())
}
<|endoftext|>


<commit_before>use fallible_iterator::FallibleIterator;
use postgres_protocol::message::backend::DataRowBody;
use std::fmt;
use std::ops::Range;

use crate::proto;
use crate::row::sealed::Sealed;
use crate::stmt::Column;
use crate::types::{FromSql, WrongType};
use crate::Error;

mod sealed {
    pub trait Sealed {}
}

/// A trait implemented by types that can index into columns of a row.
///
/// This cannot be implemented outside of this crate.
pub trait RowIndex: Sealed {
    fn __idx(&self, columns: &[Column]) -> Option<usize>;
}

impl Sealed for usize {}

impl RowIndex for usize {
    #[inline]
    fn __idx(&self, columns: &[Column]) -> Option<usize> {
        if *self >= columns.len() {
            None
        } else {
            Some(*self)
        }
    }
}

impl Sealed for str {}

impl RowIndex for str {
    #[inline]
    fn __idx(&self, columns: &[Column]) -> Option<usize> {
        if let Some(idx) = columns.iter().position(|d| d.name() == self) {
            return Some(idx);
        };

        // FIXME ASCII-only case insensitivity isn't really the right thing to
        // do. Postgres itself uses a dubious wrapper around tolower and JDBC
        // uses the US locale.
        columns
            .iter()
            .position(|d| d.name().eq_ignore_ascii_case(self))
    }
}

impl<'a, T> Sealed for &'a T where T: ?Sized + Sealed {}

impl<'a, T> RowIndex for &'a T
where
    T: ?Sized + RowIndex,
{
    #[inline]
    fn __idx(&self, columns: &[Column]) -> Option<usize> {
        T::__idx(*self, columns)
    }
}

pub struct Row {
    statement: proto::Statement,
    body: DataRowBody,
    ranges: Vec<Option<Range<usize>>>,
}

impl Row {
    #[allow(clippy::new_ret_no_self)]
    pub(crate) fn new(statement: proto::Statement, body: DataRowBody) -> Result<Row, Error> {
        let ranges = body.ranges().collect().map_err(Error::parse)?;
        Ok(Row {
            statement,
            body,
            ranges,
        })
    }

    pub fn columns(&self) -> &[Column] {
        self.statement.columns()
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub fn len(&self) -> usize {
        self.columns().len()
    }

    pub fn get<'a, I, T>(&'a self, idx: I) -> T
    where
        I: RowIndex + fmt::Display,
        T: FromSql<'a>,
    {
        match self.get_inner(&idx) {
            Ok(Some(ok)) => ok,
            Err(err) => panic!("error retrieving column {}: {}", idx, err),
            Ok(None) => panic!("no such column {}", idx),
        }
    }

    pub fn try_get<'a, I, T>(&'a self, idx: I) -> Result<Option<T>, Error>
    where
        I: RowIndex,
        T: FromSql<'a>,
    {
        self.get_inner(&idx)
    }

    fn get_inner<'a, I, T>(&'a self, idx: &I) -> Result<Option<T>, Error>
    where
        I: RowIndex,
        T: FromSql<'a>,
    {
        let idx = match idx.__idx(self.columns()) {
            Some(idx) => idx,
            None => return Ok(None),
        };

        let ty = self.columns()[idx].type_();
        if !T::accepts(ty) {
            return Err(Error::from_sql(Box::new(WrongType::new(ty.clone()))));
        }

        let buf = self.ranges[idx].clone().map(|r| &self.body.buffer()[r]);
        let value = FromSql::from_sql_nullable(ty, buf);
        value.map(Some).map_err(Error::from_sql)
    }
}
<commit_msg>Hide trait method<commit_after>use fallible_iterator::FallibleIterator;
use postgres_protocol::message::backend::DataRowBody;
use std::fmt;
use std::ops::Range;

use crate::proto;
use crate::row::sealed::Sealed;
use crate::stmt::Column;
use crate::types::{FromSql, WrongType};
use crate::Error;

mod sealed {
    pub trait Sealed {}
}

/// A trait implemented by types that can index into columns of a row.
///
/// This cannot be implemented outside of this crate.
pub trait RowIndex: Sealed {
    #[doc(hidden)]
    fn __idx(&self, columns: &[Column]) -> Option<usize>;
}

impl Sealed for usize {}

impl RowIndex for usize {
    #[inline]
    fn __idx(&self, columns: &[Column]) -> Option<usize> {
        if *self >= columns.len() {
            None
        } else {
            Some(*self)
        }
    }
}

impl Sealed for str {}

impl RowIndex for str {
    #[inline]
    fn __idx(&self, columns: &[Column]) -> Option<usize> {
        if let Some(idx) = columns.iter().position(|d| d.name() == self) {
            return Some(idx);
        };

        // FIXME ASCII-only case insensitivity isn't really the right thing to
        // do. Postgres itself uses a dubious wrapper around tolower and JDBC
        // uses the US locale.
        columns
            .iter()
            .position(|d| d.name().eq_ignore_ascii_case(self))
    }
}

impl<'a, T> Sealed for &'a T where T: ?Sized + Sealed {}

impl<'a, T> RowIndex for &'a T
where
    T: ?Sized + RowIndex,
{
    #[inline]
    fn __idx(&self, columns: &[Column]) -> Option<usize> {
        T::__idx(*self, columns)
    }
}

pub struct Row {
    statement: proto::Statement,
    body: DataRowBody,
    ranges: Vec<Option<Range<usize>>>,
}

impl Row {
    #[allow(clippy::new_ret_no_self)]
    pub(crate) fn new(statement: proto::Statement, body: DataRowBody) -> Result<Row, Error> {
        let ranges = body.ranges().collect().map_err(Error::parse)?;
        Ok(Row {
            statement,
            body,
            ranges,
        })
    }

    pub fn columns(&self) -> &[Column] {
        self.statement.columns()
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub fn len(&self) -> usize {
        self.columns().len()
    }

    pub fn get<'a, I, T>(&'a self, idx: I) -> T
    where
        I: RowIndex + fmt::Display,
        T: FromSql<'a>,
    {
        match self.get_inner(&idx) {
            Ok(Some(ok)) => ok,
            Err(err) => panic!("error retrieving column {}: {}", idx, err),
            Ok(None) => panic!("no such column {}", idx),
        }
    }

    pub fn try_get<'a, I, T>(&'a self, idx: I) -> Result<Option<T>, Error>
    where
        I: RowIndex,
        T: FromSql<'a>,
    {
        self.get_inner(&idx)
    }

    fn get_inner<'a, I, T>(&'a self, idx: &I) -> Result<Option<T>, Error>
    where
        I: RowIndex,
        T: FromSql<'a>,
    {
        let idx = match idx.__idx(self.columns()) {
            Some(idx) => idx,
            None => return Ok(None),
        };

        let ty = self.columns()[idx].type_();
        if !T::accepts(ty) {
            return Err(Error::from_sql(Box::new(WrongType::new(ty.clone()))));
        }

        let buf = self.ranges[idx].clone().map(|r| &self.body.buffer()[r]);
        let value = FromSql::from_sql_nullable(ty, buf);
        value.map(Some).map_err(Error::from_sql)
    }
}
<|endoftext|>


<commit_before>use std::iter::Peekable;
use std::str::Chars;

/// Token types that our language admits.
///
/// All the token types that our little language will need. As it is a very
/// simple language, it doesn't have many. The lexer takes an input and has a
/// token iterator as the output.
///
/// The traits are mostly for tests.
#[derive(Debug, PartialEq)]
pub enum Token {
    /// For anything that we don't recognize.
    Illegal,
    /// Last token, when the input has ended.
    EOF,

    /// Any word: a variable name, a type name...
    Ident(String),

    /// Left parenthesis.
    ParL,
    /// Right parenthesis.
    ParR,
    /// The ':' character.
    Colon,
    /// The ';' character.
    Semicolon,
    /// The ',' character.
    Comma,

    /// The only keyword we have in the language.
    Type,
}

/// The lexer in our language.
///
/// The lexer, also known as tokenizer, transforms the input text into tokens.
pub struct Lexer<'a> {
    input: Peekable<Chars<'a>>,
}

impl<'a> Lexer<'a> {
    /// Create a new lexer.
    ///
    /// To build the lexer, you feed it a `str` with the code. Then you can use
    /// the lexer as a normal `Iterator`, which iterates over [`Token`s][1].
    ///
    /// # Examples
    ///
    ///     use simcom::lexer::{Lexer, Token};
    ///
    ///     let mut tokens = Lexer::new(": tipo");
    ///     assert_eq!(tokens.next().unwrap(), Token::Colon);
    ///     assert_eq!(tokens.next().unwrap(), Token::Type);
    ///     assert_eq!(tokens.next(), None);
    ///
    /// [1]: enum.Token.html
    pub fn new(input: &'a str) -> Lexer {
        Lexer { input: input.chars().peekable() }
    }

    /// The next char in the input, advances the internal iterator.
    fn read_char(&mut self) -> Option<char> {
        self.input.next()
    }

    /// The next char in the input. *doesn't* advance the internal iterator.
    fn peek_char(&mut self) -> Option<&char> {
        self.input.peek()
    }

    /// If an alphabetic char was found, keep reading chars to build a
    /// identifier. Finally, look if it was a keyword.
    fn read_identifier(&mut self, ch: char) -> Token {
        let content = {
            // Since in ::next_token we need to call ::read_char the first
            // char was consumed, so we add it here.
            let mut content = String::new();
            content.push(ch);

            // Keep building the string with allowed characters.
            while let Some(&ch) = self.peek_char() {
                if !(ch.is_alphabetic() || ch.is_digit(10)) {
                    break;
                }

                // We call ::unwrap because we already made sure there is an
                // element with the ::peek above.
                content.push(self.read_char().unwrap());
            }

            content
        };

        // Match the identifier to all the known keywords to see if it is one
        // of them. Otherwise, return a normal identifier.
        match &content[..] {
            "tipo" => Token::Type,
            _ => Token::Ident(content),
        }
    }

    /// Advance the internal iterator when we find whitespace.
    fn consume_whitespace(&mut self) {
        while let Some(&ch) = self.peek_char() {
            if ch.is_whitespace() {
                self.read_char();
            } else {
                break;
            }
        }
    }

    /// The basis for the iterator, matches the characters to Tokens.
    fn next_token(&mut self) -> Token {
        self.consume_whitespace();

        if let Some(ch) = self.read_char() {
            match ch {
                '(' => Token::ParL,
                ')' => Token::ParR,
                ':' => Token::Colon,
                ';' => Token::Semicolon,
                ',' => Token::Comma,
                '\0' => Token::EOF,
                _ => if ch.is_alphabetic() {
                    // As ::read_identifier already advances the iterator, we
                    // can safely perform an early return.
                    return self.read_identifier(ch);
                } else {
                    Token::Illegal
                }
            }
        // If the internal iterator has given us a None, that means there are no
        // characters left. In other words, EOF was reached.
        } else {
            Token::EOF
        }
    }
}

impl<'a> Iterator for Lexer<'a> {
    type Item = Token;

    fn next(&mut self) -> Option<Self::Item> {
        match self.next_token() {
            Token::EOF => None,
            x => Some(x),
        }
    }
}
<commit_msg>Acknowledge that out lexer is too simple. Won't change, though.<commit_after>//! The lexer module.
//!
//! The simpler implementation of a lexer I could think of. It only takes a
//! stream of characters and tansforms it into a tokens one.
//!
//! It doesn't keep track of the current line or column. In a real compiler that
//! information is crucial when you write something wrong and don't know where.

use std::iter::Peekable;
use std::str::Chars;

/// Token types that our language admits.
///
/// All the token types that our little language will need. As it is a very
/// simple language, it doesn't have many. The lexer takes an input and has a
/// token iterator as the output.
///
/// The traits are mostly for tests.
#[derive(Debug, PartialEq)]
pub enum Token {
    /// For anything that we don't recognize.
    Illegal,
    /// Last token, when the input has ended.
    EOF,

    /// Any word: a variable name, a type name...
    Ident(String),

    /// Left parenthesis.
    ParL,
    /// Right parenthesis.
    ParR,
    /// The ':' character.
    Colon,
    /// The ';' character.
    Semicolon,
    /// The ',' character.
    Comma,

    /// The only keyword we have in the language.
    Type,
}

/// The lexer in our language.
///
/// The lexer, also known as tokenizer, transforms the input text into tokens.
pub struct Lexer<'a> {
    input: Peekable<Chars<'a>>,
}

impl<'a> Lexer<'a> {
    /// Create a new lexer.
    ///
    /// To build the lexer, you feed it a `str` with the code. Then you can use
    /// the lexer as a normal `Iterator`, which iterates over [`Token`s][1].
    ///
    /// # Examples
    ///
    ///     use simcom::lexer::{Lexer, Token};
    ///
    ///     let mut tokens = Lexer::new(": tipo");
    ///     assert_eq!(tokens.next().unwrap(), Token::Colon);
    ///     assert_eq!(tokens.next().unwrap(), Token::Type);
    ///     assert_eq!(tokens.next(), None);
    ///
    /// [1]: enum.Token.html
    pub fn new(input: &'a str) -> Lexer {
        Lexer { input: input.chars().peekable() }
    }

    /// The next char in the input, advances the internal iterator.
    fn read_char(&mut self) -> Option<char> {
        self.input.next()
    }

    /// The next char in the input. *doesn't* advance the internal iterator.
    fn peek_char(&mut self) -> Option<&char> {
        self.input.peek()
    }

    /// If an alphabetic char was found, keep reading chars to build a
    /// identifier. Finally, look if it was a keyword.
    fn read_identifier(&mut self, ch: char) -> Token {
        let content = {
            // Since in ::next_token we need to call ::read_char the first
            // char was consumed, so we add it here.
            let mut content = String::new();
            content.push(ch);

            // Keep building the string with allowed characters.
            while let Some(&ch) = self.peek_char() {
                if !(ch.is_alphabetic() || ch.is_digit(10)) {
                    break;
                }

                // We call ::unwrap because we already made sure there is an
                // element with the ::peek above.
                content.push(self.read_char().unwrap());
            }

            content
        };

        // Match the identifier to all the known keywords to see if it is one
        // of them. Otherwise, return a normal identifier.
        match &content[..] {
            "tipo" => Token::Type,
            _ => Token::Ident(content),
        }
    }

    /// Advance the internal iterator when we find whitespace.
    fn consume_whitespace(&mut self) {
        while let Some(&ch) = self.peek_char() {
            if ch.is_whitespace() {
                self.read_char();
            } else {
                break;
            }
        }
    }

    /// The basis for the iterator, matches the characters to Tokens.
    fn next_token(&mut self) -> Token {
        self.consume_whitespace();

        if let Some(ch) = self.read_char() {
            match ch {
                '(' => Token::ParL,
                ')' => Token::ParR,
                ':' => Token::Colon,
                ';' => Token::Semicolon,
                ',' => Token::Comma,
                '\0' => Token::EOF,
                _ => if ch.is_alphabetic() {
                    // As ::read_identifier already advances the iterator, we
                    // can safely perform an early return.
                    return self.read_identifier(ch);
                } else {
                    Token::Illegal
                }
            }
        // If the internal iterator has given us a None, that means there are no
        // characters left. In other words, EOF was reached.
        } else {
            Token::EOF
        }
    }
}

impl<'a> Iterator for Lexer<'a> {
    type Item = Token;

    fn next(&mut self) -> Option<Self::Item> {
        match self.next_token() {
            Token::EOF => None,
            x => Some(x),
        }
    }
}
<|endoftext|>


<commit_before>pub use self::token::Token;
pub use self::token::Category;
use std::cmp::min;

pub mod token;
pub mod implementations;

pub struct StateFunction(fn(&mut Lexer) -> Option<StateFunction>);

pub struct Lexer {
    data: String,
    char_count: usize,
    token_start: usize,
    token_position: usize,
    tokens: Vec<Token>,
}

pub fn new(data: &str) -> Lexer {
    Lexer{
      data: data.to_string(),
      char_count: data.chars().count(),
      token_start: 0,
      token_position: 0,
      tokens: vec![]
    }
}

impl Lexer {
    pub fn advance(&mut self) {
        if self.has_more_data() {
            self.token_position += 1;
        }
    }

    pub fn has_more_data(&self) -> bool {
        self.token_position < self.char_count
    }

    pub fn tokenize(&mut self, category: Category) {
        if self.token_start != self.token_position {
            let token = Token{
                lexeme: self.data.slice_chars(self.token_start, self.token_position).to_string(),
                category: category,
            };
            self.tokens.push(token);
            self.token_start = self.token_position;
        }
    }

    pub fn tokenize_next(&mut self, amount: usize, category: Category) {
        self.tokenize(Category::Text);
        self.token_position = min(self.token_position + amount, self.char_count);
        self.tokenize(category);
    }
}

mod tests {
    use super::new;
    use super::token::Token;
    use super::token::Category;

    #[test]
    fn new_initializes_correctly_with_unicode_data() {
        let lexer_data = "différent";
        let lexer = new(lexer_data);
        assert_eq!(lexer.data, lexer_data);
        assert_eq!(lexer.char_count, 9);
        assert_eq!(lexer.token_start, 0);
        assert_eq!(lexer.token_position, 0);
        assert_eq!(lexer.tokens, vec![]);
    }

    #[test]
    fn advance_increments_the_cursor_by_one() {
        let lexer_data = "élégant";
        let mut lexer = new(lexer_data);
        lexer.advance();
        assert_eq!(lexer.token_position, 1);
        lexer.advance();
        assert_eq!(lexer.token_position, 2);
    }

    #[test]
    fn advance_stops_when_there_is_no_more_data() {
        let lexer_data = "élégant";
        let mut lexer = new(lexer_data);

        // Try to go beyond the last character.
        for _ in 0..lexer.char_count {
            lexer.advance();
        }

        assert_eq!(lexer.token_position, lexer.char_count);
    }

    #[test]
    fn has_more_data_works() {
        let lexer_data = "él";
        let mut lexer = new(lexer_data);

        lexer.advance();
        assert!(lexer.has_more_data());

        lexer.advance();
        assert_eq!(lexer.has_more_data(), false);
    }

    #[test]
    fn tokenize_advances_token_start_to_cursor() {
        let lexer_data = "élégant";
        let mut lexer = new(lexer_data);
        lexer.advance();
        lexer.advance();
        lexer.tokenize(Category::Text);

        assert_eq!(lexer.token_start, 2);
    }

    #[test]
    fn tokenize_creates_the_correct_token() {
        let lexer_data = "élégant";
        let mut lexer = new(lexer_data);
        lexer.advance();
        lexer.advance();
        lexer.tokenize(Category::Text);

        let token = lexer.tokens.pop().unwrap();
        let expected_token = Token{ lexeme: "él".to_string(), category: Category::Text};
        assert_eq!(token, expected_token);
    }

    #[test]
    fn tokenize_does_nothing_if_range_is_empty() {
        let lexer_data = "élégant";
        let mut lexer = new(lexer_data);
        lexer.tokenize(Category::Text);

        assert_eq!(lexer.tokens.len(), 0);
        assert_eq!(lexer.token_start, 0);
        assert_eq!(lexer.token_position, 0);
    }

    #[test]
    fn tokenize_next_tokenizes_previous_data_as_text() {
        let lexer_data = "élégant";
        let mut lexer = new(lexer_data);
        lexer.advance();
        lexer.advance();
        lexer.tokenize_next(1, Category::Keyword);

        let token = lexer.tokens.remove(0);
        let expected_token = Token{ lexeme: "él".to_string(), category: Category::Text};
        assert_eq!(token, expected_token);
    }

    #[test]
    fn tokenize_next_tokenizes_next_x_chars() {
        let lexer_data = "élégant";
        let mut lexer = new(lexer_data);
        lexer.advance();
        lexer.advance();
        lexer.tokenize_next(5, Category::Keyword);

        let token = lexer.tokens.pop().unwrap();
        let expected_token = Token{ lexeme: "égant".to_string(), category: Category::Keyword};
        assert_eq!(token, expected_token);
    }

    #[test]
    fn tokenize_next_takes_at_most_what_is_left() {
        let lexer_data = "élégant";
        let mut lexer = new(lexer_data);
        lexer.advance();
        lexer.advance();
        lexer.tokenize_next(15, Category::Keyword);

        let token = lexer.tokens.pop().unwrap();
        let expected_token = Token{ lexeme: "égant".to_string(), category: Category::Keyword};
        assert_eq!(token, expected_token);
    }
}
<commit_msg>Implement current_char lexer method.<commit_after>pub use self::token::Token;
pub use self::token::Category;
use std::cmp::min;

pub mod token;
pub mod implementations;

pub struct StateFunction(fn(&mut Lexer) -> Option<StateFunction>);

pub struct Lexer {
    data: String,
    char_count: usize,
    token_start: usize,
    token_position: usize,
    tokens: Vec<Token>,
}

pub fn new(data: &str) -> Lexer {
    Lexer{
      data: data.to_string(),
      char_count: data.chars().count(),
      token_start: 0,
      token_position: 0,
      tokens: vec![]
    }
}

impl Lexer {
    pub fn advance(&mut self) {
        if self.has_more_data() {
            self.token_position += 1;
        }
    }

    pub fn has_more_data(&self) -> bool {
        self.token_position < self.char_count
    }

    pub fn current_char(&self) -> Option<char> {
        if self.has_more_data() {
            Some(self.data.chars().nth(self.token_position).unwrap())
        } else {
            None
        }
    }

    pub fn tokenize(&mut self, category: Category) {
        if self.token_start != self.token_position {
            let token = Token{
                lexeme: self.data.slice_chars(self.token_start, self.token_position).to_string(),
                category: category,
            };
            self.tokens.push(token);
            self.token_start = self.token_position;
        }
    }

    pub fn tokenize_next(&mut self, amount: usize, category: Category) {
        self.tokenize(Category::Text);
        self.token_position = min(self.token_position + amount, self.char_count);
        self.tokenize(category);
    }
}

mod tests {
    use super::new;
    use super::token::Token;
    use super::token::Category;

    #[test]
    fn new_initializes_correctly_with_unicode_data() {
        let lexer_data = "différent";
        let lexer = new(lexer_data);
        assert_eq!(lexer.data, lexer_data);
        assert_eq!(lexer.char_count, 9);
        assert_eq!(lexer.token_start, 0);
        assert_eq!(lexer.token_position, 0);
        assert_eq!(lexer.tokens, vec![]);
    }

    #[test]
    fn advance_increments_the_cursor_by_one() {
        let lexer_data = "élégant";
        let mut lexer = new(lexer_data);
        lexer.advance();
        assert_eq!(lexer.token_position, 1);
        lexer.advance();
        assert_eq!(lexer.token_position, 2);
    }

    #[test]
    fn advance_stops_when_there_is_no_more_data() {
        let lexer_data = "élégant";
        let mut lexer = new(lexer_data);

        // Try to go beyond the last character.
        for _ in 0..lexer.char_count {
            lexer.advance();
        }

        assert_eq!(lexer.token_position, lexer.char_count);
    }

    #[test]
    fn has_more_data_works() {
        let lexer_data = "él";
        let mut lexer = new(lexer_data);

        lexer.advance();
        assert!(lexer.has_more_data());

        lexer.advance();
        assert_eq!(lexer.has_more_data(), false);
    }

    #[test]
    fn current_char_returns_the_char_at_token_position() {
        let lexer_data = "él";
        let mut lexer = new(lexer_data);

        assert_eq!(lexer.current_char().unwrap(), 'é');
    }

    #[test]
    fn current_char_returns_none_if_at_the_end() {
        let lexer_data = "él";
        let mut lexer = new(lexer_data);
        lexer.advance();
        lexer.advance();

        assert_eq!(lexer.current_char(), None);
    }

    #[test]
    fn tokenize_advances_token_start_to_cursor() {
        let lexer_data = "élégant";
        let mut lexer = new(lexer_data);
        lexer.advance();
        lexer.advance();
        lexer.tokenize(Category::Text);

        assert_eq!(lexer.token_start, 2);
    }

    #[test]
    fn tokenize_creates_the_correct_token() {
        let lexer_data = "élégant";
        let mut lexer = new(lexer_data);
        lexer.advance();
        lexer.advance();
        lexer.tokenize(Category::Text);

        let token = lexer.tokens.pop().unwrap();
        let expected_token = Token{ lexeme: "él".to_string(), category: Category::Text};
        assert_eq!(token, expected_token);
    }

    #[test]
    fn tokenize_does_nothing_if_range_is_empty() {
        let lexer_data = "élégant";
        let mut lexer = new(lexer_data);
        lexer.tokenize(Category::Text);

        assert_eq!(lexer.tokens.len(), 0);
        assert_eq!(lexer.token_start, 0);
        assert_eq!(lexer.token_position, 0);
    }

    #[test]
    fn tokenize_next_tokenizes_previous_data_as_text() {
        let lexer_data = "élégant";
        let mut lexer = new(lexer_data);
        lexer.advance();
        lexer.advance();
        lexer.tokenize_next(1, Category::Keyword);

        let token = lexer.tokens.remove(0);
        let expected_token = Token{ lexeme: "él".to_string(), category: Category::Text};
        assert_eq!(token, expected_token);
    }

    #[test]
    fn tokenize_next_tokenizes_next_x_chars() {
        let lexer_data = "élégant";
        let mut lexer = new(lexer_data);
        lexer.advance();
        lexer.advance();
        lexer.tokenize_next(5, Category::Keyword);

        let token = lexer.tokens.pop().unwrap();
        let expected_token = Token{ lexeme: "égant".to_string(), category: Category::Keyword};
        assert_eq!(token, expected_token);
    }

    #[test]
    fn tokenize_next_takes_at_most_what_is_left() {
        let lexer_data = "élégant";
        let mut lexer = new(lexer_data);
        lexer.advance();
        lexer.advance();
        lexer.tokenize_next(15, Category::Keyword);

        let token = lexer.tokens.pop().unwrap();
        let expected_token = Token{ lexeme: "égant".to_string(), category: Category::Keyword};
        assert_eq!(token, expected_token);
    }
}
<|endoftext|>


<commit_before>use actix::{Actor, Addr, Context, System};

struct MyActor;

impl Actor for MyActor {
    type Context = Context<Self>;

    fn started(&mut self, ctx: &mut Self::Context) {
        println!("I am alive");
        System::current().stop();
    }
}

fn main() {
    let system = System::new("test");
    let addr = MyActor.start();
    system.run();
}
<commit_msg>Added example for subscribers<commit_after>#[macro_use] extern crate actix;

use actix::{Actor, Addr, Context, System};
use actix::prelude::*;

struct MyActor;

impl Actor for MyActor {
    type Context = Context<Self>;

    fn started(&mut self, ctx: &mut Self::Context) {
        println!("I am alive");
        System::current().stop();
    }
}

#[derive(Message)]
struct Signal(usize);

#[derive(Message)]
struct Subscribe(pub Recipient<Signal>);

struct ProcessSignals  {
    subscribers: Vec<Recipient<Signal>>,
}

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

impl ProcessSignals {
    fn send_signal(&mut self, sig: usize) {
        for subscr in &self.subscribers {
            subscr.do_send(Signal(sig));
        }
    }
}

impl Handler<Subscribe>  for ProcessSignals {
    type Result = ();
    fn handle(&mut self, msg: Subscribe, _: &mut Self::Context) {
        self.subscribers.push(msg.0);
    }
}

fn main() {
    let system = System::new("test");
    let addr = MyActor.start();
    system.run();
}
<|endoftext|>


<commit_before>// Compiles the shaders used internally by some commands

use std::env;
use std::ffi::OsStr;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;

fn main() {
    let pd = env::var("CARGO_MANIFEST_DIR").unwrap();
    let target = env::var("TARGET").unwrap();
    let os = if target.ends_with("ios") {
        "ios"
    } else if target.ends_with("darwin") {
        "darwin"
    } else {
        panic!("unsupported target {}", target)
    };
    let arch = &target[..target.chars().position(|c| c == '-').unwrap()];

    let sdk_name = match (os, arch) {
        ("ios", "aarch64") => "iphoneos",
        ("ios", "armv7s") | ("ios", "armv7") => panic!("32-bit iOS does not have metal support"),
        ("ios", "i386") | ("ios", "x86_64") => panic!("iOS simulator does not have metal support"),
        ("darwin", _) => "macosx",
        _ => panic!("unsupported target {}", target),
    };

    let project_dir = Path::new(&pd);
    let shader_dir = project_dir.join("shaders");
    println!("cargo:rerun-if-changed={}", shader_dir.to_str().unwrap());

    let od = env::var("OUT_DIR").unwrap();
    let out_dir = Path::new(&od);
    let out_lib = out_dir.join("gfx_shaders.metallib");

    // Find all .metal files _at the top level only_
    let shader_files = fs::read_dir(&shader_dir)
        .expect("could not open shader directory")
        .filter_map(|entry| {
            let entry = entry.expect("error reading shader directory entry");
            let path = entry.path();
            match path.extension().and_then(OsStr::to_str) {
                Some("metal") => Some(path),
                _ => None,
            }
        });

    // Compile all the metal files into OUT_DIR
    let mut compiled_shader_files: Vec<PathBuf> = Vec::new();
    for shader_path in shader_files.into_iter() {
        println!("cargo:rerun-if-changed={}", shader_path.to_str().unwrap());

        let mut out_path = out_dir.join(shader_path.file_name().unwrap());
        out_path.set_extension("air");

        let status = Command::new("xcrun")
            .args(&["-sdk", sdk_name, "metal", "-c"])
            .arg(shader_path.as_os_str())
            .arg("-o")
            .arg(out_path.as_os_str())
            .status()
            .expect("failed to execute metal compiler");

        if !status.success() {
            // stdout is linked to parent, so more detailed message will have been output from `metal`
            panic!("shader compilation failed");
        }

        compiled_shader_files.push(out_path);
    }

    // Link all the compiled files into a single library
    let status = Command::new("xcrun")
        .args(&["-sdk", sdk_name, "metallib"])
        .args(compiled_shader_files.iter().map(|p| p.as_os_str()))
        .arg("-o")
        .arg(out_lib.as_os_str())
        .status()
        .expect("failed to execute metal library builder");

    if !status.success() {
        panic!("shader library build failed");
    }
}
<commit_msg>[mtl] the backend metal shaders by default get built with minimum requirements in mind<commit_after>// Compiles the shaders used internally by some commands

use std::env;
use std::ffi::OsStr;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;

fn main() {
    let pd = env::var("CARGO_MANIFEST_DIR").unwrap();
    let target = env::var("TARGET").unwrap();
    let os = if target.ends_with("ios") {
        "ios"
    } else if target.ends_with("darwin") {
        "darwin"
    } else {
        panic!("unsupported target {}", target)
    };
    let arch = &target[..target.chars().position(|c| c == '-').unwrap()];

    let (sdk_name, platform_args): (_, &[_]) = match (os, arch) {
        ("ios", "aarch64") => ("iphoneos", &["-mios-version-min=8.0"]),
        ("ios", "armv7s") | ("ios", "armv7") => panic!("32-bit iOS does not have metal support"),
        ("ios", "i386") | ("ios", "x86_64") => panic!("iOS simulator does not have metal support"),
        ("darwin", _) => ("macosx", &["-mmacosx-version-min=10.11"]),
        _ => panic!("unsupported target {}", target),
    };

    let project_dir = Path::new(&pd);
    let shader_dir = project_dir.join("shaders");
    println!("cargo:rerun-if-changed={}", shader_dir.to_str().unwrap());

    let od = env::var("OUT_DIR").unwrap();
    let out_dir = Path::new(&od);
    let out_lib = out_dir.join("gfx_shaders.metallib");

    // Find all .metal files _at the top level only_
    let shader_files = fs::read_dir(&shader_dir)
        .expect("could not open shader directory")
        .filter_map(|entry| {
            let entry = entry.expect("error reading shader directory entry");
            let path = entry.path();
            match path.extension().and_then(OsStr::to_str) {
                Some("metal") => Some(path),
                _ => None,
            }
        });

    // Compile all the metal files into OUT_DIR
    let mut compiled_shader_files: Vec<PathBuf> = Vec::new();
    for shader_path in shader_files.into_iter() {
        println!("cargo:rerun-if-changed={}", shader_path.to_str().unwrap());

        let mut out_path = out_dir.join(shader_path.file_name().unwrap());
        out_path.set_extension("air");

        let status = Command::new("xcrun")
            .args(&["-sdk", sdk_name, "metal", "-c"])
            .arg(shader_path.as_os_str())
            .arg("-o")
            .arg(out_path.as_os_str())
            .args(platform_args)
            .status()
            .expect("failed to execute metal compiler");

        if !status.success() {
            // stdout is linked to parent, so more detailed message will have been output from `metal`
            panic!("shader compilation failed");
        }

        compiled_shader_files.push(out_path);
    }

    // Link all the compiled files into a single library
    let status = Command::new("xcrun")
        .args(&["-sdk", sdk_name, "metallib"])
        .args(compiled_shader_files.iter().map(|p| p.as_os_str()))
        .arg("-o")
        .arg(out_lib.as_os_str())
        .status()
        .expect("failed to execute metal library builder");

    if !status.success() {
        panic!("shader library build failed");
    }
}
<|endoftext|>


<commit_before>// This module defines constants and functions for working with zakocmp
// configuration files.

extern crate yaml_rust;

use std::io::{Error, ErrorKind};
use std::result::Result;
use std::vec::Vec;
use yaml_rust::{Yaml, YamlLoader};

const DEFAULT_POLICY_KEY: &'static str = "default-policy";
const POLICIES_KEY: &'static str = "policies";

// Enumerates the string representations of known policies.
const POLICY_REPR_IGNORE: &'static str = "ignore";
const POLICY_REPR_NOADD: &'static str = "noadd";
const POLICY_REPR_NODELETE: &'static str = "nodelete";
const POLICY_REPR_NOMODIFY: &'static str = "nomodify";
const POLICY_REPR_IMMUTABLE: &'static str = "immutable";

// Represents known policies as integers.
pub const POLICY_IGNORE: i32 = 0;
pub const POLICY_NOADD: i32 = 1 << 0;
pub const POLICY_NODELETE: i32 = 1 << 1;
pub const POLICY_NOMODIFY: i32 = 1 << 2;
pub const POLICY_IMMUTABLE: i32 = POLICY_NOADD | POLICY_NODELETE | POLICY_NOMODIFY;

// Represents the length of the string "./" which as an implementation
// detail currently precedes all paths captured in zakopane snapshots.
// If a path matches only this, the match is trivial and should not be
// have its policy applied.
const TRIVIAL_MATCH_LENGTH: usize = 2;

// Represents a sorted vector of zakopane config rules, each mapping a
// path (prefix) to a policy. This type alias is provided for ease of
// coding.
type ZakopanePolicies = Vec<(String, i32)>;

// Represents a zakopane config. Please consult the documentation.
pub struct ZakopaneConfig {
    default_policy: i32,
    policies: ZakopanePolicies,
}

// Borrows the string representation of one policy `token` and returns
// the equivalent integral representation.
fn policy_token_as_int(token: &str) -> Result<i32, Error> {
    match token {
        POLICY_REPR_IGNORE => Ok(POLICY_IGNORE),
        POLICY_REPR_NOADD => Ok(POLICY_NOADD),
        POLICY_REPR_NODELETE => Ok(POLICY_NODELETE),
        POLICY_REPR_NOMODIFY => Ok(POLICY_NOMODIFY),
        POLICY_REPR_IMMUTABLE => Ok(POLICY_IMMUTABLE),
        _ => Err(Error::new(
            ErrorKind::InvalidInput,
            format!("bad token: ``{}''", token),
        )),
    }
}

// Borrows the string representation of a combined `policy` and returns
// the equivalent integral representation. This function expects
// `policy` to comprise one or more policy tokens separated by commas.
fn policy_tokens_as_int(policy: &str) -> Result<i32, Error> {
    let policy_ints: Vec<i32> = policy
        .split(",")
        .map(|tok| policy_token_as_int(tok))
        .collect::<Result<Vec<i32>, Error>>()?;
    return Ok(policy_ints
        .iter()
        .fold(POLICY_IGNORE, |accum, elem| accum | elem));
}

// Borrows yaml representations of one line of zakopane policy and
// returns the corresponding valid tuple suitable for use in building a
// ZakopanePolicies object.
fn extract_policy(ypath: &Yaml, policy_tokens: &Yaml) -> Result<(String, i32), Error> {
    let path: String = match ypath.as_str() {
        Some(string) => string.to_owned(),
        None => return Err(Error::new(ErrorKind::InvalidData, "malformed path?")),
    };
    let policy: i32 = match policy_tokens.as_str() {
        Some(string) => policy_tokens_as_int(string)?,
        None => return Err(Error::new(ErrorKind::InvalidData, "malformed policy?")),
    };
    Ok((path, policy))
}

// Borrows the YAML representation of a zakopane config and returns the
// corresponding ZakopanePolicies. The return value can be benignly
// empty (e.g. if the present config elects not to specify any rules).
fn policies_from_yaml(doc: &Yaml) -> Result<ZakopanePolicies, Error> {
    let policies_map_yaml = &doc[POLICIES_KEY];
    if policies_map_yaml.is_badvalue() {
        // Assumes the config may be benignly devoid of specific
        // policies, returning Ok.
        return Ok(vec![]);
    }
    // Otherwise, iterates over the policies map. Each entry in the
    // policies map correlates a path prefix to a comma-separated list
    // of policies.
    let policies_map: &yaml_rust::yaml::Hash = match policies_map_yaml.as_hash() {
        Some(map) => map,
        None => return Err(Error::new(ErrorKind::InvalidData, "malformed policies")),
    };
    let mut policies: ZakopanePolicies = policies_map
        .into_iter()
        .map(|pair| extract_policy(&pair.0, &pair.1))
        .collect::<Result<ZakopanePolicies, Error>>()?;
    policies.sort_unstable_by_key(|pair| pair.0.to_owned());
    Ok(policies)
}

// Borrows the YAML representation of a zakopane config and returns the
// integral default-policy defined within.
fn default_policy_from_yaml(doc: &Yaml) -> Result<i32, Error> {
    let default_policy_yaml = &doc[DEFAULT_POLICY_KEY];
    if default_policy_yaml.is_badvalue() {
        return Err(Error::new(ErrorKind::InvalidData, DEFAULT_POLICY_KEY));
    }
    let default_policy: i32 = match default_policy_yaml.as_str() {
        None => return Err(Error::new(ErrorKind::InvalidData, DEFAULT_POLICY_KEY)),
        Some(token) => policy_tokens_as_int(&token),
    }?;
    Ok(default_policy)
}

impl ZakopaneConfig {
    // Borrows the string representation of a zakopane config and
    // returns a corresponding ZakopaneConfig.
    pub fn new(config: &str) -> Result<ZakopaneConfig, Error> {
        let docs: Vec<Yaml> = match YamlLoader::load_from_str(config) {
            Ok(val) => val,
            Err(scan_error) => return Err(Error::new(ErrorKind::InvalidData, scan_error)),
        };
        if docs.len() == 0 {
            return Err(Error::new(ErrorKind::InvalidData, "empty zakopane config"));
        }
        let doc = &docs[0];

        let default_policy = default_policy_from_yaml(&doc)?;
        let policies: ZakopanePolicies = policies_from_yaml(&doc)?;

        Ok(ZakopaneConfig {
            default_policy: default_policy,
            policies: policies,
        })
    }

    // Returns how many rules this config contains.
    // This is never less than 1 as a default-policy is always required.
    pub fn rules(&self) -> usize {
        1 + self.policies.len()
    }

    // Borrows a `path` and returns the best-matched policy that
    // applies. This function returns an owned tuple of the
    // (closest-matched path expression, integral policy).
    //
    // This function represents the default-policy fallback by
    // returning the tuple consisting of an empty &str and the
    // default policy.
    pub fn match_policy(&self, path: &str) -> (&str, i32) {
        let mut best_match_path: &str = "";
        let mut best_match_policy: i32 = 0;
        for (prefix, policy) in self.policies.iter() {
            if path.starts_with(prefix) && prefix.len() > best_match_path.len() {
                best_match_path = prefix;
                best_match_policy = *policy;
            }
        }
        if best_match_path.len() <= TRIVIAL_MATCH_LENGTH {
            return ("", self.default_policy);
        }
        return (best_match_path, best_match_policy);
    }
}

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

    #[test]
    fn policy_token_bare() {
        let policy: i32 = policy_tokens_as_int(&"noadd").unwrap();
        assert!(policy == POLICY_NOADD);

        let policy: i32 = policy_tokens_as_int(&"nodelete").unwrap();
        assert!(policy == POLICY_NODELETE);

        let policy: i32 = policy_tokens_as_int(&"nomodify").unwrap();
        assert!(policy == POLICY_NOMODIFY);
    }

    #[test]
    fn policy_tokens_can_combo() {
        let policy: i32 = policy_tokens_as_int(&"noadd,nodelete").unwrap();
        assert!(policy == POLICY_NOADD | POLICY_NODELETE);
    }

    #[test]
    fn policy_tokens_can_repeat() {
        let policy: i32 =
            policy_tokens_as_int(&"noadd,noadd,noadd,noadd,nodelete,nodelete,nodelete,noadd")
                .unwrap();
        assert!(policy == POLICY_NOADD | POLICY_NODELETE);
    }

    #[test]
    fn config_must_not_be_empty() {
        let config = "";
        assert!(!ZakopaneConfig::new(&config).is_ok());
    }

    #[test]
    fn config_must_not_be_obviously_malformed() {
        let config = r#"
This is not a zakopane config -
rather, it's two lines of text.
        "#;
        assert!(!ZakopaneConfig::new(&config).is_ok());
    }

    #[test]
    fn config_requires_default_policy() {
        let config = r#"
policies:
    hello-there: nomodify
        "#;
        assert!(!ZakopaneConfig::new(&config).is_ok());

        let mut config_with_default_policy: String = r#"
default-policy: immutable
        "#
        .to_string();
        config_with_default_policy.push_str(&config);
        assert!(ZakopaneConfig::new(&config_with_default_policy).is_ok())
    }

    #[test]
    fn config_might_not_have_specific_policies() {
        let config = r#"
default-policy: nodelete
one-irrelevant-key: it doesn't matter what we put here
another-irrelevant-key: this doesn't invalidate the YAML
third-irrelevant-key: so long as it contains a default-policy
        "#;
        assert!(ZakopaneConfig::new(&config).is_ok());
    }

    #[test]
    fn config_policies_must_be_a_map() {
        let config = r#"
default-policy: noadd
policies:
    -   eh?
    -   this ain't a map
        "#;
        assert!(!ZakopaneConfig::new(&config).is_ok());
    }

    #[test]
    fn config_can_have_several_policies() {
        let config = r#"
default-policy: immutable
policies:
    hello-there: noadd
    general-kenobi: nodelete
        "#;
        assert!(ZakopaneConfig::new(&config).is_ok());
    }

    #[test]
    fn match_default_policy() {
        let config_yaml = r#"
default-policy: noadd
        "#;
        let config = ZakopaneConfig::new(&config_yaml).unwrap();

        // With only a default policy, this config has just 1 rule.
        assert!(config.rules() == 1);

        // Any path prefix we throw at match_policy() shall come up
        // as the default policy.
        let (_path, policy) = config.match_policy("./Documents/hello/there.txt");
        assert!(policy == POLICY_NOADD);
        let (_path, policy) = config.match_policy("./Music/general/kenobi.txt");
        assert!(policy == POLICY_NOADD);
    }

    #[test]
    fn match_nondefault_policies() {
        let config_yaml = r#"
default-policy: immutable
policies:
    ./Pictures/: noadd
    ./Pictures/2019/third-party/: nodelete
    ./Pictures/2020/: nomodify
    ./Pictures/2020/food/: nodelete,nomodify
        "#;
        let config = ZakopaneConfig::new(&config_yaml).unwrap();

        assert!(config.rules() == 5);

        // Falls back on the default-policy absent any specific policy
        // defined for this file.
        let (_path, policy) = config.match_policy("./Documents/catch-me-senpai.txt");
        assert!(policy == POLICY_IMMUTABLE);
        // Matches only ``./Pictures.''
        let (_path, policy) = config.match_policy("./Pictures/2016/yano.jpg");
        assert!(policy == POLICY_NOADD);
        // As above and does _not_ match ``./Pictures/2019/third-party/.''
        let (_path, policy) = config.match_policy("./Pictures/2019/first-party.jpg");
        assert!(policy == POLICY_NOADD);
        // Does match ``./Pictures/2019/third-party/.''
        let (_path, policy) = config.match_policy("./Pictures/2019/third-party/yano.jpg");
        assert!(policy == POLICY_NODELETE);

        // Path prefix matching is done strictly and exactly;
        // ``food.md'' doesn't match ``food/,'' so there's no risk of
        // zakopane confusing cohabiting entities with similar basenames.
        let (path, policy) = config.match_policy("./Pictures/2020/food.md");
        assert!(policy == POLICY_NOMODIFY);
        assert!(path == "./Pictures/2020/");
        let (path, policy) = config.match_policy("./Pictures/2020/food/tacos.jpg");
        assert!(policy == POLICY_NODELETE | POLICY_NOMODIFY);
        assert!(path == "./Pictures/2020/food/");
    }
}
<commit_msg>zakocmp: delete pointless code<commit_after>// This module defines constants and functions for working with zakocmp
// configuration files.

extern crate yaml_rust;

use std::io::{Error, ErrorKind};
use std::result::Result;
use std::vec::Vec;
use yaml_rust::{Yaml, YamlLoader};

const DEFAULT_POLICY_KEY: &'static str = "default-policy";
const POLICIES_KEY: &'static str = "policies";

// Enumerates the string representations of known policies.
const POLICY_REPR_IGNORE: &'static str = "ignore";
const POLICY_REPR_NOADD: &'static str = "noadd";
const POLICY_REPR_NODELETE: &'static str = "nodelete";
const POLICY_REPR_NOMODIFY: &'static str = "nomodify";
const POLICY_REPR_IMMUTABLE: &'static str = "immutable";

// Represents known policies as integers.
pub const POLICY_IGNORE: i32 = 0;
pub const POLICY_NOADD: i32 = 1 << 0;
pub const POLICY_NODELETE: i32 = 1 << 1;
pub const POLICY_NOMODIFY: i32 = 1 << 2;
pub const POLICY_IMMUTABLE: i32 = POLICY_NOADD | POLICY_NODELETE | POLICY_NOMODIFY;

// Represents a sorted vector of zakopane config rules, each mapping a
// path (prefix) to a policy. This type alias is provided for ease of
// coding.
type ZakopanePolicies = Vec<(String, i32)>;

// Represents a zakopane config. Please consult the documentation.
pub struct ZakopaneConfig {
    default_policy: i32,
    policies: ZakopanePolicies,
}

// Borrows the string representation of one policy `token` and returns
// the equivalent integral representation.
fn policy_token_as_int(token: &str) -> Result<i32, Error> {
    match token {
        POLICY_REPR_IGNORE => Ok(POLICY_IGNORE),
        POLICY_REPR_NOADD => Ok(POLICY_NOADD),
        POLICY_REPR_NODELETE => Ok(POLICY_NODELETE),
        POLICY_REPR_NOMODIFY => Ok(POLICY_NOMODIFY),
        POLICY_REPR_IMMUTABLE => Ok(POLICY_IMMUTABLE),
        _ => Err(Error::new(
            ErrorKind::InvalidInput,
            format!("bad token: ``{}''", token),
        )),
    }
}

// Borrows the string representation of a combined `policy` and returns
// the equivalent integral representation. This function expects
// `policy` to comprise one or more policy tokens separated by commas.
fn policy_tokens_as_int(policy: &str) -> Result<i32, Error> {
    let policy_ints: Vec<i32> = policy
        .split(",")
        .map(|tok| policy_token_as_int(tok))
        .collect::<Result<Vec<i32>, Error>>()?;
    return Ok(policy_ints
        .iter()
        .fold(POLICY_IGNORE, |accum, elem| accum | elem));
}

// Borrows yaml representations of one line of zakopane policy and
// returns the corresponding valid tuple suitable for use in building a
// ZakopanePolicies object.
fn extract_policy(ypath: &Yaml, policy_tokens: &Yaml) -> Result<(String, i32), Error> {
    let path: String = match ypath.as_str() {
        Some(string) => string.to_owned(),
        None => return Err(Error::new(ErrorKind::InvalidData, "malformed path?")),
    };
    let policy: i32 = match policy_tokens.as_str() {
        Some(string) => policy_tokens_as_int(string)?,
        None => return Err(Error::new(ErrorKind::InvalidData, "malformed policy?")),
    };
    Ok((path, policy))
}

// Borrows the YAML representation of a zakopane config and returns the
// corresponding ZakopanePolicies. The return value can be benignly
// empty (e.g. if the present config elects not to specify any rules).
fn policies_from_yaml(doc: &Yaml) -> Result<ZakopanePolicies, Error> {
    let policies_map_yaml = &doc[POLICIES_KEY];
    if policies_map_yaml.is_badvalue() {
        // Assumes the config may be benignly devoid of specific
        // policies, returning Ok.
        return Ok(vec![]);
    }
    // Otherwise, iterates over the policies map. Each entry in the
    // policies map correlates a path prefix to a comma-separated list
    // of policies.
    let policies_map: &yaml_rust::yaml::Hash = match policies_map_yaml.as_hash() {
        Some(map) => map,
        None => return Err(Error::new(ErrorKind::InvalidData, "malformed policies")),
    };
    let mut policies: ZakopanePolicies = policies_map
        .into_iter()
        .map(|pair| extract_policy(&pair.0, &pair.1))
        .collect::<Result<ZakopanePolicies, Error>>()?;
    policies.sort_unstable_by_key(|pair| pair.0.to_owned());
    Ok(policies)
}

// Borrows the YAML representation of a zakopane config and returns the
// integral default-policy defined within.
fn default_policy_from_yaml(doc: &Yaml) -> Result<i32, Error> {
    let default_policy_yaml = &doc[DEFAULT_POLICY_KEY];
    if default_policy_yaml.is_badvalue() {
        return Err(Error::new(ErrorKind::InvalidData, DEFAULT_POLICY_KEY));
    }
    let default_policy: i32 = match default_policy_yaml.as_str() {
        None => return Err(Error::new(ErrorKind::InvalidData, DEFAULT_POLICY_KEY)),
        Some(token) => policy_tokens_as_int(&token),
    }?;
    Ok(default_policy)
}

impl ZakopaneConfig {
    // Borrows the string representation of a zakopane config and
    // returns a corresponding ZakopaneConfig.
    pub fn new(config: &str) -> Result<ZakopaneConfig, Error> {
        let docs: Vec<Yaml> = match YamlLoader::load_from_str(config) {
            Ok(val) => val,
            Err(scan_error) => return Err(Error::new(ErrorKind::InvalidData, scan_error)),
        };
        if docs.len() == 0 {
            return Err(Error::new(ErrorKind::InvalidData, "empty zakopane config"));
        }
        let doc = &docs[0];

        let default_policy = default_policy_from_yaml(&doc)?;
        let policies: ZakopanePolicies = policies_from_yaml(&doc)?;

        Ok(ZakopaneConfig {
            default_policy: default_policy,
            policies: policies,
        })
    }

    // Returns how many rules this config contains.
    // This is never less than 1 as a default-policy is always required.
    pub fn rules(&self) -> usize {
        1 + self.policies.len()
    }

    // Borrows a `path` and returns the best-matched policy that
    // applies. This function returns an owned tuple of the
    // (closest-matched path expression, integral policy).
    //
    // This function represents the default-policy fallback by
    // returning the tuple consisting of an empty &str and the
    // default policy.
    pub fn match_policy(&self, path: &str) -> (&str, i32) {
        let mut best_match_path: &str = "";
        let mut best_match_policy: i32 = 0;
        for (prefix, policy) in self.policies.iter() {
            if path.starts_with(prefix) && prefix.len() > best_match_path.len() {
                best_match_path = prefix;
                best_match_policy = *policy;
            }
        }
        if best_match_path.len() == 0 {
            return ("", self.default_policy);
        }
        return (best_match_path, best_match_policy);
    }
}

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

    #[test]
    fn policy_token_bare() {
        let policy: i32 = policy_tokens_as_int(&"noadd").unwrap();
        assert!(policy == POLICY_NOADD);

        let policy: i32 = policy_tokens_as_int(&"nodelete").unwrap();
        assert!(policy == POLICY_NODELETE);

        let policy: i32 = policy_tokens_as_int(&"nomodify").unwrap();
        assert!(policy == POLICY_NOMODIFY);
    }

    #[test]
    fn policy_tokens_can_combo() {
        let policy: i32 = policy_tokens_as_int(&"noadd,nodelete").unwrap();
        assert!(policy == POLICY_NOADD | POLICY_NODELETE);
    }

    #[test]
    fn policy_tokens_can_repeat() {
        let policy: i32 =
            policy_tokens_as_int(&"noadd,noadd,noadd,noadd,nodelete,nodelete,nodelete,noadd")
                .unwrap();
        assert!(policy == POLICY_NOADD | POLICY_NODELETE);
    }

    #[test]
    fn config_must_not_be_empty() {
        let config = "";
        assert!(!ZakopaneConfig::new(&config).is_ok());
    }

    #[test]
    fn config_must_not_be_obviously_malformed() {
        let config = r#"
This is not a zakopane config -
rather, it's two lines of text.
        "#;
        assert!(!ZakopaneConfig::new(&config).is_ok());
    }

    #[test]
    fn config_requires_default_policy() {
        let config = r#"
policies:
    hello-there: nomodify
        "#;
        assert!(!ZakopaneConfig::new(&config).is_ok());

        let mut config_with_default_policy: String = r#"
default-policy: immutable
        "#
        .to_string();
        config_with_default_policy.push_str(&config);
        assert!(ZakopaneConfig::new(&config_with_default_policy).is_ok())
    }

    #[test]
    fn config_might_not_have_specific_policies() {
        let config = r#"
default-policy: nodelete
one-irrelevant-key: it doesn't matter what we put here
another-irrelevant-key: this doesn't invalidate the YAML
third-irrelevant-key: so long as it contains a default-policy
        "#;
        assert!(ZakopaneConfig::new(&config).is_ok());
    }

    #[test]
    fn config_policies_must_be_a_map() {
        let config = r#"
default-policy: noadd
policies:
    -   eh?
    -   this ain't a map
        "#;
        assert!(!ZakopaneConfig::new(&config).is_ok());
    }

    #[test]
    fn config_can_have_several_policies() {
        let config = r#"
default-policy: immutable
policies:
    hello-there: noadd
    general-kenobi: nodelete
        "#;
        assert!(ZakopaneConfig::new(&config).is_ok());
    }

    #[test]
    fn match_default_policy() {
        let config_yaml = r#"
default-policy: noadd
        "#;
        let config = ZakopaneConfig::new(&config_yaml).unwrap();

        // With only a default policy, this config has just 1 rule.
        assert!(config.rules() == 1);

        // Any path prefix we throw at match_policy() shall come up
        // as the default policy.
        let (_path, policy) = config.match_policy("./Documents/hello/there.txt");
        assert!(policy == POLICY_NOADD);
        let (_path, policy) = config.match_policy("./Music/general/kenobi.txt");
        assert!(policy == POLICY_NOADD);
    }

    #[test]
    fn match_nondefault_policies() {
        let config_yaml = r#"
default-policy: immutable
policies:
    ./Pictures/: noadd
    ./Pictures/2019/third-party/: nodelete
    ./Pictures/2020/: nomodify
    ./Pictures/2020/food/: nodelete,nomodify
        "#;
        let config = ZakopaneConfig::new(&config_yaml).unwrap();

        assert!(config.rules() == 5);

        // Falls back on the default-policy absent any specific policy
        // defined for this file.
        let (_path, policy) = config.match_policy("./Documents/catch-me-senpai.txt");
        assert!(policy == POLICY_IMMUTABLE);
        // Matches only ``./Pictures.''
        let (_path, policy) = config.match_policy("./Pictures/2016/yano.jpg");
        assert!(policy == POLICY_NOADD);
        // As above and does _not_ match ``./Pictures/2019/third-party/.''
        let (_path, policy) = config.match_policy("./Pictures/2019/first-party.jpg");
        assert!(policy == POLICY_NOADD);
        // Does match ``./Pictures/2019/third-party/.''
        let (_path, policy) = config.match_policy("./Pictures/2019/third-party/yano.jpg");
        assert!(policy == POLICY_NODELETE);

        // Path prefix matching is done strictly and exactly;
        // ``food.md'' doesn't match ``food/,'' so there's no risk of
        // zakopane confusing cohabiting entities with similar basenames.
        let (path, policy) = config.match_policy("./Pictures/2020/food.md");
        assert!(policy == POLICY_NOMODIFY);
        assert!(path == "./Pictures/2020/");
        let (path, policy) = config.match_policy("./Pictures/2020/food/tacos.jpg");
        assert!(policy == POLICY_NODELETE | POLICY_NOMODIFY);
        assert!(path == "./Pictures/2020/food/");
    }
}
<|endoftext|>


<commit_before>// xfail-stage0

fn f[T](@int i, &T t) {}

fn main() {
  auto x = bind f[char](@0xdeafbeef, _);
}
<commit_msg>test: Un-XFAIL drop-parametric-closure-with-bound-box.rs, oops.<commit_after>fn f[T](@int i, &T t) {}

fn main() {
  auto x = bind f[char](@0xdeafbeef, _);
}
<|endoftext|>


<commit_before>extern crate clap;

use std::io::prelude::*;
use std::io::{Error, ErrorKind};
use std::fs::File;

struct Triangle(u64, u64, u64);

impl Triangle {
    fn is_valid(&self) -> bool {
        let &Triangle(a, b, c) = self;
        let mut s = [a, b, c];
        s.sort();
        s[0] + s[1] > s[2]
    }
}

fn invalid_data(msg: &str) -> Error {
    Error::new(ErrorKind::InvalidData, msg)
}

fn parse_args() -> std::io::Result<Box<Read>> {
    let source = clap::App::new("Day 03")
        .author("Devon Hollowood")
        .arg(clap::Arg::with_name("triangles")
             .index(1)
             .short("f")
             .long("triangles")
             .help("file to read triangles from. Reads from stdin otherwise")
             .takes_value(true)
        )
        .get_matches()
        .value_of_os("triangles")
        .map(|str| str.to_owned());
    match source {
        Some(filename) => Ok(Box::new(File::open(filename)?)),
        None => Ok(Box::new(std::io::stdin())),
    }
}

fn read_triangles<R: Read>(source: &mut R)
    -> std::io::Result<Vec<Triangle>>
{
    let mut contents = String::new();
    println!("Reading contents");
    source.read_to_string(&mut contents)?;
    println!("Processing");
    contents.lines().map(
        |line| {
            let sides: Vec<u64> = line.split_whitespace()
                .map(|side| {
                    side.parse()
                        .map_err(|_| invalid_data(&format!("Bad side: {}", side)))
                }).collect::<Result<_, _>>()?;
            println!("Read {}", line);
            if sides.len() != 3 {
                Err(invalid_data(&format!("Invalid line: {}", line)))
            } else {
                Ok(Triangle(sides[0], sides[1], sides[2]))
            }
        }
    ).collect()
}

fn main() {
    let mut source = parse_args()
        .unwrap_or_else(|err| panic!("Error reading file: {}", err));
    let n_valid = read_triangles(&mut source)
        .unwrap_or_else(|err| panic!("Error reading triangles: {}", err))
        .iter()
        .filter(|t| t.is_valid())
        .count();
    println!("# of valid triangles: {}", n_valid);
}
<commit_msg>Day 3 part 2<commit_after>extern crate clap;

use std::io::prelude::*;
use std::io::{Error, ErrorKind};
use std::fs::File;

struct Triangle(u64, u64, u64);

impl Triangle {
    fn is_valid(&self) -> bool {
        let &Triangle(a, b, c) = self;
        let mut s = [a, b, c];
        s.sort();
        s[0] + s[1] > s[2]
    }
}

fn invalid_data(msg: &str) -> Error {
    Error::new(ErrorKind::InvalidData, msg)
}

fn parse_args() -> std::io::Result<Box<Read>> {
    let source = clap::App::new("Day 03")
        .author("Devon Hollowood")
        .arg(clap::Arg::with_name("triangles")
             .index(1)
             .short("f")
             .long("triangles")
             .help("file to read triangles from. Reads from stdin otherwise")
             .takes_value(true)
        )
        .get_matches()
        .value_of_os("triangles")
        .map(|str| str.to_owned());
    match source {
        Some(filename) => Ok(Box::new(File::open(filename)?)),
        None => Ok(Box::new(std::io::stdin())),
    }
}

fn read_triangles_horizontal(contents: &str) -> std::io::Result<Vec<Triangle>> {
    contents.lines().map(
        |line| {
            let sides: Vec<u64> = line.split_whitespace()
                .map(|side| {
                    side.parse()
                        .map_err(|_| invalid_data(&format!("Bad side: {}", side)))
                }).collect::<Result<_, _>>()?;
            if sides.len() != 3 {
                Err(invalid_data(&format!("Invalid line: {}", line)))
            } else {
                Ok(Triangle(sides[0], sides[1], sides[2]))
            }
        }
    ).collect()
}

fn read_triangles_vertical(contents: &str) -> std::io::Result<Vec<Triangle>> {
    let mut vecs = Vec::new();
    for line in contents.lines() {
        let sides: Vec<u64> = line.split_whitespace()
            .map(|side| {
                side.parse()
                    .map_err(|_| invalid_data(&format!("Bad side: {}", side)))
            }).collect::<Result<_, _>>()?;
        if vecs.len() < sides.len() {
            vecs.resize(sides.len(), Vec::new());
        }
        for (n, val) in sides.into_iter().enumerate() {
            vecs[n].push(val);
        }
    }
    let side_list: Vec<_> =
        vecs.into_iter().fold(Vec::new(), |mut v1, v2| { v1.extend(v2); v1 });
    let mut triangles = Vec::new();
    for sides in side_list.chunks(3) {
        if sides.len() != 3 {
            return Err(invalid_data("Incomplete triangle"))
        } else {
            triangles.push(Triangle(sides[0], sides[1], sides[2]));
        }
    }
    Ok(triangles)
}

fn main() {
    let mut source = parse_args()
        .unwrap_or_else(|err| panic!("Error reading file: {}", err));
    let mut contents = String::new();
    source.read_to_string(&mut contents).expect("Could not read input");
    let n_valid_horizontal = read_triangles_horizontal(&contents)
        .unwrap_or_else(|err| panic!("Error reading triangles: {}", err))
        .iter()
        .filter(|t| t.is_valid())
        .count();
    let n_valid_vertical = read_triangles_vertical(&contents)
        .unwrap_or_else(|err| panic!("Error reading triangles: {}", err))
        .iter()
        .filter(|t| t.is_valid())
        .count();
    println!("# of valid triangles (horizontal): {}", n_valid_horizontal);
    println!("# of valid triangles (vertical): {}", n_valid_vertical);
}
<|endoftext|>


<commit_before>#![feature(maybe_uninit_extra)]
use std::mem::MaybeUninit;
use std::cell::{Cell, RefCell, UnsafeCell};

fn main() {
    aliasing_mut_and_shr();
    aliasing_frz_and_shr();
    into_interior_mutability();
    unsafe_cell_2phase();
}

fn aliasing_mut_and_shr() {
    fn inner(rc: &RefCell<i32>, aliasing: &mut i32) {
        *aliasing += 4;
        let _escape_to_raw = rc as *const _;
        *aliasing += 4;
        let _shr = &*rc;
        *aliasing += 4;
        // also turning this into a frozen ref now must work
        let aliasing = &*aliasing;
        let _val = *aliasing;
        let _escape_to_raw = rc as *const _; // this must NOT unfreeze
        let _val = *aliasing;
        let _shr = &*rc; // this must NOT unfreeze
        let _val = *aliasing;
    }

    let rc = RefCell::new(23);
    let mut bmut = rc.borrow_mut();
    inner(&rc, &mut *bmut);
    drop(bmut);
    assert_eq!(*rc.borrow(), 23+12);
}

fn aliasing_frz_and_shr() {
    fn inner(rc: &RefCell<i32>, aliasing: &i32) {
        let _val = *aliasing;
        let _escape_to_raw = rc as *const _; // this must NOT unfreeze
        let _val = *aliasing;
        let _shr = &*rc; // this must NOT unfreeze
        let _val = *aliasing;
    }

    let rc = RefCell::new(23);
    let bshr = rc.borrow();
    inner(&rc, &*bshr);
    assert_eq!(*rc.borrow(), 23);
}

// Getting a pointer into a union with interior mutability used to be tricky
// business (https://github.com/rust-lang/miri/issues/615), but it should work
// now.
fn into_interior_mutability() {
    let mut x: MaybeUninit<(Cell<u32>, u32)> = MaybeUninit::uninit();
    x.as_ptr();
    x.write((Cell::new(0), 1));
    let ptr = unsafe { x.assume_init_ref() };
    assert_eq!(ptr.1, 1);
}

// Two-phase borrows of the pointer returned by UnsafeCell::get() should not
// invalidate aliases.
fn unsafe_cell_2phase() { unsafe {
    let x = &UnsafeCell::new(vec![]);
    let x2 = &*x;
    (*x.get()).push(0);
    let _val = (*x2.get()).get(0);
} }
<commit_msg>Remove spurious `maybe_uninit_extra`<commit_after>use std::mem::MaybeUninit;
use std::cell::{Cell, RefCell, UnsafeCell};

fn main() {
    aliasing_mut_and_shr();
    aliasing_frz_and_shr();
    into_interior_mutability();
    unsafe_cell_2phase();
}

fn aliasing_mut_and_shr() {
    fn inner(rc: &RefCell<i32>, aliasing: &mut i32) {
        *aliasing += 4;
        let _escape_to_raw = rc as *const _;
        *aliasing += 4;
        let _shr = &*rc;
        *aliasing += 4;
        // also turning this into a frozen ref now must work
        let aliasing = &*aliasing;
        let _val = *aliasing;
        let _escape_to_raw = rc as *const _; // this must NOT unfreeze
        let _val = *aliasing;
        let _shr = &*rc; // this must NOT unfreeze
        let _val = *aliasing;
    }

    let rc = RefCell::new(23);
    let mut bmut = rc.borrow_mut();
    inner(&rc, &mut *bmut);
    drop(bmut);
    assert_eq!(*rc.borrow(), 23+12);
}

fn aliasing_frz_and_shr() {
    fn inner(rc: &RefCell<i32>, aliasing: &i32) {
        let _val = *aliasing;
        let _escape_to_raw = rc as *const _; // this must NOT unfreeze
        let _val = *aliasing;
        let _shr = &*rc; // this must NOT unfreeze
        let _val = *aliasing;
    }

    let rc = RefCell::new(23);
    let bshr = rc.borrow();
    inner(&rc, &*bshr);
    assert_eq!(*rc.borrow(), 23);
}

// Getting a pointer into a union with interior mutability used to be tricky
// business (https://github.com/rust-lang/miri/issues/615), but it should work
// now.
fn into_interior_mutability() {
    let mut x: MaybeUninit<(Cell<u32>, u32)> = MaybeUninit::uninit();
    x.as_ptr();
    x.write((Cell::new(0), 1));
    let ptr = unsafe { x.assume_init_ref() };
    assert_eq!(ptr.1, 1);
}

// Two-phase borrows of the pointer returned by UnsafeCell::get() should not
// invalidate aliases.
fn unsafe_cell_2phase() { unsafe {
    let x = &UnsafeCell::new(vec![]);
    let x2 = &*x;
    (*x.get()).push(0);
    let _val = (*x2.get()).get(0);
} }
<|endoftext|>