<commit_before>use std::marker::PhantomData;

use super::Normalizable;

use Colors;

/// Casting iterator for `Colors`.
#[derive(Debug, Clone)]
pub struct CastingIter<'a, T>(Colors<'a>, PhantomData<T>);

/// Type which describes how to cast any color into RGB u8.
#[derive(Debug, Clone)]
pub struct RgbU8;

/// Type which describes how to cast any color into RGB u16.
#[derive(Debug, Clone)]
pub struct RgbU16;

/// Type which describes how to cast any color into RGB f32.
#[derive(Debug, Clone)]
pub struct RgbF32;

/// Type which describes how to cast any color into RGBA u8.
#[derive(Debug, Clone)]
pub struct RgbaU8;

/// Type which describes how to cast any color into RGBA u16.
#[derive(Debug, Clone)]
pub struct RgbaU16;

/// Type which describes how to cast any color into RGBA f32.
#[derive(Debug, Clone)]
pub struct RgbaF32;

pub trait ArrayRelation<T> {
    fn into_rgb(self)  -> [T; 3];
    fn into_rgba(self) -> [T; 4];
}

impl<T: Copy + Default> ArrayRelation<T> for [T; 3] {
    fn into_rgb(self)  -> [T; 3] { self }
    fn into_rgba(self) -> [T; 4] { [self[0], self[1], self[2], T::default()] }
}

impl<T: Copy + Default> ArrayRelation<T> for [T; 4] {
    fn into_rgb(self)  -> [T; 3] { [self[0], self[1], self[2]] }
    fn into_rgba(self) -> [T; 4] { self }
}

/// Trait for types which describe casting behaviour.
pub trait Cast {
    /// Output type.
    type Into;

    /// Cast from RGB u8.
    fn from_rgb_u8(x: [u8; 3]) -> Self::Into;

    /// Cast from RGB u16.
    fn from_rgb_u16(x: [u16; 3]) -> Self::Into;

    /// Cast from RGB f32.
    fn from_rgb_f32(x: [f32; 3]) -> Self::Into;

    /// Cast from RGBA u8.
    fn from_rgba_u8(x: [u8; 4]) -> Self::Into;

    /// Cast from RGBA u16.
    fn from_rgba_u16(x: [u16; 4]) -> Self::Into;

    /// Cast from RGBA f32.
    fn from_rgba_f32(x: [f32; 4]) -> Self::Into;
}

impl<'a, A> CastingIter<'a, A> {
    pub(crate) fn new(iter: Colors<'a>) -> Self {
        CastingIter(iter, PhantomData)
    }

    /// Unwrap underlying `Colors` object.
    pub fn unwrap(self) -> Colors<'a> {
        self.0
    }
}

impl<'a, A: Cast> Iterator for CastingIter<'a, A> {
    type Item = A::Into;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        match self.0 {
            Colors::RgbU8(ref mut i)   => i.next().map(A::from_rgb_u8),
            Colors::RgbU16(ref mut i)  => i.next().map(A::from_rgb_u16),
            Colors::RgbF32(ref mut i)  => i.next().map(A::from_rgb_f32),
            Colors::RgbaU8(ref mut i)  => i.next().map(A::from_rgba_u8),
            Colors::RgbaU16(ref mut i) => i.next().map(A::from_rgba_u16),
            Colors::RgbaF32(ref mut i) => i.next().map(A::from_rgba_f32),
        }
    }

    #[inline]
    fn nth(&mut self, x: usize) -> Option<Self::Item> {
        match self.0 {
            Colors::RgbU8(ref mut i)   => i.nth(x).map(A::from_rgb_u8),
            Colors::RgbU16(ref mut i)  => i.nth(x).map(A::from_rgb_u16),
            Colors::RgbF32(ref mut i)  => i.nth(x).map(A::from_rgb_f32),
            Colors::RgbaU8(ref mut i)  => i.nth(x).map(A::from_rgba_u8),
            Colors::RgbaU16(ref mut i) => i.nth(x).map(A::from_rgba_u16),
            Colors::RgbaF32(ref mut i) => i.nth(x).map(A::from_rgba_f32),
        }
    }

    fn last(self) -> Option<Self::Item> {
        match self.0 {
            Colors::RgbU8(i)   => i.last().map(A::from_rgb_u8),
            Colors::RgbU16(i)  => i.last().map(A::from_rgb_u16),
            Colors::RgbF32(i)  => i.last().map(A::from_rgb_f32),
            Colors::RgbaU8(i)  => i.last().map(A::from_rgba_u8),
            Colors::RgbaU16(i) => i.last().map(A::from_rgba_u16),
            Colors::RgbaF32(i) => i.last().map(A::from_rgba_f32),
        }
    }

    fn count(self) -> usize {
        self.size_hint().0
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        match self.0 {
            Colors::RgbU8(ref i)   => i.size_hint(),
            Colors::RgbU16(ref i)  => i.size_hint(),
            Colors::RgbF32(ref i)  => i.size_hint(),
            Colors::RgbaU8(ref i)  => i.size_hint(),
            Colors::RgbaU16(ref i) => i.size_hint(),
            Colors::RgbaF32(ref i) => i.size_hint(),
        }
    }
}

impl Cast for RgbU8 {
    type Into = [u8; 3];

    fn from_rgb_u8(x: [u8; 3]) -> Self::Into {
        x.into_rgb().normalize()
    }

    fn from_rgb_u16(x: [u16; 3]) -> Self::Into {
        x.into_rgb().normalize()
    }

    fn from_rgb_f32(x: [f32; 3]) -> Self::Into {
        x.into_rgb().normalize()
    }

    fn from_rgba_u8(x: [u8; 4]) -> Self::Into {
        x.into_rgb().normalize()
    }

    fn from_rgba_u16(x: [u16; 4]) -> Self::Into {
        x.into_rgb().normalize()
    }

    fn from_rgba_f32(x: [f32; 4]) -> Self::Into {
        x.into_rgb().normalize()
    }
}

impl Cast for RgbU16 {
    type Into = [u16; 3];

    fn from_rgb_u8(x: [u8; 3]) -> Self::Into {
        x.into_rgb().normalize()
    }

    fn from_rgb_u16(x: [u16; 3]) -> Self::Into {
        x.into_rgb().normalize()
    }

    fn from_rgb_f32(x: [f32; 3]) -> Self::Into {
        x.into_rgb().normalize()
    }

    fn from_rgba_u8(x: [u8; 4]) -> Self::Into {
        x.into_rgb().normalize()
    }

    fn from_rgba_u16(x: [u16; 4]) -> Self::Into {
        x.into_rgb().normalize()
    }

    fn from_rgba_f32(x: [f32; 4]) -> Self::Into {
        x.into_rgb().normalize()
    }
}

impl Cast for RgbF32 {
    type Into = [f32; 3];

    fn from_rgb_u8(x: [u8; 3]) -> Self::Into {
        x.into_rgb().normalize()
    }

    fn from_rgb_u16(x: [u16; 3]) -> Self::Into {
        x.into_rgb().normalize()
    }

    fn from_rgb_f32(x: [f32; 3]) -> Self::Into {
        x.into_rgb().normalize()
    }

    fn from_rgba_u8(x: [u8; 4]) -> Self::Into {
        x.into_rgb().normalize()
    }

    fn from_rgba_u16(x: [u16; 4]) -> Self::Into {
        x.into_rgb().normalize()
    }

    fn from_rgba_f32(x: [f32; 4]) -> Self::Into {
        x.into_rgb().normalize()
    }
}

impl Cast for RgbaU8 {
    type Into = [u8; 4];

    fn from_rgb_u8(x: [u8; 3]) -> Self::Into {
        x.normalize().into_rgba()
    }

    fn from_rgb_u16(x: [u16; 3]) -> Self::Into {
        x.normalize().into_rgba()
    }

    fn from_rgb_f32(x: [f32; 3]) -> Self::Into {
        x.normalize().into_rgba()
    }

    fn from_rgba_u8(x: [u8; 4]) -> Self::Into {
        x.normalize().into_rgba()
    }

    fn from_rgba_u16(x: [u16; 4]) -> Self::Into {
        x.normalize().into_rgba()
    }

    fn from_rgba_f32(x: [f32; 4]) -> Self::Into {
        x.normalize().into_rgba()
    }
}

impl Cast for RgbaU16 {
    type Into = [u16; 4];

    fn from_rgb_u8(x: [u8; 3]) -> Self::Into {
        x.normalize().into_rgba()
    }

    fn from_rgb_u16(x: [u16; 3]) -> Self::Into {
        x.normalize().into_rgba()
    }

    fn from_rgb_f32(x: [f32; 3]) -> Self::Into {
        x.normalize().into_rgba()
    }

    fn from_rgba_u8(x: [u8; 4]) -> Self::Into {
        x.normalize().into_rgba()
    }

    fn from_rgba_u16(x: [u16; 4]) -> Self::Into {
        x.normalize().into_rgba()
    }

    fn from_rgba_f32(x: [f32; 4]) -> Self::Into {
        x.normalize().into_rgba()
    }
}

impl Cast for RgbaF32 {
    type Into = [f32; 4];

    fn from_rgb_u8(x: [u8; 3]) -> Self::Into {
        x.normalize().into_rgba()
    }

    fn from_rgb_u16(x: [u16; 3]) -> Self::Into {
        x.normalize().into_rgba()
    }

    fn from_rgb_f32(x: [f32; 3]) -> Self::Into {
        x.normalize().into_rgba()
    }

    fn from_rgba_u8(x: [u8; 4]) -> Self::Into {
        x.normalize().into_rgba()
    }

    fn from_rgba_u16(x: [u16; 4]) -> Self::Into {
        x.normalize().into_rgba()
    }

    fn from_rgba_f32(x: [f32; 4]) -> Self::Into {
        x.normalize().into_rgba()
    }
}
<commit_msg>Correct implementations for color casts<commit_after>use std::marker::PhantomData;

use super::Normalizable;

use Colors;

/// Casting iterator for `Colors`.
#[derive(Debug, Clone)]
pub struct CastingIter<'a, T>(Colors<'a>, PhantomData<T>);

/// Type which describes how to cast any color into RGB u8.
#[derive(Debug, Clone)]
pub struct RgbU8;

/// Type which describes how to cast any color into RGB u16.
#[derive(Debug, Clone)]
pub struct RgbU16;

/// Type which describes how to cast any color into RGB f32.
#[derive(Debug, Clone)]
pub struct RgbF32;

/// Type which describes how to cast any color into RGBA u8.
#[derive(Debug, Clone)]
pub struct RgbaU8;

/// Type which describes how to cast any color into RGBA u16.
#[derive(Debug, Clone)]
pub struct RgbaU16;

/// Type which describes how to cast any color into RGBA f32.
#[derive(Debug, Clone)]
pub struct RgbaF32;

trait ColorChannel {
    fn max_color() -> Self;
}

impl ColorChannel for u8 {
    fn max_color() -> Self { u8::max_value() }
}

impl ColorChannel for u16 {
    fn max_color() -> Self { u16::max_value() }
}

impl ColorChannel for f32 {
    fn max_color() -> Self { 1.0 }
}

trait ColorArray<T> {
    fn into_rgb(self)  -> [T; 3];
    fn into_rgba(self) -> [T; 4];
}

impl<T: Copy + ColorChannel> ColorArray<T> for [T; 3] {
    fn into_rgb(self)  -> [T; 3] { self }
    fn into_rgba(self) -> [T; 4] { [self[0], self[1], self[2], T::max_color()] }
}

impl<T: Copy + ColorChannel> ColorArray<T> for [T; 4] {
    fn into_rgb(self)  -> [T; 3] { [self[0], self[1], self[2]] }
    fn into_rgba(self) -> [T; 4] { self }
}

/// Trait for types which describe casting behaviour.
pub trait Cast {
    /// Output type.
    type Output;

    /// Cast from RGB u8.
    fn from_rgb_u8(x: [u8; 3]) -> Self::Output;

    /// Cast from RGB u16.
    fn from_rgb_u16(x: [u16; 3]) -> Self::Output;

    /// Cast from RGB f32.
    fn from_rgb_f32(x: [f32; 3]) -> Self::Output;

    /// Cast from RGBA u8.
    fn from_rgba_u8(x: [u8; 4]) -> Self::Output;

    /// Cast from RGBA u16.
    fn from_rgba_u16(x: [u16; 4]) -> Self::Output;

    /// Cast from RGBA f32.
    fn from_rgba_f32(x: [f32; 4]) -> Self::Output;
}

impl<'a, A> CastingIter<'a, A> {
    pub(crate) fn new(iter: Colors<'a>) -> Self {
        CastingIter(iter, PhantomData)
    }

    /// Unwrap underlying `Colors` object.
    pub fn unwrap(self) -> Colors<'a> {
        self.0
    }
}

impl<'a, A: Cast> Iterator for CastingIter<'a, A> {
    type Item = A::Output;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        match self.0 {
            Colors::RgbU8(ref mut i)   => i.next().map(A::from_rgb_u8),
            Colors::RgbU16(ref mut i)  => i.next().map(A::from_rgb_u16),
            Colors::RgbF32(ref mut i)  => i.next().map(A::from_rgb_f32),
            Colors::RgbaU8(ref mut i)  => i.next().map(A::from_rgba_u8),
            Colors::RgbaU16(ref mut i) => i.next().map(A::from_rgba_u16),
            Colors::RgbaF32(ref mut i) => i.next().map(A::from_rgba_f32),
        }
    }

    #[inline]
    fn nth(&mut self, x: usize) -> Option<Self::Item> {
        match self.0 {
            Colors::RgbU8(ref mut i)   => i.nth(x).map(A::from_rgb_u8),
            Colors::RgbU16(ref mut i)  => i.nth(x).map(A::from_rgb_u16),
            Colors::RgbF32(ref mut i)  => i.nth(x).map(A::from_rgb_f32),
            Colors::RgbaU8(ref mut i)  => i.nth(x).map(A::from_rgba_u8),
            Colors::RgbaU16(ref mut i) => i.nth(x).map(A::from_rgba_u16),
            Colors::RgbaF32(ref mut i) => i.nth(x).map(A::from_rgba_f32),
        }
    }

    fn last(self) -> Option<Self::Item> {
        match self.0 {
            Colors::RgbU8(i)   => i.last().map(A::from_rgb_u8),
            Colors::RgbU16(i)  => i.last().map(A::from_rgb_u16),
            Colors::RgbF32(i)  => i.last().map(A::from_rgb_f32),
            Colors::RgbaU8(i)  => i.last().map(A::from_rgba_u8),
            Colors::RgbaU16(i) => i.last().map(A::from_rgba_u16),
            Colors::RgbaF32(i) => i.last().map(A::from_rgba_f32),
        }
    }

    fn count(self) -> usize {
        self.size_hint().0
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        match self.0 {
            Colors::RgbU8(ref i)   => i.size_hint(),
            Colors::RgbU16(ref i)  => i.size_hint(),
            Colors::RgbF32(ref i)  => i.size_hint(),
            Colors::RgbaU8(ref i)  => i.size_hint(),
            Colors::RgbaU16(ref i) => i.size_hint(),
            Colors::RgbaF32(ref i) => i.size_hint(),
        }
    }
}

impl Cast for RgbU8 {
    type Output = [u8; 3];

    fn from_rgb_u8(x: [u8; 3]) -> Self::Output {
        x.into_rgb().normalize()
    }

    fn from_rgb_u16(x: [u16; 3]) -> Self::Output {
        x.into_rgb().normalize()
    }

    fn from_rgb_f32(x: [f32; 3]) -> Self::Output {
        x.into_rgb().normalize()
    }

    fn from_rgba_u8(x: [u8; 4]) -> Self::Output {
        x.into_rgb().normalize()
    }

    fn from_rgba_u16(x: [u16; 4]) -> Self::Output {
        x.into_rgb().normalize()
    }

    fn from_rgba_f32(x: [f32; 4]) -> Self::Output {
        x.into_rgb().normalize()
    }
}

impl Cast for RgbU16 {
    type Output = [u16; 3];

    fn from_rgb_u8(x: [u8; 3]) -> Self::Output {
        x.into_rgb().normalize()
    }

    fn from_rgb_u16(x: [u16; 3]) -> Self::Output {
        x.into_rgb().normalize()
    }

    fn from_rgb_f32(x: [f32; 3]) -> Self::Output {
        x.into_rgb().normalize()
    }

    fn from_rgba_u8(x: [u8; 4]) -> Self::Output {
        x.into_rgb().normalize()
    }

    fn from_rgba_u16(x: [u16; 4]) -> Self::Output {
        x.into_rgb().normalize()
    }

    fn from_rgba_f32(x: [f32; 4]) -> Self::Output {
        x.into_rgb().normalize()
    }
}

impl Cast for RgbF32 {
    type Output = [f32; 3];

    fn from_rgb_u8(x: [u8; 3]) -> Self::Output {
        x.into_rgb().normalize()
    }

    fn from_rgb_u16(x: [u16; 3]) -> Self::Output {
        x.into_rgb().normalize()
    }

    fn from_rgb_f32(x: [f32; 3]) -> Self::Output {
        x.into_rgb().normalize()
    }

    fn from_rgba_u8(x: [u8; 4]) -> Self::Output {
        x.into_rgb().normalize()
    }

    fn from_rgba_u16(x: [u16; 4]) -> Self::Output {
        x.into_rgb().normalize()
    }

    fn from_rgba_f32(x: [f32; 4]) -> Self::Output {
        x.into_rgb().normalize()
    }
}

impl Cast for RgbaU8 {
    type Output = [u8; 4];

    fn from_rgb_u8(x: [u8; 3]) -> Self::Output {
        x.normalize().into_rgba()
    }

    fn from_rgb_u16(x: [u16; 3]) -> Self::Output {
        x.normalize().into_rgba()
    }

    fn from_rgb_f32(x: [f32; 3]) -> Self::Output {
        x.normalize().into_rgba()
    }

    fn from_rgba_u8(x: [u8; 4]) -> Self::Output {
        x.normalize().into_rgba()
    }

    fn from_rgba_u16(x: [u16; 4]) -> Self::Output {
        x.normalize().into_rgba()
    }

    fn from_rgba_f32(x: [f32; 4]) -> Self::Output {
        x.normalize().into_rgba()
    }
}

impl Cast for RgbaU16 {
    type Output = [u16; 4];

    fn from_rgb_u8(x: [u8; 3]) -> Self::Output {
        x.normalize().into_rgba()
    }

    fn from_rgb_u16(x: [u16; 3]) -> Self::Output {
        x.normalize().into_rgba()
    }

    fn from_rgb_f32(x: [f32; 3]) -> Self::Output {
        x.normalize().into_rgba()
    }

    fn from_rgba_u8(x: [u8; 4]) -> Self::Output {
        x.normalize().into_rgba()
    }

    fn from_rgba_u16(x: [u16; 4]) -> Self::Output {
        x.normalize().into_rgba()
    }

    fn from_rgba_f32(x: [f32; 4]) -> Self::Output {
        x.normalize().into_rgba()
    }
}

impl Cast for RgbaF32 {
    type Output = [f32; 4];

    fn from_rgb_u8(x: [u8; 3]) -> Self::Output {
        x.normalize().into_rgba()
    }

    fn from_rgb_u16(x: [u16; 3]) -> Self::Output {
        x.normalize().into_rgba()
    }

    fn from_rgb_f32(x: [f32; 3]) -> Self::Output {
        x.normalize().into_rgba()
    }

    fn from_rgba_u8(x: [u8; 4]) -> Self::Output {
        x.normalize().into_rgba()
    }

    fn from_rgba_u16(x: [u16; 4]) -> Self::Output {
        x.normalize().into_rgba()
    }

    fn from_rgba_f32(x: [f32; 4]) -> Self::Output {
        x.normalize().into_rgba()
    }
}
<|endoftext|>


<commit_before>use std::fs;
use std::io::Cursor;

use clap::{App, AppSettings, Arg};

use octobuild::version::{AUTHORS, VERSION};
use octobuild::vs::postprocess;

fn bench_filter(path: &str, marker: &Option<String>, keep_headers: bool, num: usize) -> Vec<u8> {
    let source = fs::read(path).unwrap();

    let mut total: usize = 0;
    let mut result = Vec::with_capacity(source.len());
    for _ in 0..num {
        result.clear();
        postprocess::filter_preprocessed(
            &mut Cursor::new(source.clone()),
            &mut result,
            &marker,
            keep_headers,
        )
        .unwrap();
        total += result.len();
    }
    assert_eq!(total / num, result.len());
    result
}

fn main() {
    const MARKER: &str = "marker";
    const INPUT: &str = "input";
    const COUNT: &str = "count";
    const KEEP: &str = "keep";

    let matches = App::new("filter_cl")
        .setting(AppSettings::ArgRequiredElseHelp)
        .version(VERSION)
        .author(AUTHORS)
        .about("Preprocessor filter for CL.exe compiler test tool")
        .arg(
            Arg::with_name(MARKER)
                .short("m")
                .long("marker")
                .value_name("header")
                .takes_value(true)
                .help("Precompiled header marker (like StdAfx.h)"),
        )
        .arg(
            Arg::with_name(KEEP)
                .short("k")
                .long("keep")
                .help("Keep header before precompiled header marker"),
        )
        .arg(
            Arg::with_name(COUNT)
                .short("c")
                .long("count")
                .default_value("1")
                .help("Iteration count"),
        )
        .arg(
            Arg::with_name(INPUT)
                .required(true)
                .index(1)
                .help("Preprocessed input file"),
        )
        .get_matches();

    let inputs = matches.values_of_lossy(INPUT).unwrap();
    let marker = matches.value_of(MARKER).map(|s| s.to_string());
    let keep = matches.is_present(KEEP);
    let count = matches
        .value_of(COUNT)
        .unwrap_or("1")
        .parse::<usize>()
        .unwrap();

    for input in inputs.iter() {
        bench_filter(input, &marker, keep, count);
    }
}
<commit_msg>Fix clippy warnings<commit_after>use std::fs;
use std::io::Cursor;

use clap::{App, AppSettings, Arg};

use octobuild::version::{AUTHORS, VERSION};
use octobuild::vs::postprocess;

fn bench_filter(path: &str, marker: &Option<String>, keep_headers: bool, num: usize) -> Vec<u8> {
    let source = fs::read(path).unwrap();

    let mut total: usize = 0;
    let mut result = Vec::with_capacity(source.len());
    for _ in 0..num {
        result.clear();
        postprocess::filter_preprocessed(
            &mut Cursor::new(source.clone()),
            &mut result,
            marker,
            keep_headers,
        )
        .unwrap();
        total += result.len();
    }
    assert_eq!(total / num, result.len());
    result
}

fn main() {
    const MARKER: &str = "marker";
    const INPUT: &str = "input";
    const COUNT: &str = "count";
    const KEEP: &str = "keep";

    let matches = App::new("filter_cl")
        .setting(AppSettings::ArgRequiredElseHelp)
        .version(VERSION)
        .author(AUTHORS)
        .about("Preprocessor filter for CL.exe compiler test tool")
        .arg(
            Arg::with_name(MARKER)
                .short("m")
                .long("marker")
                .value_name("header")
                .takes_value(true)
                .help("Precompiled header marker (like StdAfx.h)"),
        )
        .arg(
            Arg::with_name(KEEP)
                .short("k")
                .long("keep")
                .help("Keep header before precompiled header marker"),
        )
        .arg(
            Arg::with_name(COUNT)
                .short("c")
                .long("count")
                .default_value("1")
                .help("Iteration count"),
        )
        .arg(
            Arg::with_name(INPUT)
                .required(true)
                .index(1)
                .help("Preprocessed input file"),
        )
        .get_matches();

    let inputs = matches.values_of_lossy(INPUT).unwrap();
    let marker = matches.value_of(MARKER).map(|s| s.to_string());
    let keep = matches.is_present(KEEP);
    let count = matches
        .value_of(COUNT)
        .unwrap_or("1")
        .parse::<usize>()
        .unwrap();

    for input in inputs.iter() {
        bench_filter(input, &marker, keep, count);
    }
}
<|endoftext|>


<commit_before>//! This example illustrates the use of try-setters.
//! Tests are suppressed so that this doesn't break the build on stable.
#![cfg(not(test))]
#![feature(try_from)]

#[macro_use]
extern crate derive_builder;

use std::convert::TryFrom;
use std::net::{IpAddr, AddrParseError};
use std::str::FromStr;
use std::string::ToString;

/// Temporary newtype hack around lack of TryFrom implementations
/// in std. The rust-lang issue on the subject says that there will be a
/// blanket impl for everything that currently implements FromStr, which
/// will make this feature much more useful for input validation.
#[derive(Debug, Clone, PartialEq)]
pub struct MyAddr(IpAddr);

impl From<IpAddr> for MyAddr {
    fn from(v: IpAddr) -> Self {
        MyAddr(v)
    }
}

impl<'a> TryFrom<&'a str> for MyAddr {
    type Err = AddrParseError;

    fn try_from(v: &str) -> Result<Self, AddrParseError> {
        Ok(MyAddr(IpAddr::from_str(v)?))
    }
}

#[derive(Builder, Debug, PartialEq)]
#[builder(try_setter, setter(into))]
struct Lorem {
    pub name: String,
    pub addr: MyAddr,
}

fn main() {
    create("Jane", "1.2.3.4").unwrap();
    create("Bobby", "").unwrap_err();
}

fn create(name: &str, addr: &str) -> Result<Lorem, String> {
    // Fallible and infallible setters can be mixed freely when using
    // the mutable builder pattern.
    LoremBuilder::default()
        .name(name)
        .try_addr(addr).map_err(|e| e.to_string())?
        .build()
}<commit_msg>Trying to fix tests again by blocking the try_setter example from running<commit_after>//! This example illustrates the use of try-setters.
//! Tests are suppressed using a fake feature so that this doesn't break the build on stable.
#![cfg(feature = "try_from")]
#![feature(try_from)]

#[macro_use]
extern crate derive_builder;

use std::convert::TryFrom;
use std::net::{IpAddr, AddrParseError};
use std::str::FromStr;
use std::string::ToString;

/// Temporary newtype hack around lack of TryFrom implementations
/// in std. The rust-lang issue on the subject says that there will be a
/// blanket impl for everything that currently implements FromStr, which
/// will make this feature much more useful for input validation.
#[derive(Debug, Clone, PartialEq)]
pub struct MyAddr(IpAddr);

impl From<IpAddr> for MyAddr {
    fn from(v: IpAddr) -> Self {
        MyAddr(v)
    }
}

impl<'a> TryFrom<&'a str> for MyAddr {
    type Err = AddrParseError;

    fn try_from(v: &str) -> Result<Self, AddrParseError> {
        Ok(MyAddr(IpAddr::from_str(v)?))
    }
}

#[derive(Builder, Debug, PartialEq)]
#[builder(try_setter, setter(into))]
struct Lorem {
    pub name: String,
    pub addr: MyAddr,
}

fn main() {
    create("Jane", "1.2.3.4").unwrap();
    create("Bobby", "").unwrap_err();
}

fn create(name: &str, addr: &str) -> Result<Lorem, String> {
    // Fallible and infallible setters can be mixed freely when using
    // the mutable builder pattern.
    LoremBuilder::default()
        .name(name)
        .try_addr(addr).map_err(|e| e.to_string())?
        .build()
}<|endoftext|>


<commit_before>use std::marker::PhantomData;

use crate::backend::Backend;
use crate::expression::*;
use crate::query_builder::*;
use crate::query_dsl::RunQueryDsl;
use crate::result::QueryResult;
use crate::sql_types::{DieselNumericOps, SqlType};

#[derive(Debug, Clone, DieselNumericOps)]
#[must_use = "Queries are only executed when calling `load`, `get_result`, or similar."]
/// Returned by the [`sql()`] function.
///
/// [`sql()`]: ../dsl/fn.sql.html
pub struct SqlLiteral<ST, T = ()> {
    sql: String,
    inner: T,
    _marker: PhantomData<ST>,
}

impl<ST, T> SqlLiteral<ST, T>
where
    ST: TypedExpressionType,
{
    #[doc(hidden)]
    pub fn new(sql: String, inner: T) -> Self {
        SqlLiteral {
            sql: sql,
            inner: inner,
            _marker: PhantomData,
        }
    }

    /// Bind a value for use with this SQL query.
    ///
    /// # Safety
    ///
    /// This function should be used with care, as Diesel cannot validate that
    /// the value is of the right type nor can it validate that you have passed
    /// the correct number of parameters.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #    users {
    /// #        id -> Integer,
    /// #        name -> VarChar,
    /// #    }
    /// # }
    /// #
    /// # fn main() {
    /// #     use self::users::dsl::*;
    /// #     use diesel::dsl::sql;
    /// #     use diesel::sql_types::{Integer, Text, Bool};
    /// #     let connection = establish_connection();
    /// let seans_id = users
    ///     .select(id)
    ///     .filter(sql::<Bool>("name = ").bind::<Text, _>("Sean"))
    ///     .get_result(&connection);
    /// assert_eq!(Ok(1), seans_id);
    ///
    /// let tess_id = sql::<Integer>("SELECT id FROM users WHERE name = ")
    ///     .bind::<Text, _>("Tess")
    ///     .get_result(&connection);
    /// assert_eq!(Ok(2), tess_id);
    /// # }
    /// ```
    ///
    /// ### Multiple Bind Params
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #    users {
    /// #        id -> Integer,
    /// #        name -> VarChar,
    /// #    }
    /// # }
    /// #
    /// # fn main() {
    /// #     use self::users::dsl::*;
    /// #     use diesel::dsl::sql;
    /// #     use diesel::sql_types::{Integer, Text, Bool};
    /// #     let connection = establish_connection();
    /// #     diesel::insert_into(users).values(name.eq("Ryan"))
    /// #           .execute(&connection).unwrap();
    /// let query = users
    ///     .select(name)
    ///     .filter(
    ///         sql::<Bool>("id > ")
    ///         .bind::<Integer,_>(1)
    ///         .sql(" AND name <> ")
    ///         .bind::<Text, _>("Ryan")
    ///     )
    ///     .get_results(&connection);
    /// let expected = vec!["Tess".to_string()];
    /// assert_eq!(Ok(expected), query);
    /// # }
    /// ```
    pub fn bind<BindST, U>(self, bind_value: U) -> UncheckedBind<Self, U::Expression>
    where
        BindST: SqlType + TypedExpressionType,
        U: AsExpression<BindST>,
    {
        UncheckedBind::new(self, bind_value.as_expression())
    }

    /// Use literal SQL in the query builder
    ///
    /// This function is intended for use when you need a small bit of raw SQL in
    /// your query. If you want to write the entire query using raw SQL, use
    /// [`sql_query`](../fn.sql_query.html) instead.
    ///
    /// # Safety
    ///
    /// This function should be used with care, as Diesel cannot validate that
    /// the value is of the right type nor can it validate that you have passed
    /// the correct number of parameters.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #    users {
    /// #        id -> Integer,
    /// #        name -> VarChar,
    /// #    }
    /// # }
    /// #
    /// # fn main() {
    /// #     use self::users::dsl::*;
    /// #     use diesel::dsl::sql;
    /// #     use diesel::sql_types::Bool;
    /// #     let connection = establish_connection();
    /// #     diesel::insert_into(users).values(name.eq("Ryan"))
    /// #           .execute(&connection).unwrap();
    /// let query = users
    ///     .select(name)
    ///     .filter(
    ///         sql::<Bool>("id > 1")
    ///         .sql(" AND name <> 'Ryan'")
    ///     )
    ///     .get_results(&connection);
    /// let expected = vec!["Tess".to_string()];
    /// assert_eq!(Ok(expected), query);
    /// # }
    /// ```
    pub fn sql(self, sql: &str) -> SqlLiteral<ST, Self> {
        SqlLiteral::new(sql.into(), self)
    }
}

impl<ST, T> Expression for SqlLiteral<ST, T>
where
    ST: TypedExpressionType,
{
    type SqlType = ST;
}

impl<ST, T, DB> QueryFragment<DB> for SqlLiteral<ST, T>
where
    DB: Backend,
    T: QueryFragment<DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.unsafe_to_cache_prepared();
        self.inner.walk_ast(out.reborrow())?;
        out.push_sql(&self.sql);
        Ok(())
    }
}

impl<ST, T> QueryId for SqlLiteral<ST, T> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}

impl<ST, T> Query for SqlLiteral<ST, T>
where
    Self: Expression,
{
    type SqlType = ST;
}

impl<ST, T, Conn> RunQueryDsl<Conn> for SqlLiteral<ST, T> {}

impl<QS, ST, T> SelectableExpression<QS> for SqlLiteral<ST, T> where Self: Expression {}

impl<QS, ST, T> AppearsOnTable<QS> for SqlLiteral<ST, T> where Self: Expression {}

impl<ST, T, GB> ValidGrouping<GB> for SqlLiteral<ST, T> {
    type IsAggregate = is_aggregate::Never;
}

/// Use literal SQL in the query builder.
///
/// Available for when you truly cannot represent something using the expression
/// DSL. You will need to provide the SQL type of the expression, in addition to
/// the SQL.
///
/// This function is intended for use when you need a small bit of raw SQL in
/// your query. If you want to write the entire query using raw SQL, use
/// [`sql_query`](../fn.sql_query.html) instead.
///
/// Query parameters can be bound into the literal SQL using [`SqlLiteral::bind()`].
///
/// # Safety
///
/// The compiler will be unable to verify the correctness of the annotated type.
/// If you give the wrong type, it'll either return an error when deserializing
/// the query result or produce unexpected values.
///
/// # Examples
///
/// ```rust
/// # include!("../doctest_setup.rs");
/// # fn main() {
/// #     use schema::users::dsl::*;
/// #     use diesel::sql_types::{Bool, Integer, Text};
/// use diesel::dsl::sql;
/// #     let connection = establish_connection();
/// let sean = (1, String::from("Sean"));
/// assert_eq!(Ok(sean), users.filter(sql::<Bool>("name = 'Sean'")).first(&connection));
///
/// # let connection = establish_connection();
/// # diesel::insert_into(users::table)
/// #     .values(users::name.eq("Jim"))
/// #     .execute(&connection).unwrap();
/// let query = users
///     .select(name)
///     .filter(
///         sql::<Bool>("id > ")
///         .bind::<Integer,_>(1)
///         .sql(" AND name <> ")
///         .bind::<Text, _>("Ryan")
///     )
///     .get_results(&connection);
/// let expected = vec!["Tess".to_string()];
/// assert_eq!(Ok(expected), query);
/// # }
/// ```
/// [`SqlLiteral::bind()`]: ../expression/struct.SqlLiteral.html#method.bind
pub fn sql<ST>(sql: &str) -> SqlLiteral<ST>
where
    ST: TypedExpressionType,
{
    SqlLiteral::new(sql.into(), ())
}

#[derive(QueryId, Debug, Clone, Copy)]
#[must_use = "Queries are only executed when calling `load`, `get_result`, or similar."]
/// Returned by the [`SqlLiteral::bind()`] method when binding a value to a fragment of SQL.
///
/// [`SqlLiteral::bind()`]: ./struct.SqlLiteral.html#method.bind
pub struct UncheckedBind<Query, Value> {
    query: Query,
    value: Value,
}

impl<Query, Value> UncheckedBind<Query, Value>
where
    Query: Expression,
{
    pub(crate) fn new(query: Query, value: Value) -> Self {
        UncheckedBind { query, value }
    }

    /// Use literal SQL in the query builder.
    ///
    /// This function is intended for use when you need a small bit of raw SQL in
    /// your query. If you want to write the entire query using raw SQL, use
    /// [`sql_query`](../fn.sql_query.html) instead.
    ///
    /// # Safety
    ///
    /// This function should be used with care, as Diesel cannot validate that
    /// the value is of the right type nor can it validate that you have passed
    /// the correct number of parameters.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #    users {
    /// #        id -> Integer,
    /// #        name -> VarChar,
    /// #    }
    /// # }
    /// #
    /// # fn main() {
    /// #     use self::users::dsl::*;
    /// #     use diesel::dsl::sql;
    /// #     use diesel::sql_types::{Integer, Bool};
    /// #     let connection = establish_connection();
    /// #     diesel::insert_into(users).values(name.eq("Ryan"))
    /// #           .execute(&connection).unwrap();
    /// let query = users
    ///     .select(name)
    ///     .filter(
    ///         sql::<Bool>("id > ")
    ///         .bind::<Integer,_>(1)
    ///         .sql(" AND name <> 'Ryan'")
    ///     )
    ///     .get_results(&connection);
    /// let expected = vec!["Tess".to_string()];
    /// assert_eq!(Ok(expected), query);
    /// # }
    /// ```
    pub fn sql(self, sql: &str) -> SqlLiteral<Query::SqlType, Self> {
        SqlLiteral::new(sql.into(), self)
    }
}

impl<Query, Value> Expression for UncheckedBind<Query, Value>
where
    Query: Expression,
{
    type SqlType = Query::SqlType;
}

impl<Query, Value, DB> QueryFragment<DB> for UncheckedBind<Query, Value>
where
    DB: Backend,
    Query: QueryFragment<DB>,
    Value: QueryFragment<DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        self.query.walk_ast(out.reborrow())?;
        self.value.walk_ast(out.reborrow())?;
        Ok(())
    }
}

impl<Q, Value> Query for UncheckedBind<Q, Value>
where
    Q: Query,
{
    type SqlType = Q::SqlType;
}

impl<Query, Value, GB> ValidGrouping<GB> for UncheckedBind<Query, Value> {
    type IsAggregate = is_aggregate::Never;
}

impl<QS, Query, Value> SelectableExpression<QS> for UncheckedBind<Query, Value> where
    Self: AppearsOnTable<QS>
{
}

impl<QS, Query, Value> AppearsOnTable<QS> for UncheckedBind<Query, Value> where Self: Expression {}

impl<Query, Value, Conn> RunQueryDsl<Conn> for UncheckedBind<Query, Value> {}
<commit_msg>Fix warning raised by GitHub checks<commit_after>use std::marker::PhantomData;

use crate::backend::Backend;
use crate::expression::*;
use crate::query_builder::*;
use crate::query_dsl::RunQueryDsl;
use crate::result::QueryResult;
use crate::sql_types::{DieselNumericOps, SqlType};

#[derive(Debug, Clone, DieselNumericOps)]
#[must_use = "Queries are only executed when calling `load`, `get_result`, or similar."]
/// Returned by the [`sql()`] function.
///
/// [`sql()`]: ../dsl/fn.sql.html
pub struct SqlLiteral<ST, T = ()> {
    sql: String,
    inner: T,
    _marker: PhantomData<ST>,
}

impl<ST, T> SqlLiteral<ST, T>
where
    ST: TypedExpressionType,
{
    #[doc(hidden)]
    pub fn new(sql: String, inner: T) -> Self {
        SqlLiteral {
            sql: sql,
            inner: inner,
            _marker: PhantomData,
        }
    }

    /// Bind a value for use with this SQL query.
    ///
    /// # Safety
    ///
    /// This function should be used with care, as Diesel cannot validate that
    /// the value is of the right type nor can it validate that you have passed
    /// the correct number of parameters.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #    users {
    /// #        id -> Integer,
    /// #        name -> VarChar,
    /// #    }
    /// # }
    /// #
    /// # fn main() {
    /// #     use self::users::dsl::*;
    /// #     use diesel::dsl::sql;
    /// #     use diesel::sql_types::{Integer, Text, Bool};
    /// #     let connection = establish_connection();
    /// let seans_id = users
    ///     .select(id)
    ///     .filter(sql::<Bool>("name = ").bind::<Text, _>("Sean"))
    ///     .get_result(&connection);
    /// assert_eq!(Ok(1), seans_id);
    ///
    /// let tess_id = sql::<Integer>("SELECT id FROM users WHERE name = ")
    ///     .bind::<Text, _>("Tess")
    ///     .get_result(&connection);
    /// assert_eq!(Ok(2), tess_id);
    /// # }
    /// ```
    ///
    /// ### Multiple Bind Params
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #    users {
    /// #        id -> Integer,
    /// #        name -> VarChar,
    /// #    }
    /// # }
    /// #
    /// # fn main() {
    /// #     use self::users::dsl::*;
    /// #     use diesel::dsl::sql;
    /// #     use diesel::sql_types::{Integer, Text, Bool};
    /// #     let connection = establish_connection();
    /// #     diesel::insert_into(users).values(name.eq("Ryan"))
    /// #           .execute(&connection).unwrap();
    /// let query = users
    ///     .select(name)
    ///     .filter(
    ///         sql::<Bool>("id > ")
    ///         .bind::<Integer,_>(1)
    ///         .sql(" AND name <> ")
    ///         .bind::<Text, _>("Ryan")
    ///     )
    ///     .get_results(&connection);
    /// let expected = vec!["Tess".to_string()];
    /// assert_eq!(Ok(expected), query);
    /// # }
    /// ```
    pub fn bind<BindST, U>(self, bind_value: U) -> UncheckedBind<Self, U::Expression>
    where
        BindST: SqlType + TypedExpressionType,
        U: AsExpression<BindST>,
    {
        UncheckedBind::new(self, bind_value.as_expression())
    }

    /// Use literal SQL in the query builder
    ///
    /// This function is intended for use when you need a small bit of raw SQL in
    /// your query. If you want to write the entire query using raw SQL, use
    /// [`sql_query`](../fn.sql_query.html) instead.
    ///
    /// # Safety
    ///
    /// This function should be used with care, as Diesel cannot validate that
    /// the value is of the right type nor can it validate that you have passed
    /// the correct number of parameters.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #    users {
    /// #        id -> Integer,
    /// #        name -> VarChar,
    /// #    }
    /// # }
    /// #
    /// # fn main() {
    /// #     use self::users::dsl::*;
    /// #     use diesel::dsl::sql;
    /// #     use diesel::sql_types::Bool;
    /// #     let connection = establish_connection();
    /// #     diesel::insert_into(users).values(name.eq("Ryan"))
    /// #           .execute(&connection).unwrap();
    /// let query = users
    ///     .select(name)
    ///     .filter(
    ///         sql::<Bool>("id > 1")
    ///         .sql(" AND name <> 'Ryan'")
    ///     )
    ///     .get_results(&connection);
    /// let expected = vec!["Tess".to_string()];
    /// assert_eq!(Ok(expected), query);
    /// # }
    /// ```
    pub fn sql(self, sql: &str) -> SqlLiteral<ST, Self> {
        SqlLiteral::new(sql.into(), self)
    }
}

impl<ST, T> Expression for SqlLiteral<ST, T>
where
    ST: TypedExpressionType,
{
    type SqlType = ST;
}

impl<ST, T, DB> QueryFragment<DB> for SqlLiteral<ST, T>
where
    DB: Backend,
    T: QueryFragment<DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.unsafe_to_cache_prepared();
        self.inner.walk_ast(out.reborrow())?;
        out.push_sql(&self.sql);
        Ok(())
    }
}

impl<ST, T> QueryId for SqlLiteral<ST, T> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}

impl<ST, T> Query for SqlLiteral<ST, T>
where
    Self: Expression,
{
    type SqlType = ST;
}

impl<ST, T, Conn> RunQueryDsl<Conn> for SqlLiteral<ST, T> {}

impl<QS, ST, T> SelectableExpression<QS> for SqlLiteral<ST, T> where Self: Expression {}

impl<QS, ST, T> AppearsOnTable<QS> for SqlLiteral<ST, T> where Self: Expression {}

impl<ST, T, GB> ValidGrouping<GB> for SqlLiteral<ST, T> {
    type IsAggregate = is_aggregate::Never;
}

/// Use literal SQL in the query builder.
///
/// Available for when you truly cannot represent something using the expression
/// DSL. You will need to provide the SQL type of the expression, in addition to
/// the SQL.
///
/// This function is intended for use when you need a small bit of raw SQL in
/// your query. If you want to write the entire query using raw SQL, use
/// [`sql_query`](../fn.sql_query.html) instead.
///
/// Query parameters can be bound into the literal SQL using [`SqlLiteral::bind()`].
///
/// # Safety
///
/// The compiler will be unable to verify the correctness of the annotated type.
/// If you give the wrong type, it'll either return an error when deserializing
/// the query result or produce unexpected values.
///
/// # Examples
///
/// ```rust
/// # include!("../doctest_setup.rs");
/// # fn main() {
/// #     run_test_1().unwrap();
/// #     run_test_2().unwrap();
/// # }
/// #
/// # fn run_test_1() -> QueryResult<()> {
/// #     use schema::users::dsl::*;
/// #     use diesel::sql_types::Bool;
/// use diesel::dsl::sql;
/// #     let connection = establish_connection();
/// let user = users.filter(sql::<Bool>("name = 'Sean'")).first(&connection)?;
/// let expected = (1, String::from("Sean"));
/// assert_eq!(expected, user);
/// #     Ok(())
/// # }
/// #
/// # fn run_test_2() -> QueryResult<()> {
/// #     use schema::users;
/// #     use diesel::sql_types::{Bool, Integer, Text};
/// #     let connection = establish_connection();
/// #     diesel::insert_into(users::table)
/// #         .values(users::name.eq("Jim"))
/// #         .execute(&connection).unwrap();
/// let query = users
///     .select(name)
///     .filter(
///         sql::<Bool>("id > ")
///         .bind::<Integer,_>(1)
///         .sql(" AND name <> ")
///         .bind::<Text, _>("Ryan")
///     )
///     .get_results(&connection);
/// let expected = vec!["Tess".to_string()];
/// assert_eq!(Ok(expected), query);
/// #     Ok(())
/// # }
/// ```
/// [`SqlLiteral::bind()`]: ../expression/struct.SqlLiteral.html#method.bind
pub fn sql<ST>(sql: &str) -> SqlLiteral<ST>
where
    ST: TypedExpressionType,
{
    SqlLiteral::new(sql.into(), ())
}

#[derive(QueryId, Debug, Clone, Copy)]
#[must_use = "Queries are only executed when calling `load`, `get_result`, or similar."]
/// Returned by the [`SqlLiteral::bind()`] method when binding a value to a fragment of SQL.
///
/// [`SqlLiteral::bind()`]: ./struct.SqlLiteral.html#method.bind
pub struct UncheckedBind<Query, Value> {
    query: Query,
    value: Value,
}

impl<Query, Value> UncheckedBind<Query, Value>
where
    Query: Expression,
{
    pub(crate) fn new(query: Query, value: Value) -> Self {
        UncheckedBind { query, value }
    }

    /// Use literal SQL in the query builder.
    ///
    /// This function is intended for use when you need a small bit of raw SQL in
    /// your query. If you want to write the entire query using raw SQL, use
    /// [`sql_query`](../fn.sql_query.html) instead.
    ///
    /// # Safety
    ///
    /// This function should be used with care, as Diesel cannot validate that
    /// the value is of the right type nor can it validate that you have passed
    /// the correct number of parameters.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #    users {
    /// #        id -> Integer,
    /// #        name -> VarChar,
    /// #    }
    /// # }
    /// #
    /// # fn main() {
    /// #     use self::users::dsl::*;
    /// #     use diesel::dsl::sql;
    /// #     use diesel::sql_types::{Integer, Bool};
    /// #     let connection = establish_connection();
    /// #     diesel::insert_into(users).values(name.eq("Ryan"))
    /// #           .execute(&connection).unwrap();
    /// let query = users
    ///     .select(name)
    ///     .filter(
    ///         sql::<Bool>("id > ")
    ///         .bind::<Integer,_>(1)
    ///         .sql(" AND name <> 'Ryan'")
    ///     )
    ///     .get_results(&connection);
    /// let expected = vec!["Tess".to_string()];
    /// assert_eq!(Ok(expected), query);
    /// # }
    /// ```
    pub fn sql(self, sql: &str) -> SqlLiteral<Query::SqlType, Self> {
        SqlLiteral::new(sql.into(), self)
    }
}

impl<Query, Value> Expression for UncheckedBind<Query, Value>
where
    Query: Expression,
{
    type SqlType = Query::SqlType;
}

impl<Query, Value, DB> QueryFragment<DB> for UncheckedBind<Query, Value>
where
    DB: Backend,
    Query: QueryFragment<DB>,
    Value: QueryFragment<DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        self.query.walk_ast(out.reborrow())?;
        self.value.walk_ast(out.reborrow())?;
        Ok(())
    }
}

impl<Q, Value> Query for UncheckedBind<Q, Value>
where
    Q: Query,
{
    type SqlType = Q::SqlType;
}

impl<Query, Value, GB> ValidGrouping<GB> for UncheckedBind<Query, Value> {
    type IsAggregate = is_aggregate::Never;
}

impl<QS, Query, Value> SelectableExpression<QS> for UncheckedBind<Query, Value> where
    Self: AppearsOnTable<QS>
{
}

impl<QS, Query, Value> AppearsOnTable<QS> for UncheckedBind<Query, Value> where Self: Expression {}

impl<Query, Value, Conn> RunQueryDsl<Conn> for UncheckedBind<Query, Value> {}
<|endoftext|>


<commit_before>use crate::http_metrics;
use crate::{DutiesService, ProductionValidatorClient};
use lighthouse_metrics::set_gauge;
use slog::{error, info, Logger};
use slot_clock::SlotClock;
use tokio::time::{sleep, Duration};
use types::EthSpec;

/// Spawns a notifier service which periodically logs information about the node.
pub fn spawn_notifier<T: EthSpec>(client: &ProductionValidatorClient<T>) -> Result<(), String> {
    let context = client.context.service_context("notifier".into());
    let executor = context.executor.clone();
    let duties_service = client.duties_service.clone();

    let slot_duration = Duration::from_secs(context.eth2_config.spec.seconds_per_slot);

    let interval_fut = async move {
        let log = context.log();

        loop {
            if let Some(duration_to_next_slot) = duties_service.slot_clock.duration_to_next_slot() {
                sleep(duration_to_next_slot + slot_duration / 2).await;
                notify(&duties_service, log).await;
            } else {
                error!(log, "Failed to read slot clock");
                // If we can't read the slot clock, just wait another slot.
                sleep(slot_duration).await;
                continue;
            }
        }
    };

    executor.spawn(interval_fut, "validator_notifier");
    Ok(())
}

/// Performs a single notification routine.
async fn notify<T: SlotClock + 'static, E: EthSpec>(
    duties_service: &DutiesService<T, E>,
    log: &Logger,
) {
    let num_available = duties_service.beacon_nodes.num_available().await;
    let num_synced = duties_service.beacon_nodes.num_synced().await;
    let num_total = duties_service.beacon_nodes.num_total();
    if num_synced > 0 {
        info!(
            log,
            "Connected to beacon node(s)";
            "total" => num_total,
            "available" => num_available,
            "synced" => num_synced,
        )
    } else {
        error!(
            log,
            "No synced beacon nodes";
            "total" => num_total,
            "available" => num_available,
            "synced" => num_synced,
        )
    }
    let num_synced_fallback = duties_service.beacon_nodes.num_synced_fallback().await;
    if num_synced_fallback > 0 {
        set_gauge(&http_metrics::metrics::ETH2_FALLBACK_CONNECTED, 1);
    } else {
        set_gauge(&http_metrics::metrics::ETH2_FALLBACK_CONNECTED, 0);
    }

    if let Some(slot) = duties_service.slot_clock.now() {
        let epoch = slot.epoch(E::slots_per_epoch());

        let total_validators = duties_service.total_validator_count();
        let proposing_validators = duties_service.proposer_count(epoch);
        let attesting_validators = duties_service.attester_count(epoch);
        let doppelganger_detecting_validators = duties_service.doppelganger_detecting_count();

        if doppelganger_detecting_validators > 0 {
            info!(log, "Listening for doppelgangers"; "doppelganger_detecting_validators" => doppelganger_detecting_validators)
        }

        if total_validators == 0 {
            info!(
                log,
                "No validators present";
                "msg" => "see `lighthouse account validator create --help` \
                or the HTTP API documentation"
            )
        } else if total_validators == attesting_validators {
            info!(
                log,
                "All validators active";
                "proposers" => proposing_validators,
                "active_validators" => attesting_validators,
                "total_validators" => total_validators,
                "epoch" => format!("{}", epoch),
                "slot" => format!("{}", slot),
            );
        } else if attesting_validators > 0 {
            info!(
                log,
                "Some validators active";
                "proposers" => proposing_validators,
                "active_validators" => attesting_validators,
                "total_validators" => total_validators,
                "epoch" => format!("{}", epoch),
                "slot" => format!("{}", slot),
            );
        } else {
            info!(
                log,
                "Awaiting activation";
                "validators" => total_validators,
                "epoch" => format!("{}", epoch),
                "slot" => format!("{}", slot),
            );
        }
    } else {
        error!(log, "Unable to read slot clock");
    }
}
<commit_msg>Clarify proposers message is about current epoch (#3084)<commit_after>use crate::http_metrics;
use crate::{DutiesService, ProductionValidatorClient};
use lighthouse_metrics::set_gauge;
use slog::{error, info, Logger};
use slot_clock::SlotClock;
use tokio::time::{sleep, Duration};
use types::EthSpec;

/// Spawns a notifier service which periodically logs information about the node.
pub fn spawn_notifier<T: EthSpec>(client: &ProductionValidatorClient<T>) -> Result<(), String> {
    let context = client.context.service_context("notifier".into());
    let executor = context.executor.clone();
    let duties_service = client.duties_service.clone();

    let slot_duration = Duration::from_secs(context.eth2_config.spec.seconds_per_slot);

    let interval_fut = async move {
        let log = context.log();

        loop {
            if let Some(duration_to_next_slot) = duties_service.slot_clock.duration_to_next_slot() {
                sleep(duration_to_next_slot + slot_duration / 2).await;
                notify(&duties_service, log).await;
            } else {
                error!(log, "Failed to read slot clock");
                // If we can't read the slot clock, just wait another slot.
                sleep(slot_duration).await;
                continue;
            }
        }
    };

    executor.spawn(interval_fut, "validator_notifier");
    Ok(())
}

/// Performs a single notification routine.
async fn notify<T: SlotClock + 'static, E: EthSpec>(
    duties_service: &DutiesService<T, E>,
    log: &Logger,
) {
    let num_available = duties_service.beacon_nodes.num_available().await;
    let num_synced = duties_service.beacon_nodes.num_synced().await;
    let num_total = duties_service.beacon_nodes.num_total();
    if num_synced > 0 {
        info!(
            log,
            "Connected to beacon node(s)";
            "total" => num_total,
            "available" => num_available,
            "synced" => num_synced,
        )
    } else {
        error!(
            log,
            "No synced beacon nodes";
            "total" => num_total,
            "available" => num_available,
            "synced" => num_synced,
        )
    }
    let num_synced_fallback = duties_service.beacon_nodes.num_synced_fallback().await;
    if num_synced_fallback > 0 {
        set_gauge(&http_metrics::metrics::ETH2_FALLBACK_CONNECTED, 1);
    } else {
        set_gauge(&http_metrics::metrics::ETH2_FALLBACK_CONNECTED, 0);
    }

    if let Some(slot) = duties_service.slot_clock.now() {
        let epoch = slot.epoch(E::slots_per_epoch());

        let total_validators = duties_service.total_validator_count();
        let proposing_validators = duties_service.proposer_count(epoch);
        let attesting_validators = duties_service.attester_count(epoch);
        let doppelganger_detecting_validators = duties_service.doppelganger_detecting_count();

        if doppelganger_detecting_validators > 0 {
            info!(log, "Listening for doppelgangers"; "doppelganger_detecting_validators" => doppelganger_detecting_validators)
        }

        if total_validators == 0 {
            info!(
                log,
                "No validators present";
                "msg" => "see `lighthouse account validator create --help` \
                or the HTTP API documentation"
            )
        } else if total_validators == attesting_validators {
            info!(
                log,
                "All validators active";
                "current_epoch_proposers" => proposing_validators,
                "active_validators" => attesting_validators,
                "total_validators" => total_validators,
                "epoch" => format!("{}", epoch),
                "slot" => format!("{}", slot),
            );
        } else if attesting_validators > 0 {
            info!(
                log,
                "Some validators active";
                "current_epoch_proposers" => proposing_validators,
                "active_validators" => attesting_validators,
                "total_validators" => total_validators,
                "epoch" => format!("{}", epoch),
                "slot" => format!("{}", slot),
            );
        } else {
            info!(
                log,
                "Awaiting activation";
                "validators" => total_validators,
                "epoch" => format!("{}", epoch),
                "slot" => format!("{}", slot),
            );
        }
    } else {
        error!(log, "Unable to read slot clock");
    }
}
<|endoftext|>


<commit_before>//! Implements a command for showing infos from Sentry.
use std::io;
use std::collections::HashMap;

use clap::{App, Arg, ArgMatches};
use serde_json;

use prelude::*;
use api::Api;
use config::{Auth, Config};

#[derive(Serialize, Default)]
pub struct AuthStatus {
    #[serde(rename="type")]
    auth_type: Option<String>,
    successful: bool,
}

#[derive(Serialize, Default)]
pub struct ConfigStatus {
    config: HashMap<String, Option<String>>,
    auth: AuthStatus,
    have_dsn: bool,
}

pub fn make_app<'a, 'b: 'a>(app: App<'a, 'b>) -> App<'a, 'b> {
    app.about("print out information about the sentry server")
        .arg(Arg::with_name("quiet")
             .short("q")
             .long("quiet")
             .help("Do not output anything, just report a status \
                    code for correct config"))
        .arg(Arg::with_name("config_status_json")
             .long("config-status-json")
             .help("Returns the status of the config that sentry-cli loads \
                    as JSON dump. This can be used by external tools to aid \
                    the user towards configuration."))
}

fn describe_auth(auth: Option<&Auth>) -> &str {
    match auth {
        None => "Unauthorized",
        Some(&Auth::Token(_)) => "Auth Token",
        Some(&Auth::Key(_)) => "API Key",
    }
}

fn get_config_status_json(config: &Config) -> Result<()> {
    let mut rv = ConfigStatus::default();

    let (project, org) = config.get_org_and_project_defaults();
    rv.config.insert("org".into(), org);
    rv.config.insert("project".into(), project);
    rv.config.insert("url".into(), Some(config.url.clone()));

    rv.auth.auth_type = config.auth.as_ref().map(|val| match val {
        &Auth::Token(_) => "token".into(),
        &Auth::Key(_) => "api_key".into(),
    });
    rv.auth.successful = config.auth.is_some() && Api::new(config).get_auth_info().is_ok();
    rv.have_dsn = config.get_dsn().is_ok();

    serde_json::to_writer_pretty(&mut io::stdout(), &rv)?;
    println!("");
    Ok(())
}

pub fn execute<'a>(matches: &ArgMatches<'a>, config: &Config) -> Result<()> {
    if matches.is_present("config_status_json") {
        return get_config_status_json(config);
    }

    let (project, org) = config.get_org_and_project_defaults();
    let info_rv = Api::new(config).get_auth_info();
    let errors = project.is_none() || org.is_none() || config.auth.is_none() || info_rv.is_err();

    if !matches.is_present("quiet") {
        println!("Sentry Server: {}", config.url);
        println!("Default Organization: {}", project.unwrap_or("-".into()));
        println!("Default Project: {}", org.unwrap_or("-".into()));

        if config.auth.is_some() {
            println!("");
            println!("Authentication Info:");
            println!("  Method: {}", describe_auth(config.auth.as_ref()));
            match info_rv {
                Ok(info) => {
                    if let Some(ref user) = info.user {
                        println!("  User: {}", user.email);
                    }
                    if let Some(ref auth) = info.auth {
                        println!("  Scopes:");
                        for scope in &auth.scopes {
                            println!("    - {}", scope);
                        }
                    }
                }
                Err(err) => {
                    println!("  (failure on authentication: {})", err);
                }
            }
        }
    }

    if errors {
        Err(ErrorKind::QuietExit(1).into())
    } else {
        Ok(())
    }
}
<commit_msg>fix: Swap org and project in info.  Fixes #119<commit_after>//! Implements a command for showing infos from Sentry.
use std::io;
use std::collections::HashMap;

use clap::{App, Arg, ArgMatches};
use serde_json;

use prelude::*;
use api::Api;
use config::{Auth, Config};

#[derive(Serialize, Default)]
pub struct AuthStatus {
    #[serde(rename="type")]
    auth_type: Option<String>,
    successful: bool,
}

#[derive(Serialize, Default)]
pub struct ConfigStatus {
    config: HashMap<String, Option<String>>,
    auth: AuthStatus,
    have_dsn: bool,
}

pub fn make_app<'a, 'b: 'a>(app: App<'a, 'b>) -> App<'a, 'b> {
    app.about("print out information about the sentry server")
        .arg(Arg::with_name("quiet")
             .short("q")
             .long("quiet")
             .help("Do not output anything, just report a status \
                    code for correct config"))
        .arg(Arg::with_name("config_status_json")
             .long("config-status-json")
             .help("Returns the status of the config that sentry-cli loads \
                    as JSON dump. This can be used by external tools to aid \
                    the user towards configuration."))
}

fn describe_auth(auth: Option<&Auth>) -> &str {
    match auth {
        None => "Unauthorized",
        Some(&Auth::Token(_)) => "Auth Token",
        Some(&Auth::Key(_)) => "API Key",
    }
}

fn get_config_status_json(config: &Config) -> Result<()> {
    let mut rv = ConfigStatus::default();

    let (org, project) = config.get_org_and_project_defaults();
    rv.config.insert("org".into(), org);
    rv.config.insert("project".into(), project);
    rv.config.insert("url".into(), Some(config.url.clone()));

    rv.auth.auth_type = config.auth.as_ref().map(|val| match val {
        &Auth::Token(_) => "token".into(),
        &Auth::Key(_) => "api_key".into(),
    });
    rv.auth.successful = config.auth.is_some() && Api::new(config).get_auth_info().is_ok();
    rv.have_dsn = config.get_dsn().is_ok();

    serde_json::to_writer_pretty(&mut io::stdout(), &rv)?;
    println!("");
    Ok(())
}

pub fn execute<'a>(matches: &ArgMatches<'a>, config: &Config) -> Result<()> {
    if matches.is_present("config_status_json") {
        return get_config_status_json(config);
    }

    let (org, project) = config.get_org_and_project_defaults();
    let info_rv = Api::new(config).get_auth_info();
    let errors = project.is_none() || org.is_none() || config.auth.is_none() || info_rv.is_err();

    if !matches.is_present("quiet") {
        println!("Sentry Server: {}", config.url);
        println!("Default Organization: {}", project.unwrap_or("-".into()));
        println!("Default Project: {}", org.unwrap_or("-".into()));

        if config.auth.is_some() {
            println!("");
            println!("Authentication Info:");
            println!("  Method: {}", describe_auth(config.auth.as_ref()));
            match info_rv {
                Ok(info) => {
                    if let Some(ref user) = info.user {
                        println!("  User: {}", user.email);
                    }
                    if let Some(ref auth) = info.auth {
                        println!("  Scopes:");
                        for scope in &auth.scopes {
                            println!("    - {}", scope);
                        }
                    }
                }
                Err(err) => {
                    println!("  (failure on authentication: {})", err);
                }
            }
        }
    }

    if errors {
        Err(ErrorKind::QuietExit(1).into())
    } else {
        Ok(())
    }
}
<|endoftext|>


<commit_before>extern crate walkdir;
extern crate chrono;

use std::path;
use self::walkdir::{WalkDir, DirEntry, Error as WalkDirError};
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
use self::chrono::{DateTime, UTC};
use std::error::Error;
use std::str::FromStr;
use std::net::SocketAddrV4;

#[derive(Debug)]
pub struct ELBRecord {
    timestamp: DateTime<UTC>,
    elb_name: String,
    client_address: SocketAddrV4,
    backend_address: SocketAddrV4,
    request_processing_time: f32,
    backend_processing_time: f32,
    response_processing_time: f32,
    elb_status_code: u16,
    backend_status_code: u16,
    received_bytes: u64,
    sent_bytes: u64,
    request_method: String,
    request_url: String,
    request_http_version: String
}

pub fn file_list(dir: &path::Path, filenames: &mut Vec<DirEntry>) -> Result<usize, WalkDirError> {
    for entry in WalkDir::new(dir).min_depth(1) {
        match entry {
            Err(err) => return Err(err),
            Ok(entry) => filenames.push(entry),
        }
    }
    Ok(filenames.len())
}

//TODO Reconsider logging based on the standard interfaces included with Rust.
//TODO We really want to accept a function to handle the parsed lines.
pub fn process_files(runtime_context: &::RuntimeContext, filenames: Vec<walkdir::DirEntry>) -> usize {
    let debug = runtime_context.debug;
    let mut record_count = 0;
    for filename in filenames {
        debug!(debug, "Processing file {}.", filename.path().display());
        match File::open(filename.path()) {
            Ok(file) => {
                let buffered_file = BufReader::new(&file);
                let recs: Vec<_> = buffered_file.lines()
                    .map(|possible_line| {
                        match possible_line {
                            Ok(record) => parse_record(record),

                            Err(_) => {
                                Err(ParsingErrors {
                                    record: "".to_string(),
                                    errors: vec![ELBRecordParsingErrors::LineReadError]
                                })
                            }
                        }
                    })
                    .collect();
                record_count += recs.len();
                debug!(debug, "Found {} records in file {}.", recs.len(), filename.path().display());
            },
            Err(e) => {
                println!("ERROR: {}", e);
            }
        }
    }

    record_count
}

//TODO Take a look at the error handling once again.  This doesn't feel write given code you've read.

#[derive(Debug)]
pub struct ParsingErrors {
    record: String,
    errors: Vec<ELBRecordParsingErrors>,
}

#[derive(Debug, PartialEq)]
enum ELBRecordParsingErrors {
    MalformedRecord,
    ParsingError { property: &'static str, description: String },
    LineReadError
}

#[derive(Debug, PartialEq, Clone, Copy)]
enum ELBRecordFields {
    Timestamp = 0,
    ELBName,
    ClientAddress,
    BackendAddress,
    RequestProcessingTime,
    BackendProcessingTime,
    ResponseProcessingTime,
    ELBStatusCode,
    BackendStatusCode,
    ReceivedBytes,
    SentBytes,
    RequestMethod,
    RequestURL,
    RequestHTTPVersion
}

impl ELBRecordFields {

  fn idx(&self) -> usize {
    *self as usize
  }

  fn as_str(&self) -> &'static str {
      match *self {
          ELBRecordFields::Timestamp => "timestamp",
          ELBRecordFields::ELBName => "ELB name",
          ELBRecordFields::ClientAddress => "client address",
          ELBRecordFields::BackendAddress => "backend address",
          ELBRecordFields::RequestProcessingTime => "request processing time",
          ELBRecordFields::BackendProcessingTime => "backend processing time",
          ELBRecordFields::ResponseProcessingTime => "response processing time",
          ELBRecordFields::ELBStatusCode => "ELB status code",
          ELBRecordFields::BackendStatusCode => "backend status code",
          ELBRecordFields::ReceivedBytes => "received bytes",
          ELBRecordFields::SentBytes => "sent bytes",
          ELBRecordFields::RequestMethod => "request method",
          ELBRecordFields::RequestURL => "request URL",
          ELBRecordFields::RequestHTTPVersion => "request HTTP version"
      }
  }
}

const ELB_RECORD_FIELD_COUNT: usize = 14;
pub fn parse_record(record: String) -> Result<Box<ELBRecord>, ParsingErrors> {
    let mut errors: Vec<ELBRecordParsingErrors> = Vec::new();

    {
        //record is borrowed by the split method which means ownership of record cannot be
        //transferred to ParsingErrors until the borrow is complete.
        //Scoping this section of code seems more readable than creating a separate function
        //just to mitigate the borrow.
        let split_line: Vec<&str> = record.split(' ').collect();
        if split_line.len() != ELB_RECORD_FIELD_COUNT {
            errors.push(ELBRecordParsingErrors::MalformedRecord);
            None
        } else {
            let ts = split_line.parse_property(ELBRecordFields::Timestamp, &mut errors);
            let clnt_addr = split_line.parse_property(ELBRecordFields::ClientAddress, &mut errors);
            let be_addr = split_line.parse_property(ELBRecordFields::BackendAddress, &mut errors);
            let req_proc_time = split_line.parse_property(ELBRecordFields::RequestProcessingTime, &mut errors);
            let be_proc_time = split_line.parse_property(ELBRecordFields::BackendProcessingTime, &mut errors);
            let res_proc_time = split_line.parse_property(ELBRecordFields::ResponseProcessingTime, &mut errors);
            let elb_sc = split_line.parse_property(ELBRecordFields::ELBStatusCode, &mut errors);
            let be_sc = split_line.parse_property(ELBRecordFields::BackendStatusCode, &mut errors);
            let bytes_received = split_line.parse_property(ELBRecordFields::ReceivedBytes, &mut errors);
            let bytes_sent = split_line.parse_property(ELBRecordFields::SentBytes, &mut errors);

            if errors.is_empty() {
                //If errors is empty it is more than likely parsing was successful and unwrap is safe.
                Some(
                    ELBRecord {
                        timestamp: ts.unwrap(),
                        elb_name: split_line[ELBRecordFields::ELBName.idx()].to_string(),
                        client_address: clnt_addr.unwrap(),
                        backend_address: be_addr.unwrap(),
                        request_processing_time: req_proc_time.unwrap(),
                        backend_processing_time: be_proc_time.unwrap(),
                        response_processing_time: res_proc_time.unwrap(),
                        elb_status_code: elb_sc.unwrap(),
                        backend_status_code: be_sc.unwrap(),
                        received_bytes: bytes_received.unwrap(),
                        sent_bytes: bytes_sent.unwrap(),
                        request_method: split_line[ELBRecordFields::RequestMethod.idx()].trim_matches('"').to_string(),
                        request_url: split_line[ELBRecordFields::RequestURL.idx()].to_string(),
                        request_http_version: split_line[ELBRecordFields::RequestHTTPVersion.idx()].trim_matches('"').to_string()
                    }
                )
            } else {
                None
            }
        }
    }.map( |elb_rec|
        Ok(Box::new(elb_rec))
    ).unwrap_or_else( ||
        Err(ParsingErrors {
            record: record,
            errors: errors
        })
    )
}

trait ELBRecordFieldParser {
    fn parse_property<T>(
        &self,
        field_id: ELBRecordFields,
        errors: &mut Vec<ELBRecordParsingErrors>
    ) -> Option<T>
        where T: FromStr,
        T::Err: Error + 'static;
}

impl<'a> ELBRecordFieldParser for Vec<&'a str> {

    fn parse_property<T>(
        &self,
        field_id: ELBRecordFields,
        errors: &mut Vec<ELBRecordParsingErrors>
    ) -> Option<T>
        where T: FromStr,
        T::Err: Error + 'static,
    {
        let raw_prop = self[field_id.idx()];
        match raw_prop.parse::<T>() {
            Ok(parsed) => Some(parsed),

            Err(e) => {
                errors.push(
                    ELBRecordParsingErrors::ParsingError {
                        property: field_id.as_str(),
                        description: e.description().to_string(),
                    }
                );
                None
            }
        }
    }
}

//TODO test the error case.
#[cfg(test)]
mod tests {
    use super::parse_record;
    use super::ELBRecordParsingErrors;

    const TEST_RECORD: &'static str = "2015-08-15T23:43:05.302180Z elb-name 172.16.1.6:54814 \
    172.16.1.5:9000 0.000039 0.145507 0.00003 200 200 0 7582 \
    \"GET http://some.domain.com:80/path0/path1?param0=p0&param1=p1 HTTP/1.1\"\
    ";

    #[test]
	fn parse_record_returns_a_malformed_record_error_for_records_short_on_values() {
        let short_record = "2015-08-15T23:43:05.302180Z elb-name 172.16.1.6:54814 \
        172.16.1.5:9000 0.000039 200 200 0 7582 \
        \"GET http://some.domain.com:80/path0/path1?param0=p0&param1=p1 HTTP/1.1\" \
        ";

        let malformed_error = parse_record(short_record.to_string()).unwrap_err().errors.pop();

		assert_eq!(malformed_error, Some(ELBRecordParsingErrors::MalformedRecord))
	}

    #[test]
	fn parse_record_returns_a_record_with_the_request_http_version() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.request_http_version, "HTTP/1.1")
	}

    #[test]
	fn parse_record_returns_a_record_with_the_request_url() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.request_url, "http://some.domain.com:80/path0/path1?param0=p0&param1=p1")
	}

    #[test]
	fn parse_record_returns_a_record_with_the_request_method() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.request_method, "GET")
	}

    #[test]
	fn parse_record_returns_a_record_with_the_sent_bytes() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.sent_bytes, 7582)
	}

    #[test]
	fn parse_record_returns_a_record_with_the_received_bytes() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.received_bytes, 0)
	}

    #[test]
	fn parse_record_returns_a_record_with_the_backend_status_code() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.backend_status_code, 200)
	}

    #[test]
	fn parse_record_returns_a_record_with_the_elb_status_code() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.elb_status_code, 200)
	}

    #[test]
	fn parse_record_returns_a_record_with_the_response_processing_time() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.response_processing_time, 0.00003)
	}

    #[test]
	fn parse_record_returns_a_record_with_the_backend_processing_time() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.backend_processing_time, 0.145507)
	}

    #[test]
	fn parse_record_returns_a_record_with_the_request_processing_time() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.request_processing_time, 0.000039)
	}

    #[test]
	fn parse_record_returns_a_record_with_the_backend_address() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.backend_address, "172.16.1.5:9000".parse().unwrap())
	}

    #[test]
	fn parse_record_returns_a_record_with_the_client_address() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.client_address, "172.16.1.6:54814".parse().unwrap())
	}

    #[test]
	fn parse_record_returns_a_record_with_the_timestamp() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(format!("{:?}", elb_record.timestamp), "2015-08-15T23:43:05.302180Z")
	}

    #[test]
	fn parse_record_returns_a_record_with_the_elb_name() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.elb_name, "elb-name")
	}
}
<commit_msg>ELBRecordParsingErrors.ParsingError.property changed to field_id with type ELBRecordFields.<commit_after>extern crate walkdir;
extern crate chrono;

use std::path;
use self::walkdir::{WalkDir, DirEntry, Error as WalkDirError};
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
use self::chrono::{DateTime, UTC};
use std::error::Error;
use std::str::FromStr;
use std::net::SocketAddrV4;

#[derive(Debug)]
pub struct ELBRecord {
    timestamp: DateTime<UTC>,
    elb_name: String,
    client_address: SocketAddrV4,
    backend_address: SocketAddrV4,
    request_processing_time: f32,
    backend_processing_time: f32,
    response_processing_time: f32,
    elb_status_code: u16,
    backend_status_code: u16,
    received_bytes: u64,
    sent_bytes: u64,
    request_method: String,
    request_url: String,
    request_http_version: String
}

pub fn file_list(dir: &path::Path, filenames: &mut Vec<DirEntry>) -> Result<usize, WalkDirError> {
    for entry in WalkDir::new(dir).min_depth(1) {
        match entry {
            Err(err) => return Err(err),
            Ok(entry) => filenames.push(entry),
        }
    }
    Ok(filenames.len())
}

//TODO Reconsider logging based on the standard interfaces included with Rust.
//TODO We really want to accept a function to handle the parsed lines.
pub fn process_files(runtime_context: &::RuntimeContext, filenames: Vec<walkdir::DirEntry>) -> usize {
    let debug = runtime_context.debug;
    let mut record_count = 0;
    for filename in filenames {
        debug!(debug, "Processing file {}.", filename.path().display());
        match File::open(filename.path()) {
            Ok(file) => {
                let buffered_file = BufReader::new(&file);
                let recs: Vec<_> = buffered_file.lines()
                    .map(|possible_line| {
                        match possible_line {
                            Ok(record) => parse_record(record),

                            Err(_) => {
                                Err(ParsingErrors {
                                    record: "".to_string(),
                                    errors: vec![ELBRecordParsingErrors::LineReadError]
                                })
                            }
                        }
                    })
                    .collect();
                record_count += recs.len();
                debug!(debug, "Found {} records in file {}.", recs.len(), filename.path().display());
            },
            Err(e) => {
                println!("ERROR: {}", e);
            }
        }
    }

    record_count
}

//TODO Take a look at the error handling once again.  This doesn't feel write given code you've read.

#[derive(Debug)]
pub struct ParsingErrors {
    record: String,
    errors: Vec<ELBRecordParsingErrors>,
}

#[derive(Debug, PartialEq)]
enum ELBRecordParsingErrors {
    MalformedRecord,
    ParsingError { field_id: ELBRecordFields, description: String },
    LineReadError
}

#[derive(Debug, PartialEq, Clone, Copy)]
enum ELBRecordFields {
    Timestamp = 0,
    ELBName,
    ClientAddress,
    BackendAddress,
    RequestProcessingTime,
    BackendProcessingTime,
    ResponseProcessingTime,
    ELBStatusCode,
    BackendStatusCode,
    ReceivedBytes,
    SentBytes,
    RequestMethod,
    RequestURL,
    RequestHTTPVersion
}

impl ELBRecordFields {

  fn idx(&self) -> usize {
    *self as usize
  }

  fn as_str(&self) -> &'static str {
      match *self {
          ELBRecordFields::Timestamp => "timestamp",
          ELBRecordFields::ELBName => "ELB name",
          ELBRecordFields::ClientAddress => "client address",
          ELBRecordFields::BackendAddress => "backend address",
          ELBRecordFields::RequestProcessingTime => "request processing time",
          ELBRecordFields::BackendProcessingTime => "backend processing time",
          ELBRecordFields::ResponseProcessingTime => "response processing time",
          ELBRecordFields::ELBStatusCode => "ELB status code",
          ELBRecordFields::BackendStatusCode => "backend status code",
          ELBRecordFields::ReceivedBytes => "received bytes",
          ELBRecordFields::SentBytes => "sent bytes",
          ELBRecordFields::RequestMethod => "request method",
          ELBRecordFields::RequestURL => "request URL",
          ELBRecordFields::RequestHTTPVersion => "request HTTP version"
      }
  }
}

const ELB_RECORD_FIELD_COUNT: usize = 14;
pub fn parse_record(record: String) -> Result<Box<ELBRecord>, ParsingErrors> {
    let mut errors: Vec<ELBRecordParsingErrors> = Vec::new();

    {
        //record is borrowed by the split method which means ownership of record cannot be
        //transferred to ParsingErrors until the borrow is complete.
        //Scoping this section of code seems more readable than creating a separate function
        //just to mitigate the borrow.
        let split_line: Vec<&str> = record.split(' ').collect();
        if split_line.len() != ELB_RECORD_FIELD_COUNT {
            errors.push(ELBRecordParsingErrors::MalformedRecord);
            None
        } else {
            let ts = split_line.parse_property(ELBRecordFields::Timestamp, &mut errors);
            let clnt_addr = split_line.parse_property(ELBRecordFields::ClientAddress, &mut errors);
            let be_addr = split_line.parse_property(ELBRecordFields::BackendAddress, &mut errors);
            let req_proc_time = split_line.parse_property(ELBRecordFields::RequestProcessingTime, &mut errors);
            let be_proc_time = split_line.parse_property(ELBRecordFields::BackendProcessingTime, &mut errors);
            let res_proc_time = split_line.parse_property(ELBRecordFields::ResponseProcessingTime, &mut errors);
            let elb_sc = split_line.parse_property(ELBRecordFields::ELBStatusCode, &mut errors);
            let be_sc = split_line.parse_property(ELBRecordFields::BackendStatusCode, &mut errors);
            let bytes_received = split_line.parse_property(ELBRecordFields::ReceivedBytes, &mut errors);
            let bytes_sent = split_line.parse_property(ELBRecordFields::SentBytes, &mut errors);

            if errors.is_empty() {
                //If errors is empty it is more than likely parsing was successful and unwrap is safe.
                Some(
                    ELBRecord {
                        timestamp: ts.unwrap(),
                        elb_name: split_line[ELBRecordFields::ELBName.idx()].to_string(),
                        client_address: clnt_addr.unwrap(),
                        backend_address: be_addr.unwrap(),
                        request_processing_time: req_proc_time.unwrap(),
                        backend_processing_time: be_proc_time.unwrap(),
                        response_processing_time: res_proc_time.unwrap(),
                        elb_status_code: elb_sc.unwrap(),
                        backend_status_code: be_sc.unwrap(),
                        received_bytes: bytes_received.unwrap(),
                        sent_bytes: bytes_sent.unwrap(),
                        request_method: split_line[ELBRecordFields::RequestMethod.idx()].trim_matches('"').to_string(),
                        request_url: split_line[ELBRecordFields::RequestURL.idx()].to_string(),
                        request_http_version: split_line[ELBRecordFields::RequestHTTPVersion.idx()].trim_matches('"').to_string()
                    }
                )
            } else {
                None
            }
        }
    }.map( |elb_rec|
        Ok(Box::new(elb_rec))
    ).unwrap_or_else( ||
        Err(ParsingErrors {
            record: record,
            errors: errors
        })
    )
}

trait ELBRecordFieldParser {
    fn parse_property<T>(
        &self,
        field_id: ELBRecordFields,
        errors: &mut Vec<ELBRecordParsingErrors>
    ) -> Option<T>
        where T: FromStr,
        T::Err: Error + 'static;
}

impl<'a> ELBRecordFieldParser for Vec<&'a str> {

    fn parse_property<T>(
        &self,
        field_id: ELBRecordFields,
        errors: &mut Vec<ELBRecordParsingErrors>
    ) -> Option<T>
        where T: FromStr,
        T::Err: Error + 'static,
    {
        let raw_prop = self[field_id.idx()];
        match raw_prop.parse::<T>() {
            Ok(parsed) => Some(parsed),

            Err(e) => {
                errors.push(
                    ELBRecordParsingErrors::ParsingError {
                        field_id: field_id,
                        description: e.description().to_string(),
                    }
                );
                None
            }
        }
    }
}

//TODO test the error case.
#[cfg(test)]
mod tests {
    use super::parse_record;
    use super::ELBRecordParsingErrors;

    const TEST_RECORD: &'static str = "2015-08-15T23:43:05.302180Z elb-name 172.16.1.6:54814 \
    172.16.1.5:9000 0.000039 0.145507 0.00003 200 200 0 7582 \
    \"GET http://some.domain.com:80/path0/path1?param0=p0&param1=p1 HTTP/1.1\"\
    ";

    #[test]
	fn parse_record_returns_a_malformed_record_error_for_records_short_on_values() {
        let short_record = "2015-08-15T23:43:05.302180Z elb-name 172.16.1.6:54814 \
        172.16.1.5:9000 0.000039 200 200 0 7582 \
        \"GET http://some.domain.com:80/path0/path1?param0=p0&param1=p1 HTTP/1.1\" \
        ";

        let malformed_error = parse_record(short_record.to_string()).unwrap_err().errors.pop();

		assert_eq!(malformed_error, Some(ELBRecordParsingErrors::MalformedRecord))
	}

    #[test]
	fn parse_record_returns_a_record_with_the_request_http_version() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.request_http_version, "HTTP/1.1")
	}

    #[test]
	fn parse_record_returns_a_record_with_the_request_url() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.request_url, "http://some.domain.com:80/path0/path1?param0=p0&param1=p1")
	}

    #[test]
	fn parse_record_returns_a_record_with_the_request_method() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.request_method, "GET")
	}

    #[test]
	fn parse_record_returns_a_record_with_the_sent_bytes() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.sent_bytes, 7582)
	}

    #[test]
	fn parse_record_returns_a_record_with_the_received_bytes() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.received_bytes, 0)
	}

    #[test]
	fn parse_record_returns_a_record_with_the_backend_status_code() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.backend_status_code, 200)
	}

    #[test]
	fn parse_record_returns_a_record_with_the_elb_status_code() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.elb_status_code, 200)
	}

    #[test]
	fn parse_record_returns_a_record_with_the_response_processing_time() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.response_processing_time, 0.00003)
	}

    #[test]
	fn parse_record_returns_a_record_with_the_backend_processing_time() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.backend_processing_time, 0.145507)
	}

    #[test]
	fn parse_record_returns_a_record_with_the_request_processing_time() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.request_processing_time, 0.000039)
	}

    #[test]
	fn parse_record_returns_a_record_with_the_backend_address() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.backend_address, "172.16.1.5:9000".parse().unwrap())
	}

    #[test]
	fn parse_record_returns_a_record_with_the_client_address() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.client_address, "172.16.1.6:54814".parse().unwrap())
	}

    #[test]
	fn parse_record_returns_a_record_with_the_timestamp() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(format!("{:?}", elb_record.timestamp), "2015-08-15T23:43:05.302180Z")
	}

    #[test]
	fn parse_record_returns_a_record_with_the_elb_name() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.elb_name, "elb-name")
	}
}
<|endoftext|>


<commit_before>use std::env;
use std::ffi::{CString, OsStr};
use std::fs::{self, File, OpenOptions};
use std::io;
cfg_if! {
    if #[cfg(not(target_os = "wasi"))] {
        use std::os::unix::ffi::OsStrExt;
        use std::os::unix::fs::{MetadataExt, OpenOptionsExt};
    } else {
        use std::os::wasi::ffi::OsStrExt;
        #[cfg(feature = "nightly")]
        use std::os::wasi::fs::MetadataExt;
    }
}
use crate::util;
use std::path::Path;

#[cfg(not(target_os = "redox"))]
use libc::{c_char, c_int, link, rename, unlink};

#[cfg(not(target_os = "redox"))]
#[inline(always)]
pub fn cvt_err(result: c_int) -> io::Result<c_int> {
    if result == -1 {
        Err(io::Error::last_os_error())
    } else {
        Ok(result)
    }
}

#[cfg(target_os = "redox")]
#[inline(always)]
pub fn cvt_err(result: Result<usize, syscall::Error>) -> io::Result<usize> {
    result.map_err(|err| io::Error::from_raw_os_error(err.errno))
}

// Stolen from std.
pub fn cstr(path: &Path) -> io::Result<CString> {
    CString::new(path.as_os_str().as_bytes())
        .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "path contained a null"))
}

pub fn create_named(path: &Path, open_options: &mut OpenOptions) -> io::Result<File> {
    open_options.read(true).write(true).create_new(true);

    #[cfg(not(target_os = "wasi"))]
    {
        open_options.mode(0o600);
    }

    open_options.open(path)
}

fn create_unlinked(path: &Path) -> io::Result<File> {
    let tmp;
    // shadow this to decrease the lifetime. It can't live longer than `tmp`.
    let mut path = path;
    if !path.is_absolute() {
        let cur_dir = env::current_dir()?;
        tmp = cur_dir.join(path);
        path = &tmp;
    }

    let f = create_named(path, &mut OpenOptions::new())?;
    // don't care whether the path has already been unlinked,
    // but perhaps there are some IO error conditions we should send up?
    let _ = fs::remove_file(path);
    Ok(f)
}

#[cfg(target_os = "linux")]
pub fn create(dir: &Path) -> io::Result<File> {
    use libc::{EISDIR, ENOENT, EOPNOTSUPP, O_EXCL, O_TMPFILE};
    OpenOptions::new()
        .read(true)
        .write(true)
        .custom_flags(O_TMPFILE | O_EXCL) // do not mix with `create_new(true)`
        .open(dir)
        .or_else(|e| {
            match e.raw_os_error() {
                // These are the three "not supported" error codes for O_TMPFILE.
                Some(EOPNOTSUPP) | Some(EISDIR) | Some(ENOENT) => create_unix(dir),
                _ => Err(e),
            }
        })
}

#[cfg(not(target_os = "linux"))]
pub fn create(dir: &Path) -> io::Result<File> {
    create_unix(dir)
}

fn create_unix(dir: &Path) -> io::Result<File> {
    util::create_helper(
        dir,
        OsStr::new(".tmp"),
        OsStr::new(""),
        crate::NUM_RAND_CHARS,
        |path| create_unlinked(&path),
    )
}

pub fn reopen(file: &File, path: &Path) -> io::Result<File> {
    let new_file = OpenOptions::new().read(true).write(true).open(path)?;
    let old_meta = file.metadata()?;
    let new_meta = new_file.metadata()?;
    cfg_if! {
        if #[cfg(any(not(target_os = "wasi"), feature = "nightly"))] {
            if old_meta.dev() != new_meta.dev() || old_meta.ino() != new_meta.ino() {
                return Err(io::Error::new(
                    io::ErrorKind::NotFound,
                    "original tempfile has been replaced",
                ));
            }
        } else {
            return Err(io::Error::new(
                io::ErrorKind::Other,
                "this operation is supported on WASI only on nightly Rust (with `nightly` feature enabled)"
            ));
        }
    }
    Ok(new_file)
}

#[cfg(not(target_os = "redox"))]
pub fn persist(old_path: &Path, new_path: &Path, overwrite: bool) -> io::Result<()> {
    unsafe {
        let old_path = cstr(old_path)?;
        let new_path = cstr(new_path)?;
        if overwrite {
            cvt_err(rename(
                old_path.as_ptr() as *const c_char,
                new_path.as_ptr() as *const c_char,
            ))?;
        } else {
            cvt_err(link(
                old_path.as_ptr() as *const c_char,
                new_path.as_ptr() as *const c_char,
            ))?;
            // Ignore unlink errors. Can we do better?
            // On recent linux, we can use renameat2 to do this atomically.
            let _ = unlink(old_path.as_ptr() as *const c_char);
        }
        Ok(())
    }
}

#[cfg(target_os = "redox")]
pub fn persist(old_path: &Path, new_path: &Path, overwrite: bool) -> io::Result<()> {
    // XXX implement when possible
    Err(io::Error::from_raw_os_error(syscall::ENOSYS))
}

pub fn keep(_: &Path) -> io::Result<()> {
    Ok(())
}
<commit_msg>Extract conditional compilation to function level<commit_after>use std::env;
use std::ffi::{CString, OsStr};
use std::fs::{self, File, OpenOptions};
use std::io;
cfg_if! {
    if #[cfg(not(target_os = "wasi"))] {
        use std::os::unix::ffi::OsStrExt;
        use std::os::unix::fs::{MetadataExt, OpenOptionsExt};
    } else {
        use std::os::wasi::ffi::OsStrExt;
        #[cfg(feature = "nightly")]
        use std::os::wasi::fs::MetadataExt;
    }
}
use crate::util;
use std::path::Path;

#[cfg(not(target_os = "redox"))]
use libc::{c_char, c_int, link, rename, unlink};

#[cfg(not(target_os = "redox"))]
#[inline(always)]
pub fn cvt_err(result: c_int) -> io::Result<c_int> {
    if result == -1 {
        Err(io::Error::last_os_error())
    } else {
        Ok(result)
    }
}

#[cfg(target_os = "redox")]
#[inline(always)]
pub fn cvt_err(result: Result<usize, syscall::Error>) -> io::Result<usize> {
    result.map_err(|err| io::Error::from_raw_os_error(err.errno))
}

// Stolen from std.
pub fn cstr(path: &Path) -> io::Result<CString> {
    CString::new(path.as_os_str().as_bytes())
        .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "path contained a null"))
}

pub fn create_named(path: &Path, open_options: &mut OpenOptions) -> io::Result<File> {
    open_options.read(true).write(true).create_new(true);

    #[cfg(not(target_os = "wasi"))]
    {
        open_options.mode(0o600);
    }

    open_options.open(path)
}

fn create_unlinked(path: &Path) -> io::Result<File> {
    let tmp;
    // shadow this to decrease the lifetime. It can't live longer than `tmp`.
    let mut path = path;
    if !path.is_absolute() {
        let cur_dir = env::current_dir()?;
        tmp = cur_dir.join(path);
        path = &tmp;
    }

    let f = create_named(path, &mut OpenOptions::new())?;
    // don't care whether the path has already been unlinked,
    // but perhaps there are some IO error conditions we should send up?
    let _ = fs::remove_file(path);
    Ok(f)
}

#[cfg(target_os = "linux")]
pub fn create(dir: &Path) -> io::Result<File> {
    use libc::{EISDIR, ENOENT, EOPNOTSUPP, O_EXCL, O_TMPFILE};
    OpenOptions::new()
        .read(true)
        .write(true)
        .custom_flags(O_TMPFILE | O_EXCL) // do not mix with `create_new(true)`
        .open(dir)
        .or_else(|e| {
            match e.raw_os_error() {
                // These are the three "not supported" error codes for O_TMPFILE.
                Some(EOPNOTSUPP) | Some(EISDIR) | Some(ENOENT) => create_unix(dir),
                _ => Err(e),
            }
        })
}

#[cfg(not(target_os = "linux"))]
pub fn create(dir: &Path) -> io::Result<File> {
    create_unix(dir)
}

fn create_unix(dir: &Path) -> io::Result<File> {
    util::create_helper(
        dir,
        OsStr::new(".tmp"),
        OsStr::new(""),
        crate::NUM_RAND_CHARS,
        |path| create_unlinked(&path),
    )
}

#[cfg(any(not(target_os = "wasi"), feature = "nightly"))]
pub fn reopen(file: &File, path: &Path) -> io::Result<File> {
    let new_file = OpenOptions::new().read(true).write(true).open(path)?;
    let old_meta = file.metadata()?;
    let new_meta = new_file.metadata()?;
    if old_meta.dev() != new_meta.dev() || old_meta.ino() != new_meta.ino() {
        return Err(io::Error::new(
            io::ErrorKind::NotFound,
            "original tempfile has been replaced",
        ));
    }
    Ok(new_file)
}

#[cfg(all(target_os = "wasi", not(feature = "nightly")))]
pub fn reopen(file: &File, path: &Path) -> io::Result<File> {
    return Err(io::Error::new(
        io::ErrorKind::Other,
        "this operation is supported on WASI only on nightly Rust (with `nightly` feature enabled)",
    ));
}

#[cfg(not(target_os = "redox"))]
pub fn persist(old_path: &Path, new_path: &Path, overwrite: bool) -> io::Result<()> {
    unsafe {
        let old_path = cstr(old_path)?;
        let new_path = cstr(new_path)?;
        if overwrite {
            cvt_err(rename(
                old_path.as_ptr() as *const c_char,
                new_path.as_ptr() as *const c_char,
            ))?;
        } else {
            cvt_err(link(
                old_path.as_ptr() as *const c_char,
                new_path.as_ptr() as *const c_char,
            ))?;
            // Ignore unlink errors. Can we do better?
            // On recent linux, we can use renameat2 to do this atomically.
            let _ = unlink(old_path.as_ptr() as *const c_char);
        }
        Ok(())
    }
}

#[cfg(target_os = "redox")]
pub fn persist(old_path: &Path, new_path: &Path, overwrite: bool) -> io::Result<()> {
    // XXX implement when possible
    Err(io::Error::from_raw_os_error(syscall::ENOSYS))
}

pub fn keep(_: &Path) -> io::Result<()> {
    Ok(())
}
<|endoftext|>