<commit_before>use serde::{de, ser};
use serde::ser::SerializeMap;
use std::fmt;
use std::collections::HashMap;

use ::{GraphQLError, Value, Variables};
use ast::InputValue;
use executor::ExecutionError;
use parser::{ParseError, Spanning, SourcePosition};
use validation::RuleError;

impl ser::Serialize for ExecutionError {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ser::Serializer,
    {
        let mut map = try!(serializer.serialize_map(Some(3)));

        try!(map.serialize_key("message"));
        try!(map.serialize_value(self.message()));

        let locations = vec![self.location()];
        try!(map.serialize_key("locations"));
        try!(map.serialize_value(&locations));

        try!(map.serialize_key("path"));
        try!(map.serialize_value(self.path()));

        map.end()
    }
}

impl<'a> ser::Serialize for GraphQLError<'a> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ser::Serializer,
    {
        match *self {
            GraphQLError::ParseError(ref err) => vec![err].serialize(serializer),
            GraphQLError::ValidationError(ref errs) => errs.serialize(serializer),
            GraphQLError::NoOperationProvided => {
                serializer.serialize_str("Must provide an operation")
            },
            GraphQLError::MultipleOperationsProvided => {
                serializer.serialize_str("Must provide operation name if query contains multiple operations")
            },
            GraphQLError::UnknownOperationName => {
                serializer.serialize_str("Unknown operation")
            },
        }
    }
}

impl de::Deserialize for InputValue {
    fn deserialize<D>(deserializer: D) -> Result<InputValue, D::Error>
        where D: de::Deserializer,
    {
        struct InputValueVisitor;

        impl de::Visitor for InputValueVisitor {
            type Value = InputValue;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a valid input value")
            }

            fn visit_bool<E>(self, value: bool) -> Result<InputValue, E> {
                Ok(InputValue::boolean(value))
            }

            fn visit_i64<E>(self, value: i64) -> Result<InputValue, E> {
                Ok(InputValue::int(value))
            }

            fn visit_u64<E>(self, value: u64) -> Result<InputValue, E>
                where E: de::Error,
            {
                self.visit_f64(value as f64)
            }

            fn visit_f64<E>(self, value: f64) -> Result<InputValue, E> {
                Ok(InputValue::float(value))
            }

            fn visit_str<E>(self, value: &str) -> Result<InputValue, E>
                where E: de::Error,
            {
                self.visit_string(value.into())
            }

            fn visit_string<E>(self, value: String) -> Result<InputValue, E> {
                Ok(InputValue::string(value))
            }

            fn visit_none<E>(self) -> Result<InputValue, E> {
                Ok(InputValue::null())
            }

            fn visit_unit<E>(self) -> Result<InputValue, E> {
                Ok(InputValue::null())
            }

            fn visit_seq<V>(self, visitor: V) -> Result<InputValue, V::Error>
                where V: de::SeqVisitor,
            {
                let values = try!(de::impls::VecVisitor::new().visit_seq(visitor));
                Ok(InputValue::list(values))
            }

            fn visit_map<V>(self, visitor: V) -> Result<InputValue, V::Error>
                where V: de::MapVisitor,
            {
                let values = try!(de::impls::HashMapVisitor::<String, InputValue, _>::new()
                    .visit_map(visitor));
                Ok(InputValue::object(values))
            }
        }

        deserializer.deserialize(InputValueVisitor)
    }
}

impl ser::Serialize for InputValue {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ser::Serializer,
    {
        match *self {
            InputValue::Null | InputValue::Variable(_) => serializer.serialize_unit(),
            InputValue::Int(v) => serializer.serialize_i64(v),
            InputValue::Float(v) => serializer.serialize_f64(v),
            InputValue::String(ref v) | InputValue::Enum(ref v) => serializer.serialize_str(v),
            InputValue::Boolean(v) => serializer.serialize_bool(v),
            InputValue::List(ref v) => {
                v.iter().map(|x| x.item.clone()).collect::<Vec<_>>().serialize(serializer)
            },
            InputValue::Object(ref v) => {
                v.iter()
                    .map(|&(ref k, ref v)| (k.item.clone(), v.item.clone()))
                    .collect::<HashMap<_, _>>()
                    .serialize(serializer)
            },
        }
    }
}

impl ser::Serialize for RuleError {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ser::Serializer,
    {
        let mut map = try!(serializer.serialize_map(Some(2)));

        try!(map.serialize_key("message"));
        try!(map.serialize_value(self.message()));

        try!(map.serialize_key("locations"));
        try!(map.serialize_value(self.locations()));

        map.end()
    }
}

impl ser::Serialize for SourcePosition {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ser::Serializer,
    {
        let mut map = try!(serializer.serialize_map(Some(2)));

        let line = self.line() + 1;
        try!(map.serialize_key("line"));
        try!(map.serialize_value(&line));

        let column = self.column() + 1;
        try!(map.serialize_key("column"));
        try!(map.serialize_value(&column));

        map.end()
    }
}

impl<'a> ser::Serialize for Spanning<ParseError<'a>> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ser::Serializer,
    {
        let mut map = try!(serializer.serialize_map(Some(2)));

        let message = format!("{}", self.item);
        try!(map.serialize_key("message"));
        try!(map.serialize_value(&message));

        let mut location = HashMap::new();
        location.insert("line".to_owned(), self.start.line() + 1);
        location.insert("column".to_owned(), self.start.column() + 1);

        let locations = vec![location];

        try!(map.serialize_key("locations"));
        try!(map.serialize_value(&locations));

        map.end()
    }
}

impl ser::Serialize for Value {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ser::Serializer,
    {
        match *self {
            Value::Null => serializer.serialize_unit(),
            Value::Int(v) => serializer.serialize_i64(v),
            Value::Float(v) => serializer.serialize_f64(v),
            Value::String(ref v) => serializer.serialize_str(v),
            Value::Boolean(v) => serializer.serialize_bool(v),
            Value::List(ref v) => v.serialize(serializer),
            Value::Object(ref v) => v.serialize(serializer),
        }
    }
}

/// The expected structure of the decoded JSON Document for either Post or Get requests.
#[cfg(feature="iron-handlers")]
#[derive(Deserialize)]
pub struct GraphQlQuery {
    query: String,
    #[serde(rename = "operationName")]
    operation_name: Option<String>,
    variables: Option<InputValue>
}

impl GraphQlQuery {

    pub fn new(query: String,
               operation_name: Option<String>,
               variables: Option<InputValue>
              ) ->  GraphQlQuery {
                GraphQlQuery {
                    query: query,
                    operation_name: operation_name,
                    variables: variables
                }
           }

    pub fn query(&self) -> &str {
        self.query.as_str()
    }

    pub fn operation_name(&self) -> Option<&str> {
        self.operation_name.as_ref().map(|oper_name| &**oper_name)
    }

    pub fn variables(&self) -> Variables {
        self.variables.as_ref().and_then(|iv| {
          iv.to_object_value().map(|o| {
              o.into_iter().map(|(k, v)| (k.to_owned(), v.clone())).collect()
          })
      }).unwrap_or_default()
    }

}

#[cfg(feature="iron-handlers")]
pub struct WrappedGraphQLResult<'a>(Result<(Value, Vec<ExecutionError>), GraphQLError<'a>>);

impl<'a> WrappedGraphQLResult<'a> {
    pub fn new(result: Result<(Value, Vec<ExecutionError>),
               GraphQLError<'a>>
           ) -> WrappedGraphQLResult<'a> {
        WrappedGraphQLResult(result)
    }
}

impl<'a> ser::Serialize for WrappedGraphQLResult<'a> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ser::Serializer,
    {
        match self.0 {
            Ok((ref res, ref err)) => {
                let mut map = try!(serializer.serialize_map(None));

                try!(map.serialize_key("data"));
                try!(map.serialize_value(res));

                if !err.is_empty() {
                    try!(map.serialize_key("errors"));
                    try!(map.serialize_value(err));
                }

                map.end()
            },
            Err(ref err) => {
                let mut map = try!(serializer.serialize_map(Some(1)));
                try!(map.serialize_key("errors"));
                try!(map.serialize_value(err));
                map.end()
            },
        }
    }
}
<commit_msg>Added conditional compliation logic.<commit_after>use serde::{de, ser};
use serde::ser::SerializeMap;
use std::fmt;
use std::collections::HashMap;

use ::{GraphQLError, Value};
#[cfg(feature="iron-handlers")]
use ::Variables;
use ast::InputValue;
use executor::ExecutionError;
use parser::{ParseError, Spanning, SourcePosition};
use validation::RuleError;

impl ser::Serialize for ExecutionError {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ser::Serializer,
    {
        let mut map = try!(serializer.serialize_map(Some(3)));

        try!(map.serialize_key("message"));
        try!(map.serialize_value(self.message()));

        let locations = vec![self.location()];
        try!(map.serialize_key("locations"));
        try!(map.serialize_value(&locations));

        try!(map.serialize_key("path"));
        try!(map.serialize_value(self.path()));

        map.end()
    }
}

impl<'a> ser::Serialize for GraphQLError<'a> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ser::Serializer,
    {
        match *self {
            GraphQLError::ParseError(ref err) => vec![err].serialize(serializer),
            GraphQLError::ValidationError(ref errs) => errs.serialize(serializer),
            GraphQLError::NoOperationProvided => {
                serializer.serialize_str("Must provide an operation")
            },
            GraphQLError::MultipleOperationsProvided => {
                serializer.serialize_str("Must provide operation name if query contains multiple operations")
            },
            GraphQLError::UnknownOperationName => {
                serializer.serialize_str("Unknown operation")
            },
        }
    }
}

impl de::Deserialize for InputValue {
    fn deserialize<D>(deserializer: D) -> Result<InputValue, D::Error>
        where D: de::Deserializer,
    {
        struct InputValueVisitor;

        impl de::Visitor for InputValueVisitor {
            type Value = InputValue;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a valid input value")
            }

            fn visit_bool<E>(self, value: bool) -> Result<InputValue, E> {
                Ok(InputValue::boolean(value))
            }

            fn visit_i64<E>(self, value: i64) -> Result<InputValue, E> {
                Ok(InputValue::int(value))
            }

            fn visit_u64<E>(self, value: u64) -> Result<InputValue, E>
                where E: de::Error,
            {
                self.visit_f64(value as f64)
            }

            fn visit_f64<E>(self, value: f64) -> Result<InputValue, E> {
                Ok(InputValue::float(value))
            }

            fn visit_str<E>(self, value: &str) -> Result<InputValue, E>
                where E: de::Error,
            {
                self.visit_string(value.into())
            }

            fn visit_string<E>(self, value: String) -> Result<InputValue, E> {
                Ok(InputValue::string(value))
            }

            fn visit_none<E>(self) -> Result<InputValue, E> {
                Ok(InputValue::null())
            }

            fn visit_unit<E>(self) -> Result<InputValue, E> {
                Ok(InputValue::null())
            }

            fn visit_seq<V>(self, visitor: V) -> Result<InputValue, V::Error>
                where V: de::SeqVisitor,
            {
                let values = try!(de::impls::VecVisitor::new().visit_seq(visitor));
                Ok(InputValue::list(values))
            }

            fn visit_map<V>(self, visitor: V) -> Result<InputValue, V::Error>
                where V: de::MapVisitor,
            {
                let values = try!(de::impls::HashMapVisitor::<String, InputValue, _>::new()
                    .visit_map(visitor));
                Ok(InputValue::object(values))
            }
        }

        deserializer.deserialize(InputValueVisitor)
    }
}

impl ser::Serialize for InputValue {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ser::Serializer,
    {
        match *self {
            InputValue::Null | InputValue::Variable(_) => serializer.serialize_unit(),
            InputValue::Int(v) => serializer.serialize_i64(v),
            InputValue::Float(v) => serializer.serialize_f64(v),
            InputValue::String(ref v) | InputValue::Enum(ref v) => serializer.serialize_str(v),
            InputValue::Boolean(v) => serializer.serialize_bool(v),
            InputValue::List(ref v) => {
                v.iter().map(|x| x.item.clone()).collect::<Vec<_>>().serialize(serializer)
            },
            InputValue::Object(ref v) => {
                v.iter()
                    .map(|&(ref k, ref v)| (k.item.clone(), v.item.clone()))
                    .collect::<HashMap<_, _>>()
                    .serialize(serializer)
            },
        }
    }
}

impl ser::Serialize for RuleError {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ser::Serializer,
    {
        let mut map = try!(serializer.serialize_map(Some(2)));

        try!(map.serialize_key("message"));
        try!(map.serialize_value(self.message()));

        try!(map.serialize_key("locations"));
        try!(map.serialize_value(self.locations()));

        map.end()
    }
}

impl ser::Serialize for SourcePosition {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ser::Serializer,
    {
        let mut map = try!(serializer.serialize_map(Some(2)));

        let line = self.line() + 1;
        try!(map.serialize_key("line"));
        try!(map.serialize_value(&line));

        let column = self.column() + 1;
        try!(map.serialize_key("column"));
        try!(map.serialize_value(&column));

        map.end()
    }
}

impl<'a> ser::Serialize for Spanning<ParseError<'a>> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ser::Serializer,
    {
        let mut map = try!(serializer.serialize_map(Some(2)));

        let message = format!("{}", self.item);
        try!(map.serialize_key("message"));
        try!(map.serialize_value(&message));

        let mut location = HashMap::new();
        location.insert("line".to_owned(), self.start.line() + 1);
        location.insert("column".to_owned(), self.start.column() + 1);

        let locations = vec![location];

        try!(map.serialize_key("locations"));
        try!(map.serialize_value(&locations));

        map.end()
    }
}

impl ser::Serialize for Value {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ser::Serializer,
    {
        match *self {
            Value::Null => serializer.serialize_unit(),
            Value::Int(v) => serializer.serialize_i64(v),
            Value::Float(v) => serializer.serialize_f64(v),
            Value::String(ref v) => serializer.serialize_str(v),
            Value::Boolean(v) => serializer.serialize_bool(v),
            Value::List(ref v) => v.serialize(serializer),
            Value::Object(ref v) => v.serialize(serializer),
        }
    }
}

/// The expected structure of the decoded JSON Document for either Post or Get requests.
#[cfg(feature="iron-handlers")]
#[derive(Deserialize)]
pub struct GraphQlQuery {
    query: String,
    #[serde(rename = "operationName")]
    operation_name: Option<String>,
    variables: Option<InputValue>
}

#[cfg(feature="iron-handlers")]
impl GraphQlQuery {

    pub fn new(query: String,
               operation_name: Option<String>,
               variables: Option<InputValue>
              ) ->  GraphQlQuery {
                GraphQlQuery {
                    query: query,
                    operation_name: operation_name,
                    variables: variables
                }
           }

    pub fn query(&self) -> &str {
        self.query.as_str()
    }

    pub fn operation_name(&self) -> Option<&str> {
        self.operation_name.as_ref().map(|oper_name| &**oper_name)
    }

    pub fn variables(&self) -> Variables {
        self.variables.as_ref().and_then(|iv| {
          iv.to_object_value().map(|o| {
              o.into_iter().map(|(k, v)| (k.to_owned(), v.clone())).collect()
          })
      }).unwrap_or_default()
    }

}

#[cfg(feature="iron-handlers")]
pub struct WrappedGraphQLResult<'a>(Result<(Value, Vec<ExecutionError>), GraphQLError<'a>>);

#[cfg(feature="iron-handlers")]
impl<'a> WrappedGraphQLResult<'a> {
    pub fn new(result: Result<(Value, Vec<ExecutionError>),
               GraphQLError<'a>>
           ) -> WrappedGraphQLResult<'a> {
        WrappedGraphQLResult(result)
    }
}

#[cfg(feature="iron-handlers")]
impl<'a> ser::Serialize for WrappedGraphQLResult<'a> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ser::Serializer,
    {
        match self.0 {
            Ok((ref res, ref err)) => {
                let mut map = try!(serializer.serialize_map(None));

                try!(map.serialize_key("data"));
                try!(map.serialize_value(res));

                if !err.is_empty() {
                    try!(map.serialize_key("errors"));
                    try!(map.serialize_value(err));
                }

                map.end()
            },
            Err(ref err) => {
                let mut map = try!(serializer.serialize_map(Some(1)));
                try!(map.serialize_key("errors"));
                try!(map.serialize_value(err));
                map.end()
            },
        }
    }
}
<|endoftext|>


<commit_before>use std::f32::consts::*;

use Vector;
use scene::Scene;
use ray::Ray;
use colour::Colourf;
use integrator::Integrator;
use geometry::TextureCoordinate;
use na::{Norm, Dot};
use na;

pub struct Whitted {
    pub max_ray_depth: u8,
}

impl Whitted {
    pub fn new(n: u8) -> Whitted {
        Whitted { max_ray_depth: n }
    }

    fn reflect(&self, i: &Vector, n: &Vector) -> Vector {
        (*i - *n * 2.0 * n.dot(i)).normalize()
    }
}

fn fmod(x: f32) -> f32 {
    x - x.floor()
}

fn pattern(tex_coord: &TextureCoordinate, scale_u: f32, scale_v: f32) -> f32 {
    let p = (fmod(tex_coord.u * scale_u) < 0.5) ^ (fmod(tex_coord.v * scale_v) < 0.5);
    if p { 1.0 } else { 0.5 }
}

impl Integrator for Whitted {
    fn illumination(&self, scene: &Scene, ray: &mut Ray) -> Colourf {
        let mut colour = Colourf::black();

        if ray.depth > self.max_ray_depth {
            return Colourf::rgb(0.0, 0.0, 0.5);
        }

        if let Some(intersection) = scene.intersect(ray) {
            let hit = intersection.hit;
            let ref mat = hit.material;
            let w_o = -ray.dir;
            let n = intersection.dg.nhit;
            let p = intersection.dg.phit;

            // colour += Colourf::grey(w_o.dot(&n));
            if mat.reflection == 0.0 && mat.transparency == 0.0 {
                // Diffuse material
                for light in &scene.lights {
                    let shading_info = light.shading_info(&p);
                    let mut shadow_ray = ray.spawn(p, shading_info.w_i);
                    shadow_ray.t_max = shading_info.light_distance;
                    if let None = scene.intersect(&mut shadow_ray) {
                        let diffuse = mat.surface_colour * FRAC_1_PI * shading_info.l_i *
                                      shading_info.w_i.dot(&n).max(0.0) *
                                      pattern(&intersection.dg.tex_coord, 10.0, 10.0);
                        colour += diffuse;
                    }
                }
            }

            if mat.reflection > 0.0 {
                let mut refl_ray = ray.spawn(p, self.reflect(&ray.dir, &n));
                let refl = self.illumination(scene, &mut refl_ray);
                colour += refl * mat.reflection;
                if mat.transparency > 0.0 {
                    let mut cos_i = na::clamp(ray.dir.dot(&n), -1.0, 1.0);
                    let mut eta = 1.5;
                    let mut n_refl = n;
                    if cos_i < 0.0 {
                        cos_i = -cos_i;
                    } else {
                        eta = 1.0 / eta;
                        n_refl = -n_refl;
                    }
                    let k = 1.0 - eta * eta * (1.0 - cos_i * cos_i);
                    if k > 0.0 {
                        let refl_dir = eta * ray.dir + (eta * cos_i - k.sqrt()) * n_refl;
                        let mut refl_ray = ray.spawn(p, refl_dir.normalize());
                        colour += self.illumination(scene, &mut refl_ray) * mat.transparency;
                    }
                }
            }
        } else {
            // return Colourf::rgb(0.0, 0.0, 0.5);
            return scene.atmosphere.compute_incident_light(ray);
        }

        return colour;
    }
}
<commit_msg>Fix broken refraction + impl Fresnel<commit_after>use std::f32::consts::*;

use Vector;
use scene::Scene;
use ray::Ray;
use colour::Colourf;
use integrator::Integrator;
use geometry::TextureCoordinate;
use na::{Norm, Dot, zero};
use na;

pub struct Whitted {
    pub max_ray_depth: u8,
}

impl Whitted {
    pub fn new(n: u8) -> Whitted {
        Whitted { max_ray_depth: n }
    }
}

/// Compute the reflection direction
fn reflect(i: &Vector, n: &Vector) -> Vector {
    (*i - *n * 2.0 * n.dot(i)).normalize()
}

/// Compute the refraction direction
fn refract(i: &Vector, n: &Vector, ior: f32) -> Vector {
    let mut cos_i = na::clamp(i.dot(&n), -1.0, 1.0);
    let (etai, etat, n_refr) = if cos_i < 0.0 {
        cos_i = -cos_i;
        (1.0, ior, *n)
    } else {
        (ior, 1.0, -*n)
    };

    let eta = etai / etat;
    let k = 1.0 - eta * eta * (1.0 - cos_i * cos_i);

    if k > 0.0 {
        *i * eta + n_refr * (eta * cos_i - k.sqrt())
    } else {
        zero()
    }
}

/// Compute the Fresnel coefficient
fn fresnel(i: &Vector, n: &Vector, ior: f32) -> f32 {
    let mut cosi = na::clamp(i.dot(&n), -1.0, 1.0);
    let (etai, etat) = if cosi > 0.0 { (ior, 1.0) } else { (1.0, ior) };

    let sint = etai / etat * (1.0 - cosi * cosi).max(0.0).sqrt();
    if sint >= 1.0 {
        return 1.0;
    } else {
        let cost = (1.0 - sint * sint).max(0.0).sqrt();
        cosi = cosi.abs();
        let r_s = ((etat * cosi) - (etai * cost)) / ((etat * cosi) + (etai * cost));
        let r_p = ((etai * cosi) - (etat * cost)) / ((etai * cosi) + (etat * cost));
        return (r_s * r_s + r_p * r_p) / 2.0;
    }
}

fn fmod(x: f32) -> f32 {
    x - x.floor()
}

fn pattern(tex_coord: &TextureCoordinate, scale_u: f32, scale_v: f32) -> f32 {
    let p = (fmod(tex_coord.u * scale_u) < 0.5) ^ (fmod(tex_coord.v * scale_v) < 0.5);
    if p { 1.0 } else { 0.5 }
}

impl Integrator for Whitted {
    fn illumination(&self, scene: &Scene, ray: &mut Ray) -> Colourf {
        let mut colour = Colourf::black();

        if ray.depth > self.max_ray_depth {
            return Colourf::rgb(0.0, 0.0, 0.5);
        }

        if let Some(intersection) = scene.intersect(ray) {
            let hit = intersection.hit;
            let ref mat = hit.material;
            let n = intersection.dg.nhit;
            let p = intersection.dg.phit;

            // colour += Colourf::grey(w_o.dot(&n));
            if mat.reflection == 0.0 && mat.transparency == 0.0 {
                // Diffuse material
                for light in &scene.lights {
                    let shading_info = light.shading_info(&p);
                    let mut shadow_ray = ray.spawn(p, shading_info.w_i);
                    shadow_ray.t_max = shading_info.light_distance;
                    if let None = scene.intersect(&mut shadow_ray) {
                        let diffuse = mat.surface_colour * FRAC_1_PI * shading_info.l_i *
                                      shading_info.w_i.dot(&n).max(0.0) *
                                      pattern(&intersection.dg.tex_coord, 10.0, 10.0);
                        colour += diffuse;
                    }
                }
            } else {
                // Fresnel reflection / refraction
                let kr = fresnel(&ray.dir, &n, 1.5);
                let bias = if ray.dir.dot(&n) < 0.0 {
                    // outside
                    1e-4 * n
                } else {
                    // inside
                    -1e-4 * n
                };

                if kr < 1.0 {
                    // refraction
                    let refr_dir = refract(&ray.dir, &n, 1.5);
                    let mut refr_ray = ray.spawn(p - bias, refr_dir);
                    colour += self.illumination(scene, &mut refr_ray) * (1.0 - kr);
                }
                // Reflection
                let mut refl_ray = ray.spawn(p + bias, reflect(&ray.dir, &n));
                let refl = self.illumination(scene, &mut refl_ray);
                colour += refl * kr;
            }

        } else {
            // return Colourf::rgb(0.0, 0.0, 0.5);
            return scene.atmosphere.compute_incident_light(ray);
        }

        return colour;
    }
}
<|endoftext|>


<commit_before>//! A module of helper traits and iterators that are not intended to be used
//! directly.

/// Apply `IntoIterator` on each element of a tuple.
pub trait IntoIteratorTuple
{
    /// Tuple of values that implement `Iterator`.
    type Output;

    /// Return a tuple of iterators.
    fn into_iterator_tuple(self) -> Self::Output;
}

/// A helper trait for (x, y, z) ++ w => (x, y, z, w),
/// used for implementing `iproduct!`.
pub trait AppendTuple<X> {
    /// Resulting tuple type
    type Result;
    /// “Append” value `x` to a tuple.
    fn append(self, x: X) -> Self::Result;
}

macro_rules! impl_append_tuple(
    () => (
        impl<T> AppendTuple<T> for () {
            type Result = (T, );
            fn append(self, x: T) -> (T, ) {
                (x, )
            }
        }
    );

    ($A:ident, $($B:ident,)*) => (
        impl_append_tuple!($($B,)*);
        #[allow(non_snake_case)]
        impl<$A, $($B,)* T> AppendTuple<T> for ($A, $($B),*) {
            type Result = ($A, $($B, )* T);
            fn append(self, x: T) -> ($A, $($B,)* T) {
                let ($A, $($B),*) = self;
                ($A, $($B,)* x)
            }
        }
    );
);

impl_append_tuple!(A, B, C, D, E, F, G, H, I, J, K, L,);

/// A helper iterator that maps an iterator of tuples like
/// `((A, B), C)` to an iterator of `(A, B, C)`.
///
/// Used by the `iproduct!()` macro.
#[derive(Clone)]
pub struct FlatTuples<I> {
    iter: I,
}

impl<I> FlatTuples<I> {
    /// Create a new `FlatTuples`.
    #[doc(hidden)]
    pub fn new(iter: I) -> Self {
        FlatTuples { iter: iter }
    }
}

impl<X, T, I> Iterator for FlatTuples<I>
    where I: Iterator<Item = (T, X)>,
          T: AppendTuple<X>
{
    type Item = T::Result;
    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|(t, x)| t.append(x))
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }
}

impl<X, T, I> DoubleEndedIterator for FlatTuples<I>
    where I: DoubleEndedIterator<Item = (T, X)>,
          T: AppendTuple<X>
{
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item> {
        self.iter.next_back().map(|(t, x)| t.append(x))
    }
}

<commit_msg>Remove the AppendTuple trait (just use multiple FlatTuples impls)<commit_after>//! A module of helper traits and iterators that are not intended to be used
//! directly.

/// Apply `IntoIterator` on each element of a tuple.
pub trait IntoIteratorTuple
{
    /// Tuple of values that implement `Iterator`.
    type Output;

    /// Return a tuple of iterators.
    fn into_iterator_tuple(self) -> Self::Output;
}

macro_rules! impl_cons_iter(
    () => ();

    ($A:ident, $($B:ident,)*) => (
        impl_cons_iter!($($B,)*);
        #[allow(non_snake_case)]
        impl<X, Iter, $($B),*> Iterator for FlatTuples<Iter, (($($B,)*), X)>
            where Iter: Iterator<Item = (($($B,)*), X)>,
        {
            type Item = ($($B,)* X, );
            fn next(&mut self) -> Option<Self::Item> {
                self.iter.next().map(|(($($B,)*), x)| ($($B,)* x, ))
            }

            fn size_hint(&self) -> (usize, Option<usize>) {
                self.iter.size_hint()
            }
        }

        #[allow(non_snake_case)]
        impl<X, Iter, $($B),*> DoubleEndedIterator for FlatTuples<Iter, (($($B,)*), X)>
            where Iter: DoubleEndedIterator<Item = (($($B,)*), X)>,
        {
            fn next_back(&mut self) -> Option<Self::Item> {
                self.iter.next().map(|(($($B,)*), x)| ($($B,)* x, ))
            }
        }

    );
);

impl_cons_iter!(A, B, C, D, E, F, G, H, I, J, K, L,);

/// A helper iterator that maps an iterator of tuples like
/// `((A, B), C)` to an iterator of `(A, B, C)`.
///
/// Used by the `iproduct!()` macro.
pub struct FlatTuples<I, J>
    where I: Iterator<Item=J>,
{
    iter: I,
}

impl<I, J> Clone for FlatTuples<I, J>
    where I: Clone + Iterator<Item=J>,
{
    fn clone(&self) -> Self {
        FlatTuples {
            iter: self.iter.clone(),
        }
    }
}

impl<I, J> FlatTuples<I, J>
    where I: Iterator<Item=J>
{
    /// Create a new `FlatTuples`.
    #[doc(hidden)]
    pub fn new(iter: I) -> Self {
        FlatTuples { iter: iter }
    }
}
<|endoftext|>


<commit_before>//! Local server that establish a TCP Transparent Proxy with server

use std::{
    io,
    io::ErrorKind,
    net::SocketAddr,
    sync::{
        atomic::{AtomicU64, Ordering},
        Arc,
    },
};

use futures::future::{self, Either};
use log::{debug, error, info, trace};
use tokio::net::{TcpListener, TcpStream};

use crate::{
    config::ServerConfig,
    context::{Context, SharedContext},
    relay::{
        loadbalancing::server::{LoadBalancer, PingBalancer, PingServer, PingServerType},
        socks5::Address,
    },
};

#[cfg(not(target_os = "linux"))]
pub fn get_original_destination_addr(_: &mut TcpStream) -> io::Result<SocketAddr> {
    unimplemented!("Transparent Proxy (redir) doesn't work on this platform");
}

#[cfg(target_os = "linux")]
pub fn get_original_destination_addr(s: &mut TcpStream) -> io::Result<SocketAddr> {
    use std::{
        io::Error,
        mem,
        net::{SocketAddrV4, SocketAddrV6},
        os::unix::io::AsRawFd,
    };

    let fd = s.as_raw_fd();

    unsafe {
        let mut target_addr: libc::sockaddr_storage = mem::zeroed();
        let mut target_addr_len = mem::size_of_val(&target_addr) as libc::socklen_t;

        // Check if it is IPv6 address
        let ret = libc::getsockopt(
            fd,
            libc::SOL_IPV6,
            libc::SO_ORIGINAL_DST, // FIXME: Should use IP6T_SO_ORIGINAL_DST
            &mut target_addr as *mut _ as *mut _,
            &mut target_addr_len,
        );

        if ret != 0 {
            let err = Error::last_os_error();
            match err.raw_os_error() {
                Some(libc::ENOPROTOOPT) | Some(libc::EOPNOTSUPP) => {
                    // The option is unknown at the level indicated.
                    //
                    // - The current system doesn't support IPv6 netfilter
                    // - This is not an IPv6 connection
                    //
                    // Continue with IPv4
                }
                _ => {
                    return Err(err);
                }
            }

            let ret = libc::getsockopt(
                fd,
                libc::SOL_IP,
                libc::SO_ORIGINAL_DST,
                &mut target_addr as *mut _ as *mut _,
                &mut target_addr_len,
            );

            if ret != 0 {
                return Err(Error::last_os_error());
            }
        }

        // Convert sockaddr_storage to SocketAddr
        match target_addr.ss_family as libc::c_int {
            libc::AF_INET => {
                let addr: SocketAddrV4 = mem::transmute_copy(&target_addr);
                Ok(SocketAddr::V4(addr))
            }
            libc::AF_INET6 => {
                let addr: SocketAddrV6 = mem::transmute_copy(&target_addr);
                Ok(SocketAddr::V6(addr))
            }
            _ => {
                let err = Error::new(ErrorKind::InvalidData, "family must be either AF_INET or AF_INET6");
                return Err(err);
            }
        }
    }
}

/// Established Client Transparent Proxy
///
/// This method must be called after handshaking with client (for example, socks5 handshaking)
async fn establish_client_tcp_redir<'a>(
    context: &Context,
    mut s: TcpStream,
    client_addr: SocketAddr,
    addr: &Address,
    svr_cfg: &ServerConfig,
) -> io::Result<()> {
    let svr_s = match super::connect_proxy_server(context, &*svr_cfg).await {
        Ok(svr_s) => {
            trace!("Proxy server connected, {:?}", svr_cfg);
            svr_s
        }
        Err(err) => {
            // Just close the connection.
            error!("Failed to connect remote server {}, err: {}", svr_cfg.addr(), err);
            return Err(err);
        }
    };

    let mut svr_s = super::proxy_server_handshake(context, svr_s, svr_cfg, addr).await?;
    let (mut svr_r, mut svr_w) = svr_s.split();

    let (mut r, mut w) = s.split();

    use tokio::io::copy;

    let rhalf = copy(&mut r, &mut svr_w);
    let whalf = copy(&mut svr_r, &mut w);

    debug!(
        "REDIR relay established {} <-> {} ({})",
        client_addr,
        svr_cfg.addr(),
        addr
    );

    match future::select(rhalf, whalf).await {
        Either::Left((Ok(..), _)) => trace!("REDIR relay {} -> {} ({}) closed", client_addr, svr_cfg.addr(), addr),
        Either::Left((Err(err), _)) => {
            if let ErrorKind::TimedOut = err.kind() {
                trace!(
                    "REDIR relay {} -> {} ({}) closed with error {}",
                    client_addr,
                    svr_cfg.addr(),
                    addr,
                    err,
                );
            } else {
                error!(
                    "REDIR relay {} -> {} ({}) closed with error {}",
                    client_addr,
                    svr_cfg.addr(),
                    addr,
                    err,
                );
            }
        }
        Either::Right((Ok(..), _)) => trace!("REDIR relay {} <- {} ({}) closed", client_addr, svr_cfg.addr(), addr),
        Either::Right((Err(err), _)) => {
            if let ErrorKind::TimedOut = err.kind() {
                trace!(
                    "REDIR relay {} <- {} ({}) closed with error {}",
                    client_addr,
                    svr_cfg.addr(),
                    addr,
                    err,
                );
            } else {
                error!(
                    "REDIR relay {} <- {} ({}) closed with error {}",
                    client_addr,
                    svr_cfg.addr(),
                    addr,
                    err,
                );
            }
        }
    }

    debug!("REDIR relay {} <-> {} ({}) closed", client_addr, svr_cfg.addr(), addr);

    Ok(())
}

async fn handle_redir_client(context: &Context, mut s: TcpStream, server_score: Arc<ServerScore>) -> io::Result<()> {
    let conf = server_score.server_config();

    if let Err(err) = s.set_keepalive(conf.timeout()) {
        error!("Failed to set keep alive: {:?}", err);
    }

    if context.config().no_delay {
        if let Err(err) = s.set_nodelay(true) {
            error!("Failed to set no delay: {:?}", err);
        }
    }

    let client_addr = s.peer_addr()?;

    // Get forward address from socket
    let target_addr = Address::from(get_original_destination_addr(&mut s)?);

    trace!("REDIR target address {}", target_addr);

    establish_client_tcp_redir(context, s, client_addr, &target_addr, conf).await
}

struct ServerScore {
    svr_cfg: ServerConfig,
    score: AtomicU64,
}

impl ServerScore {
    fn new(config: &ServerConfig) -> Arc<ServerScore> {
        let s = ServerScore {
            svr_cfg: config.clone(),
            score: AtomicU64::new(0),
        };
        Arc::new(s)
    }
}

impl PingServer for ServerScore {
    fn server_config(&self) -> &ServerConfig {
        &self.svr_cfg
    }

    fn score(&self) -> u64 {
        self.score.load(Ordering::Acquire)
    }

    fn set_score(&self, score: u64) {
        self.score.store(score, Ordering::Release);
    }
}

pub async fn run(context: SharedContext) -> io::Result<()> {
    if cfg!(not(target_os = "linux")) {
        unimplemented!("Transparent Proxy (redir) doesn't work on this platform");
    }

    assert!(
        context.config().mode.enable_tcp(),
        "You must enable TCP relay for transparent proxy"
    );

    let local_addr = context.config().local.as_ref().expect("Missing local config");
    let bind_addr = local_addr.bind_addr(&*context).await?;

    let mut listener = TcpListener::bind(&bind_addr)
        .await
        .unwrap_or_else(|err| panic!("Failed to listen on {}, {}", local_addr, err));

    let actual_local_addr = listener.local_addr().expect("Could not determine port bound to");

    let servers = context.config().server.iter().map(ServerScore::new).collect();
    let mut servers = PingBalancer::new(context.clone(), servers, PingServerType::Tcp).await;
    info!("ShadowSocks TCP Redir Listening on {}", actual_local_addr);

    loop {
        let (socket, peer_addr) = listener.accept().await?;
        let server_cfg = servers.pick_server();

        trace!("Got connection, addr: {}", peer_addr);
        trace!("Picked proxy server: {:?}", server_cfg.server_config());

        let context = context.clone();
        tokio::spawn(async move {
            if let Err(err) = handle_redir_client(&*context, socket, server_cfg).await {
                error!("TCP Redir client, error: {:?}", err);
            }
        });
    }
}
<commit_msg>[#190] Supports TCP Transparent Proxy on BSD-like systems<commit_after>//! Local server that establish a TCP Transparent Proxy with server

use std::{
    io,
    io::ErrorKind,
    net::SocketAddr,
    sync::{
        atomic::{AtomicU64, Ordering},
        Arc,
    },
};

use cfg_if::cfg_if;
use futures::future::{self, Either};
use log::{debug, error, info, trace};
use tokio::net::{TcpListener, TcpStream};

use crate::{
    config::ServerConfig,
    context::{Context, SharedContext},
    relay::{
        loadbalancing::server::{LoadBalancer, PingBalancer, PingServer, PingServerType},
        socks5::Address,
    },
};

cfg_if! {
    if #[cfg(any(target_os = "linux", target_os = "android"))] {
        fn get_original_destination_addr(s: &mut TcpStream) -> io::Result<SocketAddr> {
            use std::{
                io::Error,
                mem,
                net::{SocketAddrV4, SocketAddrV6},
                os::unix::io::AsRawFd,
            };
            let fd = s.as_raw_fd();
            unsafe {
                let mut target_addr: libc::sockaddr_storage = mem::zeroed();
                let mut target_addr_len = mem::size_of_val(&target_addr) as libc::socklen_t;
                // Check if it is IPv6 address
                let ret = libc::getsockopt(
                    fd,
                    libc::SOL_IPV6,
                    libc::SO_ORIGINAL_DST, // FIXME: Should use IP6T_SO_ORIGINAL_DST
                    &mut target_addr as *mut _ as *mut _,
                    &mut target_addr_len,
                );
                if ret != 0 {
                    let err = Error::last_os_error();
                    match err.raw_os_error() {
                        Some(libc::ENOPROTOOPT) | Some(libc::EOPNOTSUPP) => {
                            // The option is unknown at the level indicated.
                            //
                            // - The current system doesn't support IPv6 netfilter
                            // - This is not an IPv6 connection
                            //
                            // Continue with IPv4
                        }
                        _ => {
                            return Err(err);
                        }
                    }
                    let ret = libc::getsockopt(
                        fd,
                        libc::SOL_IP,
                        libc::SO_ORIGINAL_DST,
                        &mut target_addr as *mut _ as *mut _,
                        &mut target_addr_len,
                    );
                    if ret != 0 {
                        return Err(Error::last_os_error());
                    }
                }
                // Convert sockaddr_storage to SocketAddr
                match target_addr.ss_family as libc::c_int {
                    libc::AF_INET => {
                        let addr: SocketAddrV4 = mem::transmute_copy(&target_addr);
                        Ok(SocketAddr::V4(addr))
                    }
                    libc::AF_INET6 => {
                        let addr: SocketAddrV6 = mem::transmute_copy(&target_addr);
                        Ok(SocketAddr::V6(addr))
                    }
                    _ => {
                        let err = Error::new(ErrorKind::InvalidData, "family must be either AF_INET or AF_INET6");
                        return Err(err);
                    }
                }
            }
        }
    } else if #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", target_os = "dragonfly"))] {
        fn get_original_destination_addr(s: &mut TcpStream) -> io::Result<SocketAddr> {
            // On FreeBSD, Mac OS X, OpenBSD, ... use fwd action in IPFW or PF
            // Retrieve original destination address with getsockname()
            s.local_addr()
        }
    } else {
        fn get_original_destination_addr(_: &mut TcpStream) -> io::Result<SocketAddr> {
            unimplemented!("Transparent Proxy (redir) doesn't work on this platform");
        }
    }
}

/// Established Client Transparent Proxy
///
/// This method must be called after handshaking with client (for example, socks5 handshaking)
async fn establish_client_tcp_redir<'a>(
    context: &Context,
    mut s: TcpStream,
    client_addr: SocketAddr,
    addr: &Address,
    svr_cfg: &ServerConfig,
) -> io::Result<()> {
    let svr_s = match super::connect_proxy_server(context, &*svr_cfg).await {
        Ok(svr_s) => {
            trace!("Proxy server connected, {:?}", svr_cfg);
            svr_s
        }
        Err(err) => {
            // Just close the connection.
            error!("Failed to connect remote server {}, err: {}", svr_cfg.addr(), err);
            return Err(err);
        }
    };

    let mut svr_s = super::proxy_server_handshake(context, svr_s, svr_cfg, addr).await?;
    let (mut svr_r, mut svr_w) = svr_s.split();

    let (mut r, mut w) = s.split();

    use tokio::io::copy;

    let rhalf = copy(&mut r, &mut svr_w);
    let whalf = copy(&mut svr_r, &mut w);

    debug!(
        "REDIR relay established {} <-> {} ({})",
        client_addr,
        svr_cfg.addr(),
        addr
    );

    match future::select(rhalf, whalf).await {
        Either::Left((Ok(..), _)) => trace!("REDIR relay {} -> {} ({}) closed", client_addr, svr_cfg.addr(), addr),
        Either::Left((Err(err), _)) => {
            if let ErrorKind::TimedOut = err.kind() {
                trace!(
                    "REDIR relay {} -> {} ({}) closed with error {}",
                    client_addr,
                    svr_cfg.addr(),
                    addr,
                    err,
                );
            } else {
                error!(
                    "REDIR relay {} -> {} ({}) closed with error {}",
                    client_addr,
                    svr_cfg.addr(),
                    addr,
                    err,
                );
            }
        }
        Either::Right((Ok(..), _)) => trace!("REDIR relay {} <- {} ({}) closed", client_addr, svr_cfg.addr(), addr),
        Either::Right((Err(err), _)) => {
            if let ErrorKind::TimedOut = err.kind() {
                trace!(
                    "REDIR relay {} <- {} ({}) closed with error {}",
                    client_addr,
                    svr_cfg.addr(),
                    addr,
                    err,
                );
            } else {
                error!(
                    "REDIR relay {} <- {} ({}) closed with error {}",
                    client_addr,
                    svr_cfg.addr(),
                    addr,
                    err,
                );
            }
        }
    }

    debug!("REDIR relay {} <-> {} ({}) closed", client_addr, svr_cfg.addr(), addr);

    Ok(())
}

async fn handle_redir_client(context: &Context, mut s: TcpStream, server_score: Arc<ServerScore>) -> io::Result<()> {
    let conf = server_score.server_config();

    if let Err(err) = s.set_keepalive(conf.timeout()) {
        error!("Failed to set keep alive: {:?}", err);
    }

    if context.config().no_delay {
        if let Err(err) = s.set_nodelay(true) {
            error!("Failed to set no delay: {:?}", err);
        }
    }

    let client_addr = s.peer_addr()?;

    // Get forward address from socket
    let target_addr = Address::from(get_original_destination_addr(&mut s)?);

    trace!("REDIR target address {}", target_addr);

    establish_client_tcp_redir(context, s, client_addr, &target_addr, conf).await
}

struct ServerScore {
    svr_cfg: ServerConfig,
    score: AtomicU64,
}

impl ServerScore {
    fn new(config: &ServerConfig) -> Arc<ServerScore> {
        let s = ServerScore {
            svr_cfg: config.clone(),
            score: AtomicU64::new(0),
        };
        Arc::new(s)
    }
}

impl PingServer for ServerScore {
    fn server_config(&self) -> &ServerConfig {
        &self.svr_cfg
    }

    fn score(&self) -> u64 {
        self.score.load(Ordering::Acquire)
    }

    fn set_score(&self, score: u64) {
        self.score.store(score, Ordering::Release);
    }
}

pub async fn run(context: SharedContext) -> io::Result<()> {
    assert!(
        context.config().mode.enable_tcp(),
        "You must enable TCP relay for transparent proxy"
    );

    let local_addr = context.config().local.as_ref().expect("Missing local config");
    let bind_addr = local_addr.bind_addr(&*context).await?;

    let mut listener = TcpListener::bind(&bind_addr)
        .await
        .unwrap_or_else(|err| panic!("Failed to listen on {}, {}", local_addr, err));

    let actual_local_addr = listener.local_addr().expect("Could not determine port bound to");

    let servers = context.config().server.iter().map(ServerScore::new).collect();
    let mut servers = PingBalancer::new(context.clone(), servers, PingServerType::Tcp).await;
    info!("ShadowSocks TCP Redir Listening on {}", actual_local_addr);

    loop {
        let (socket, peer_addr) = listener.accept().await?;
        let server_cfg = servers.pick_server();

        trace!("Got connection, addr: {}", peer_addr);
        trace!("Picked proxy server: {:?}", server_cfg.server_config());

        let context = context.clone();
        tokio::spawn(async move {
            if let Err(err) = handle_redir_client(&*context, socket, server_cfg).await {
                error!("TCP Redir client, error: {:?}", err);
            }
        });
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The rust-pcre authors.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern mod extra;
extern mod rustc;
extern mod rustpkg;

use extra::time;
use rustc::driver::driver::host_triple;
use rustpkg::api;
use std::from_str::{from_str};
use std::io::fs::{mkdir, File};
use std::io::buffered::BufferedReader;
use std::io;
use std::option::{Option};
use std::os;
use std::run;
use std::str;

struct Version {
    major: uint,
    minor: uint
}

impl Version {
    pub fn parse(version_str: &str) -> Option<Version> {
        let mut it = version_str.split('.');
        match (it.next().and_then(from_str::<uint>), it.next().and_then(from_str::<uint>)) {
            (Some(major), Some(minor)) => Some(Version { major: major, minor: minor }),
            _                          => None
        }
    }
}

impl ToStr for Version {
    fn to_str(&self) -> ~str {
        format!("{:u}.{:u}", self.major, self.minor)
    }
}

impl Ord for Version {
    fn lt(&self, other: &Version) -> bool {
        self.major < other.major || (self.major == other.major && self.minor < other.minor)
    }
}

fn cd(path: &Path) {
    if !os::change_dir(path) {
        fail!("Package script error: Failed to `cd` into `{}`", path.display());
    }
}

fn do_install(args: ~[~str]) {
    let sysroot_arg = args[1].clone();
    let sysroot_path = from_str(sysroot_arg).unwrap();

    let pcre_libs = match os::getenv("PCRE_LIBS") {
        None            => {
            let pcre_config_output = io::io_error::cond.trap(|e: io::IoError| {
                match e.kind {
                    io::FileNotFound => fail!("Package script error: Could not run `pcre-config` because no such executable is in the executable search PATH. Make sure that you have installed a dev package for libpcre and/or make sure that libpcre's bindir is added to your PATH (currently \"{}\").", os::getenv("PATH").unwrap_or(~"")),
                    _ => fail!("Package script error: Could not run `pcre-config`: {}", e.to_str())
                }
            }).inside(|| -> run::ProcessOutput {
                run::process_output("pcre-config", [~"--libs"]).expect("failed to exec `pcre-config`")
            });
            if !pcre_config_output.status.success() {
                fail!("Package script error: `pcre-config` failed");
            }
            let output_ptr = pcre_config_output.output.as_ptr();
            let output_len = pcre_config_output.output.len();
            let libs_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };
            os::setenv("PCRE_LIBS", libs_str);
            libs_str
        },
        Some(pcre_libs) => pcre_libs
    };
    // `pcre-config` adds a newline to the end, which we need to trim away because newlines
    // in link_args cause build issues.
    let trimmed_pcre_libs = pcre_libs.trim();
    debug!("PCRE_LIBS=\"{:s}\"", trimmed_pcre_libs);

    let workspace_path = os::getcwd();

    // Check the version
    let target_build_path = workspace_path.join("build").join(host_triple());
    if !target_build_path.exists() {
        if !io::result(|| mkdir(&target_build_path, 0x1FF)).is_ok() {
            fail!("Package script error: Failed to create target build directory `{}`", target_build_path.display());
        }
    }
    let out_path = target_build_path.join("pcre");
    if !out_path.exists() {
        if !io::result(|| mkdir(&out_path, 0x1FF)).is_ok() {
            fail!("Package script error: Failed to create output directory `{}`", out_path.display());
        }
    }

    let versioncheck_rs_path = out_path.join("versioncheck.rs");
    {
        let mut w = match File::create(&versioncheck_rs_path) {
            None    => fail!("Package script error: Failed to open `{}` for writing", versioncheck_rs_path.display()),
            Some(w) => w
        };
        write!(&mut w as &mut Writer, "\
\\#[feature(globs)];
\\#[feature(link_args)];
use std::c_str::\\{CString\\};
use std::libc::*;
use std::ptr;
use std::vec;

type options = c_int;
struct pcre;
struct pcre_extra;

\\#[link_args = \"{:s}\"]
extern \\{
    static pcre_free: extern \"C\" fn(ptr: *c_void);

    fn pcre_compile(pattern: *c_char, options: options, errptr: *mut *c_char, erroffset: *mut c_int, tableptr: *c_uchar) -> *pcre;
    fn pcre_exec(code: *pcre, extra: *pcre_extra, subject: *c_char, length: c_int, startoffset: c_int, options: options, ovector: *mut c_int, ovecsize: c_int) -> c_int;
    fn pcre_version() -> *c_char;
\\}

fn main () \\{
    unsafe \\{
        let version_cstring = CString::new(pcre_version(), false);
        let version_str = version_cstring.as_str().unwrap().to_owned();

        let pattern = \"^\\\\\\\\d+\\\\\\\\.\\\\\\\\d+\";
        pattern.with_c_str(|pattern_c_str| \\{
            let mut err: *c_char = ptr::null();
            let mut erroffset: c_int = 0;
            let code = pcre_compile(pattern_c_str, 0, &mut err, &mut erroffset, ptr::null());
            if ptr::is_null(code) \\{
                if ptr::is_null(code) \\{
                    let err_cstring = CString::new(err, false);
                    match err_cstring.as_str() \\{
                        None          => fail!(\"pcre_compile() failed at offset \\{\\}\", erroffset as uint),
                        Some(err_str) => fail!(\"pcre_compile() failed at offset \\{\\}: \\{\\}\", erroffset as uint, err_str)
                    \\}
                \\}
            \\}
            assert!(ptr::is_not_null(code));

            let ovecsize = 1 * 3;
            let mut ovector: ~[c_int] = vec::from_elem(ovecsize, 0 as c_int);
            version_str.with_c_str_unchecked(|version_c_str| \\{
                let rc = pcre_exec(code, ptr::null(), version_c_str, version_str.len() as c_int, 0, 0, ovector.as_mut_ptr(), ovecsize as c_int);
                if rc < 0 \\{
                    fail!(\"pcre_exec() failed\");
                \\}

                print!(\"\\{\\}\", version_str.slice_to(ovector[1] as uint));
            \\});

            pcre_free(code as *c_void);
        \\});
    \\}
\\}
", trimmed_pcre_libs);
    }

    // Compile and run `versioncheck.rs`
    cd(&out_path);
    let rustc_run_output = run::process_output("rustc", [~"versioncheck.rs"]).expect("failed to exec `rustc`");
    if !rustc_run_output.status.success() {
        println!("{}", str::from_utf8(rustc_run_output.output));
        println!("{}", str::from_utf8(rustc_run_output.error));
        fail!("Package script error: `rustc versioncheck.rs` failed: {}", rustc_run_output.status);
    }
    let version_check_output = run::process_output("./versioncheck", []).expect("failed to exec `./versioncheck`");
    if !version_check_output.status.success() {
        println!("{}", str::from_utf8(version_check_output.output));
        println!("{}", str::from_utf8(version_check_output.error));
        fail!("versioncheck error: {}", version_check_output.status);
    }
    cd(&workspace_path);

    let output_ptr = version_check_output.output.as_ptr();
    let output_len = version_check_output.output.len();
    let output_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };
    debug!("output_str = `{}`", output_str);

    // The "no debug symbols in executable" warning may be present in the output.
    // https://github.com/mozilla/rust/issues/3495
    let mut output_rsplit_iter = output_str.rsplit('\n');
    let version_str: ~str = match output_rsplit_iter.next() {
        None              => output_str.clone(),
        Some(version_str) => version_str.to_owned()
    };

    debug!("libpcre version {:s}", version_str);

    let min_required_version = Version::parse("8.20").unwrap();
    let pcre_version = match Version::parse(version_str) {
        None               => fail!("Package script error: Failed to parse version string '{}'", version_str),
        Some(pcre_version) => pcre_version
    };

    if pcre_version < min_required_version {
        fail!("Package script error: Found libpcre version {}, but at least version {} is required", version_str, min_required_version.to_str());
    }

    let src_path = workspace_path.join("src");

    // Output `src/pcre/detail/native.rs`
    let detail_src_path = src_path.join("pcre").join("detail");
    if !detail_src_path.exists() {
        fail!("Package script error: Source directory `{}` does not exist.", detail_src_path.display());
    }
    let native_rs_path = detail_src_path.join("native.rs");
    let native_rs_in_path = detail_src_path.join("native.rs.in");
    if !native_rs_in_path.exists() {
        fail!("Package script error: Source file `{}` does not exist.", native_rs_in_path.display());
    }
    {
        let r = match File::open(&native_rs_in_path) {
            None    => fail!("Package script error: Failed to open `{}` for reading", native_rs_in_path.display()),
            Some(r) => r
        };
        let mut w = match File::create(&native_rs_path) {
            None    => fail!("Package script error: Failed to open `{}` for writing", native_rs_path.display()),
            Some(w) => w
        };
        write!(&mut w as &mut Writer, "// -*- buffer-read-only: t -*-\n");
        write!(&mut w as &mut Writer, "// Generated by {:s} on {:s}\n", args[0], time::now().rfc822());

        let mut buffered_reader = BufferedReader::new(r);
        for line in buffered_reader.lines() {
            let substituted_line = str::replace(line, "@PCRE_LIBS@", trimmed_pcre_libs);
            write!(&mut w as &mut Writer, "{:s}", substituted_line);
        }
    }

    api::build_lib(sysroot_path, workspace_path, ~"pcre", rustpkg::version::ExactRevision(~"0.1"), from_str("mod.rs").unwrap());
}

fn do_configs(args: ~[~str]) {
    drop(args);
}

fn main() {
    let args = os::args();
    let args_len = args.len();

    if args_len < 2 {
        fail!("Package script requires a directory where rustc libraries live as the first argument");
    } else if args_len < 3 {
        fail!("Package script requires a command as the second argument");
    }

    if args[2] == ~"install" {
        do_install(args);
    } else if args[2] == ~"configs" {
        do_configs(args);
    } else {
        fail!("Package script error: Unsupported command `{}`", args[2]);
    }
}
<commit_msg>Use BufferedReader from std::io<commit_after>// Copyright 2013 The rust-pcre authors.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern mod extra;
extern mod rustc;
extern mod rustpkg;

use extra::time;
use rustc::driver::driver::host_triple;
use rustpkg::api;
use std::from_str::{from_str};
use std::io;
use std::io::BufferedReader;
use std::io::fs::{mkdir, File};
use std::option::{Option};
use std::os;
use std::run;
use std::str;

struct Version {
    major: uint,
    minor: uint
}

impl Version {
    pub fn parse(version_str: &str) -> Option<Version> {
        let mut it = version_str.split('.');
        match (it.next().and_then(from_str::<uint>), it.next().and_then(from_str::<uint>)) {
            (Some(major), Some(minor)) => Some(Version { major: major, minor: minor }),
            _                          => None
        }
    }
}

impl ToStr for Version {
    fn to_str(&self) -> ~str {
        format!("{:u}.{:u}", self.major, self.minor)
    }
}

impl Ord for Version {
    fn lt(&self, other: &Version) -> bool {
        self.major < other.major || (self.major == other.major && self.minor < other.minor)
    }
}

fn cd(path: &Path) {
    if !os::change_dir(path) {
        fail!("Package script error: Failed to `cd` into `{}`", path.display());
    }
}

fn do_install(args: ~[~str]) {
    let sysroot_arg = args[1].clone();
    let sysroot_path = from_str(sysroot_arg).unwrap();

    let pcre_libs = match os::getenv("PCRE_LIBS") {
        None            => {
            let pcre_config_output = io::io_error::cond.trap(|e: io::IoError| {
                match e.kind {
                    io::FileNotFound => fail!("Package script error: Could not run `pcre-config` because no such executable is in the executable search PATH. Make sure that you have installed a dev package for libpcre and/or make sure that libpcre's bindir is added to your PATH (currently \"{}\").", os::getenv("PATH").unwrap_or(~"")),
                    _ => fail!("Package script error: Could not run `pcre-config`: {}", e.to_str())
                }
            }).inside(|| -> run::ProcessOutput {
                run::process_output("pcre-config", [~"--libs"]).expect("failed to exec `pcre-config`")
            });
            if !pcre_config_output.status.success() {
                fail!("Package script error: `pcre-config` failed");
            }
            let output_ptr = pcre_config_output.output.as_ptr();
            let output_len = pcre_config_output.output.len();
            let libs_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };
            os::setenv("PCRE_LIBS", libs_str);
            libs_str
        },
        Some(pcre_libs) => pcre_libs
    };
    // `pcre-config` adds a newline to the end, which we need to trim away because newlines
    // in link_args cause build issues.
    let trimmed_pcre_libs = pcre_libs.trim();
    debug!("PCRE_LIBS=\"{:s}\"", trimmed_pcre_libs);

    let workspace_path = os::getcwd();

    // Check the version
    let target_build_path = workspace_path.join("build").join(host_triple());
    if !target_build_path.exists() {
        if !io::result(|| mkdir(&target_build_path, 0x1FF)).is_ok() {
            fail!("Package script error: Failed to create target build directory `{}`", target_build_path.display());
        }
    }
    let out_path = target_build_path.join("pcre");
    if !out_path.exists() {
        if !io::result(|| mkdir(&out_path, 0x1FF)).is_ok() {
            fail!("Package script error: Failed to create output directory `{}`", out_path.display());
        }
    }

    let versioncheck_rs_path = out_path.join("versioncheck.rs");
    {
        let mut w = match File::create(&versioncheck_rs_path) {
            None    => fail!("Package script error: Failed to open `{}` for writing", versioncheck_rs_path.display()),
            Some(w) => w
        };
        write!(&mut w as &mut Writer, "\
\\#[feature(globs)];
\\#[feature(link_args)];
use std::c_str::\\{CString\\};
use std::libc::*;
use std::ptr;
use std::vec;

type options = c_int;
struct pcre;
struct pcre_extra;

\\#[link_args = \"{:s}\"]
extern \\{
    static pcre_free: extern \"C\" fn(ptr: *c_void);

    fn pcre_compile(pattern: *c_char, options: options, errptr: *mut *c_char, erroffset: *mut c_int, tableptr: *c_uchar) -> *pcre;
    fn pcre_exec(code: *pcre, extra: *pcre_extra, subject: *c_char, length: c_int, startoffset: c_int, options: options, ovector: *mut c_int, ovecsize: c_int) -> c_int;
    fn pcre_version() -> *c_char;
\\}

fn main () \\{
    unsafe \\{
        let version_cstring = CString::new(pcre_version(), false);
        let version_str = version_cstring.as_str().unwrap().to_owned();

        let pattern = \"^\\\\\\\\d+\\\\\\\\.\\\\\\\\d+\";
        pattern.with_c_str(|pattern_c_str| \\{
            let mut err: *c_char = ptr::null();
            let mut erroffset: c_int = 0;
            let code = pcre_compile(pattern_c_str, 0, &mut err, &mut erroffset, ptr::null());
            if ptr::is_null(code) \\{
                if ptr::is_null(code) \\{
                    let err_cstring = CString::new(err, false);
                    match err_cstring.as_str() \\{
                        None          => fail!(\"pcre_compile() failed at offset \\{\\}\", erroffset as uint),
                        Some(err_str) => fail!(\"pcre_compile() failed at offset \\{\\}: \\{\\}\", erroffset as uint, err_str)
                    \\}
                \\}
            \\}
            assert!(ptr::is_not_null(code));

            let ovecsize = 1 * 3;
            let mut ovector: ~[c_int] = vec::from_elem(ovecsize, 0 as c_int);
            version_str.with_c_str_unchecked(|version_c_str| \\{
                let rc = pcre_exec(code, ptr::null(), version_c_str, version_str.len() as c_int, 0, 0, ovector.as_mut_ptr(), ovecsize as c_int);
                if rc < 0 \\{
                    fail!(\"pcre_exec() failed\");
                \\}

                print!(\"\\{\\}\", version_str.slice_to(ovector[1] as uint));
            \\});

            pcre_free(code as *c_void);
        \\});
    \\}
\\}
", trimmed_pcre_libs);
    }

    // Compile and run `versioncheck.rs`
    cd(&out_path);
    let rustc_run_output = run::process_output("rustc", [~"versioncheck.rs"]).expect("failed to exec `rustc`");
    if !rustc_run_output.status.success() {
        println!("{}", str::from_utf8(rustc_run_output.output));
        println!("{}", str::from_utf8(rustc_run_output.error));
        fail!("Package script error: `rustc versioncheck.rs` failed: {}", rustc_run_output.status);
    }
    let version_check_output = run::process_output("./versioncheck", []).expect("failed to exec `./versioncheck`");
    if !version_check_output.status.success() {
        println!("{}", str::from_utf8(version_check_output.output));
        println!("{}", str::from_utf8(version_check_output.error));
        fail!("versioncheck error: {}", version_check_output.status);
    }
    cd(&workspace_path);

    let output_ptr = version_check_output.output.as_ptr();
    let output_len = version_check_output.output.len();
    let output_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };
    debug!("output_str = `{}`", output_str);

    // The "no debug symbols in executable" warning may be present in the output.
    // https://github.com/mozilla/rust/issues/3495
    let mut output_rsplit_iter = output_str.rsplit('\n');
    let version_str: ~str = match output_rsplit_iter.next() {
        None              => output_str.clone(),
        Some(version_str) => version_str.to_owned()
    };

    debug!("libpcre version {:s}", version_str);

    let min_required_version = Version::parse("8.20").unwrap();
    let pcre_version = match Version::parse(version_str) {
        None               => fail!("Package script error: Failed to parse version string '{}'", version_str),
        Some(pcre_version) => pcre_version
    };

    if pcre_version < min_required_version {
        fail!("Package script error: Found libpcre version {}, but at least version {} is required", version_str, min_required_version.to_str());
    }

    let src_path = workspace_path.join("src");

    // Output `src/pcre/detail/native.rs`
    let detail_src_path = src_path.join("pcre").join("detail");
    if !detail_src_path.exists() {
        fail!("Package script error: Source directory `{}` does not exist.", detail_src_path.display());
    }
    let native_rs_path = detail_src_path.join("native.rs");
    let native_rs_in_path = detail_src_path.join("native.rs.in");
    if !native_rs_in_path.exists() {
        fail!("Package script error: Source file `{}` does not exist.", native_rs_in_path.display());
    }
    {
        let r = match File::open(&native_rs_in_path) {
            None    => fail!("Package script error: Failed to open `{}` for reading", native_rs_in_path.display()),
            Some(r) => r
        };
        let mut w = match File::create(&native_rs_path) {
            None    => fail!("Package script error: Failed to open `{}` for writing", native_rs_path.display()),
            Some(w) => w
        };
        write!(&mut w as &mut Writer, "// -*- buffer-read-only: t -*-\n");
        write!(&mut w as &mut Writer, "// Generated by {:s} on {:s}\n", args[0], time::now().rfc822());

        let mut buffered_reader = BufferedReader::new(r);
        for line in buffered_reader.lines() {
            let substituted_line = str::replace(line, "@PCRE_LIBS@", trimmed_pcre_libs);
            write!(&mut w as &mut Writer, "{:s}", substituted_line);
        }
    }

    api::build_lib(sysroot_path, workspace_path, ~"pcre", rustpkg::version::ExactRevision(~"0.1"), from_str("mod.rs").unwrap());
}

fn do_configs(args: ~[~str]) {
    drop(args);
}

fn main() {
    let args = os::args();
    let args_len = args.len();

    if args_len < 2 {
        fail!("Package script requires a directory where rustc libraries live as the first argument");
    } else if args_len < 3 {
        fail!("Package script requires a command as the second argument");
    }

    if args[2] == ~"install" {
        do_install(args);
    } else if args[2] == ~"configs" {
        do_configs(args);
    } else {
        fail!("Package script error: Unsupported command `{}`", args[2]);
    }
}
<|endoftext|>


<commit_before>// This file is part of the uutils coreutils package.
//
// (c) Virgile Andreani <virgile.andreani@anbuco.fr>
// (c) kwantam <kwantam@gmail.com>
//     * 2015-04-28 ~ updated to work with both UTF-8 and non-UTF-8 encodings
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (ToDO) ctype cwidth iflag nbytes nspaces nums tspaces uflag

#[macro_use]
extern crate uucore;

use clap::{crate_version, App, Arg, ArgMatches};
use std::fs::File;
use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Write};
use std::iter::repeat;
use std::str::from_utf8;
use unicode_width::UnicodeWidthChar;

static ABOUT: &str = "Convert tabs in each FILE to spaces, writing to standard output.
 With no FILE, or when FILE is -, read standard input.";

pub mod options {
    pub static TABS: &str = "tabs";
    pub static INITIAL: &str = "initial";
    pub static NO_UTF8: &str = "no-utf8";
    pub static FILES: &str = "FILES";
}

static LONG_HELP: &str = "";

static DEFAULT_TABSTOP: usize = 8;

fn get_usage() -> String {
    format!("{0} [OPTION]... [FILE]...", executable!())
}

fn tabstops_parse(s: String) -> Vec<usize> {
    let words = s.split(',');

    let nums = words
        .map(|sn| {
            sn.parse::<usize>()
                .unwrap_or_else(|_| crash!(1, "{}\n", "tab size contains invalid character(s)"))
        })
        .collect::<Vec<usize>>();

    if nums.iter().any(|&n| n == 0) {
        crash!(1, "{}\n", "tab size cannot be 0");
    }

    if let (false, _) = nums
        .iter()
        .fold((true, 0), |(acc, last), &n| (acc && last <= n, n))
    {
        crash!(1, "{}\n", "tab sizes must be ascending");
    }

    nums
}

struct Options {
    files: Vec<String>,
    tabstops: Vec<usize>,
    tspaces: String,
    iflag: bool,
    uflag: bool,
}

impl Options {
    fn new(matches: &ArgMatches) -> Options {
        let tabstops = match matches.value_of(options::TABS) {
            Some(s) => tabstops_parse(s.to_string()),
            None => vec![DEFAULT_TABSTOP],
        };

        let iflag = matches.is_present(options::INITIAL);
        let uflag = !matches.is_present(options::NO_UTF8);

        // avoid allocations when dumping out long sequences of spaces
        // by precomputing the longest string of spaces we will ever need
        let nspaces = tabstops
            .iter()
            .scan(0, |pr, &it| {
                let ret = Some(it - *pr);
                *pr = it;
                ret
            })
            .max()
            .unwrap(); // length of tabstops is guaranteed >= 1
        let tspaces = repeat(' ').take(nspaces).collect();

        let files: Vec<String> = match matches.values_of(options::FILES) {
            Some(s) => s.map(|v| v.to_string()).collect(),
            None => vec!["-".to_owned()],
        };

        Options {
            files,
            tabstops,
            tspaces,
            iflag,
            uflag,
        }
    }
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let usage = get_usage();
    let matches = App::new(executable!())
        .version(crate_version!())
        .about(ABOUT)
        .usage(&usage[..])
        .after_help(LONG_HELP)
        .arg(
            Arg::with_name(options::INITIAL)
                .long(options::INITIAL)
                .short("i")
                .help("do not convert tabs after non blanks"),
        )
        .arg(
            Arg::with_name(options::TABS)
                .long(options::TABS)
                .short("t")
                .value_name("N, LIST")
                .takes_value(true)
                .help("have tabs N characters apart, not 8 or use comma separated list of explicit tab positions"),
        )
        .arg(
            Arg::with_name(options::NO_UTF8)
                .long(options::NO_UTF8)
                .short("U")
                .help("interpret input file as 8-bit ASCII rather than UTF-8"),
        ).arg(
            Arg::with_name(options::FILES)
                .multiple(true)
                .hidden(true)
                .takes_value(true)
        )
        .get_matches_from(args);

    expand(Options::new(&matches));
    0
}

fn open(path: String) -> BufReader<Box<dyn Read + 'static>> {
    let file_buf;
    if path == "-" {
        BufReader::new(Box::new(stdin()) as Box<dyn Read>)
    } else {
        file_buf = match File::open(&path[..]) {
            Ok(a) => a,
            Err(e) => crash!(1, "{}: {}\n", &path[..], e),
        };
        BufReader::new(Box::new(file_buf) as Box<dyn Read>)
    }
}

fn next_tabstop(tabstops: &[usize], col: usize) -> usize {
    if tabstops.len() == 1 {
        tabstops[0] - col % tabstops[0]
    } else {
        match tabstops.iter().find(|&&t| t > col) {
            Some(t) => t - col,
            None => 1,
        }
    }
}

#[derive(PartialEq, Eq, Debug)]
enum CharType {
    Backspace,
    Tab,
    Other,
}

fn expand(options: Options) {
    use self::CharType::*;

    let mut output = BufWriter::new(stdout());
    let ts = options.tabstops.as_ref();
    let mut buf = Vec::new();

    for file in options.files.into_iter() {
        let mut fh = open(file);

        while match fh.read_until(b'\n', &mut buf) {
            Ok(s) => s > 0,
            Err(_) => buf.is_empty(),
        } {
            let mut col = 0;
            let mut byte = 0;
            let mut init = true;

            while byte < buf.len() {
                let (ctype, cwidth, nbytes) = if options.uflag {
                    let nbytes = char::from(buf[byte]).len_utf8();

                    if byte + nbytes > buf.len() {
                        // don't overrun buffer because of invalid UTF-8
                        (Other, 1, 1)
                    } else if let Ok(t) = from_utf8(&buf[byte..byte + nbytes]) {
                        match t.chars().next() {
                            Some('\t') => (Tab, 0, nbytes),
                            Some('\x08') => (Backspace, 0, nbytes),
                            Some(c) => (Other, UnicodeWidthChar::width(c).unwrap_or(0), nbytes),
                            None => {
                                // no valid char at start of t, so take 1 byte
                                (Other, 1, 1)
                            }
                        }
                    } else {
                        (Other, 1, 1) // implicit assumption: non-UTF-8 char is 1 col wide
                    }
                } else {
                    (
                        match buf[byte] {
                            // always take exactly 1 byte in strict ASCII mode
                            0x09 => Tab,
                            0x08 => Backspace,
                            _ => Other,
                        },
                        1,
                        1,
                    )
                };

                // figure out how many columns this char takes up
                match ctype {
                    Tab => {
                        // figure out how many spaces to the next tabstop
                        let nts = next_tabstop(ts, col);
                        col += nts;

                        // now dump out either spaces if we're expanding, or a literal tab if we're not
                        if init || !options.iflag {
                            safe_unwrap!(output.write_all(&options.tspaces[..nts].as_bytes()));
                        } else {
                            safe_unwrap!(output.write_all(&buf[byte..byte + nbytes]));
                        }
                    }
                    _ => {
                        col = if ctype == Other {
                            col + cwidth
                        } else if col > 0 {
                            col - 1
                        } else {
                            0
                        };

                        // if we're writing anything other than a space, then we're
                        // done with the line's leading spaces
                        if buf[byte] != 0x20 {
                            init = false;
                        }

                        safe_unwrap!(output.write_all(&buf[byte..byte + nbytes]));
                    }
                }

                byte += nbytes; // advance the pointer
            }

            safe_unwrap!(output.flush());
            buf.truncate(0); // clear the buffer
        }
    }
}
<commit_msg>refactor/expand ~ fix `cargo clippy` complaint (clippy::needless_borrow)<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Virgile Andreani <virgile.andreani@anbuco.fr>
// (c) kwantam <kwantam@gmail.com>
//     * 2015-04-28 ~ updated to work with both UTF-8 and non-UTF-8 encodings
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (ToDO) ctype cwidth iflag nbytes nspaces nums tspaces uflag

#[macro_use]
extern crate uucore;

use clap::{crate_version, App, Arg, ArgMatches};
use std::fs::File;
use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Write};
use std::iter::repeat;
use std::str::from_utf8;
use unicode_width::UnicodeWidthChar;

static ABOUT: &str = "Convert tabs in each FILE to spaces, writing to standard output.
 With no FILE, or when FILE is -, read standard input.";

pub mod options {
    pub static TABS: &str = "tabs";
    pub static INITIAL: &str = "initial";
    pub static NO_UTF8: &str = "no-utf8";
    pub static FILES: &str = "FILES";
}

static LONG_HELP: &str = "";

static DEFAULT_TABSTOP: usize = 8;

fn get_usage() -> String {
    format!("{0} [OPTION]... [FILE]...", executable!())
}

fn tabstops_parse(s: String) -> Vec<usize> {
    let words = s.split(',');

    let nums = words
        .map(|sn| {
            sn.parse::<usize>()
                .unwrap_or_else(|_| crash!(1, "{}\n", "tab size contains invalid character(s)"))
        })
        .collect::<Vec<usize>>();

    if nums.iter().any(|&n| n == 0) {
        crash!(1, "{}\n", "tab size cannot be 0");
    }

    if let (false, _) = nums
        .iter()
        .fold((true, 0), |(acc, last), &n| (acc && last <= n, n))
    {
        crash!(1, "{}\n", "tab sizes must be ascending");
    }

    nums
}

struct Options {
    files: Vec<String>,
    tabstops: Vec<usize>,
    tspaces: String,
    iflag: bool,
    uflag: bool,
}

impl Options {
    fn new(matches: &ArgMatches) -> Options {
        let tabstops = match matches.value_of(options::TABS) {
            Some(s) => tabstops_parse(s.to_string()),
            None => vec![DEFAULT_TABSTOP],
        };

        let iflag = matches.is_present(options::INITIAL);
        let uflag = !matches.is_present(options::NO_UTF8);

        // avoid allocations when dumping out long sequences of spaces
        // by precomputing the longest string of spaces we will ever need
        let nspaces = tabstops
            .iter()
            .scan(0, |pr, &it| {
                let ret = Some(it - *pr);
                *pr = it;
                ret
            })
            .max()
            .unwrap(); // length of tabstops is guaranteed >= 1
        let tspaces = repeat(' ').take(nspaces).collect();

        let files: Vec<String> = match matches.values_of(options::FILES) {
            Some(s) => s.map(|v| v.to_string()).collect(),
            None => vec!["-".to_owned()],
        };

        Options {
            files,
            tabstops,
            tspaces,
            iflag,
            uflag,
        }
    }
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let usage = get_usage();
    let matches = App::new(executable!())
        .version(crate_version!())
        .about(ABOUT)
        .usage(&usage[..])
        .after_help(LONG_HELP)
        .arg(
            Arg::with_name(options::INITIAL)
                .long(options::INITIAL)
                .short("i")
                .help("do not convert tabs after non blanks"),
        )
        .arg(
            Arg::with_name(options::TABS)
                .long(options::TABS)
                .short("t")
                .value_name("N, LIST")
                .takes_value(true)
                .help("have tabs N characters apart, not 8 or use comma separated list of explicit tab positions"),
        )
        .arg(
            Arg::with_name(options::NO_UTF8)
                .long(options::NO_UTF8)
                .short("U")
                .help("interpret input file as 8-bit ASCII rather than UTF-8"),
        ).arg(
            Arg::with_name(options::FILES)
                .multiple(true)
                .hidden(true)
                .takes_value(true)
        )
        .get_matches_from(args);

    expand(Options::new(&matches));
    0
}

fn open(path: String) -> BufReader<Box<dyn Read + 'static>> {
    let file_buf;
    if path == "-" {
        BufReader::new(Box::new(stdin()) as Box<dyn Read>)
    } else {
        file_buf = match File::open(&path[..]) {
            Ok(a) => a,
            Err(e) => crash!(1, "{}: {}\n", &path[..], e),
        };
        BufReader::new(Box::new(file_buf) as Box<dyn Read>)
    }
}

fn next_tabstop(tabstops: &[usize], col: usize) -> usize {
    if tabstops.len() == 1 {
        tabstops[0] - col % tabstops[0]
    } else {
        match tabstops.iter().find(|&&t| t > col) {
            Some(t) => t - col,
            None => 1,
        }
    }
}

#[derive(PartialEq, Eq, Debug)]
enum CharType {
    Backspace,
    Tab,
    Other,
}

fn expand(options: Options) {
    use self::CharType::*;

    let mut output = BufWriter::new(stdout());
    let ts = options.tabstops.as_ref();
    let mut buf = Vec::new();

    for file in options.files.into_iter() {
        let mut fh = open(file);

        while match fh.read_until(b'\n', &mut buf) {
            Ok(s) => s > 0,
            Err(_) => buf.is_empty(),
        } {
            let mut col = 0;
            let mut byte = 0;
            let mut init = true;

            while byte < buf.len() {
                let (ctype, cwidth, nbytes) = if options.uflag {
                    let nbytes = char::from(buf[byte]).len_utf8();

                    if byte + nbytes > buf.len() {
                        // don't overrun buffer because of invalid UTF-8
                        (Other, 1, 1)
                    } else if let Ok(t) = from_utf8(&buf[byte..byte + nbytes]) {
                        match t.chars().next() {
                            Some('\t') => (Tab, 0, nbytes),
                            Some('\x08') => (Backspace, 0, nbytes),
                            Some(c) => (Other, UnicodeWidthChar::width(c).unwrap_or(0), nbytes),
                            None => {
                                // no valid char at start of t, so take 1 byte
                                (Other, 1, 1)
                            }
                        }
                    } else {
                        (Other, 1, 1) // implicit assumption: non-UTF-8 char is 1 col wide
                    }
                } else {
                    (
                        match buf[byte] {
                            // always take exactly 1 byte in strict ASCII mode
                            0x09 => Tab,
                            0x08 => Backspace,
                            _ => Other,
                        },
                        1,
                        1,
                    )
                };

                // figure out how many columns this char takes up
                match ctype {
                    Tab => {
                        // figure out how many spaces to the next tabstop
                        let nts = next_tabstop(ts, col);
                        col += nts;

                        // now dump out either spaces if we're expanding, or a literal tab if we're not
                        if init || !options.iflag {
                            safe_unwrap!(output.write_all(options.tspaces[..nts].as_bytes()));
                        } else {
                            safe_unwrap!(output.write_all(&buf[byte..byte + nbytes]));
                        }
                    }
                    _ => {
                        col = if ctype == Other {
                            col + cwidth
                        } else if col > 0 {
                            col - 1
                        } else {
                            0
                        };

                        // if we're writing anything other than a space, then we're
                        // done with the line's leading spaces
                        if buf[byte] != 0x20 {
                            init = false;
                        }

                        safe_unwrap!(output.write_all(&buf[byte..byte + nbytes]));
                    }
                }

                byte += nbytes; // advance the pointer
            }

            safe_unwrap!(output.flush());
            buf.truncate(0); // clear the buffer
        }
    }
}
<|endoftext|>


<commit_before>// * This file is part of the uutils coreutils package.
// *
// * (c) 2020 nicoo <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

extern crate rand;

use std::collections::BTreeMap;
use std::fmt;

use crate::numeric::{Arithmetic, Montgomery};
use crate::{miller_rabin, rho, table};

#[derive(Clone, Debug)]
pub struct Factors {
    f: BTreeMap<u64, u8>,
}

impl Factors {
    pub fn one() -> Factors {
        Factors { f: BTreeMap::new() }
    }

    pub fn add(&mut self, prime: u64, exp: u8) {
        debug_assert!(miller_rabin::is_prime(prime));
        debug_assert!(exp > 0);
        let n = *self.f.get(&prime).unwrap_or(&0);
        self.f.insert(prime, exp + n);
    }

    pub fn push(&mut self, prime: u64) {
        self.add(prime, 1)
    }

    #[cfg(test)]
    fn product(&self) -> u64 {
        self.f
            .iter()
            .fold(1, |acc, (p, exp)| acc * p.pow(*exp as u32))
    }
}

impl fmt::Display for Factors {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        for (p, exp) in self.f.iter() {
            for _ in 0..*exp {
                write!(f, " {}", p)?
            }
        }

        Ok(())
    }
}

fn _factor<A: Arithmetic>(num: u64, f: Factors) -> Factors {
    use miller_rabin::Result::*;
    // Shadow the name, so the recursion automatically goes from “Big” arithmetic to small.
    let _factor = |n, f| {
        // TODO: Optimise with 32 and 64b versions
        _factor::<A>(n, f)
    };

    if num == 1 {
        return f;
    }

    let n = A::new(num);
    let divisor = match miller_rabin::test::<A>(n) {
        Prime => {
            let mut r = f;
            r.push(num);
            return r;
        }

        Composite(d) => d,
        Pseudoprime => rho::find_divisor::<A>(n),
    };

    let f = _factor(divisor, f);
    _factor(num / divisor, f)
}

pub fn factor(mut n: u64) -> Factors {
    let mut factors = Factors::one();

    if n < 2 {
        factors.push(n);
        return factors;
    }

    let z = n.trailing_zeros();
    if z > 0 {
        factors.add(2, z as u8);
        n >>= z;
    }

    if n == 1 {
        return factors;
    }

    let (factors, n) = table::factor(n, factors);

    // TODO: Optimise with 32 and 64b versions
    _factor::<Montgomery>(n, factors)
}

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

    #[test]
    fn factor_recombines_small() {
        assert!((1..10_000)
            .map(|i| 2 * i + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_overflowing() {
        assert!((0..250)
            .map(|i| 2 * i + 2u64.pow(32) + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_strong_pseudoprime() {
        // This is a strong pseudoprime (wrt. miller_rabin::BASIS)
        //  and triggered a bug in rho::factor's codepath handling
        //  miller_rabbin::Result::Composite
        let pseudoprime = 17179869183;
        for _ in 0..20 {
            // Repeat the test 20 times, as it only fails some fraction
            // of the time.
            assert!(factor(pseudoprime).product() == pseudoprime);
        }
    }

    quickcheck! {
        fn factor_recombines(i: u64) -> bool {
            i == 0 || factor(i).product() == i
        }
    }
}
<commit_msg>Fix bug in factor::factor::factor (>_>")<commit_after>// * This file is part of the uutils coreutils package.
// *
// * (c) 2020 nicoo <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

extern crate rand;

use std::collections::BTreeMap;
use std::fmt;

use crate::numeric::{Arithmetic, Montgomery};
use crate::{miller_rabin, rho, table};

#[derive(Clone, Debug)]
pub struct Factors {
    f: BTreeMap<u64, u8>,
}

impl Factors {
    pub fn one() -> Factors {
        Factors { f: BTreeMap::new() }
    }

    pub fn add(&mut self, prime: u64, exp: u8) {
        debug_assert!(miller_rabin::is_prime(prime));
        debug_assert!(exp > 0);
        let n = *self.f.get(&prime).unwrap_or(&0);
        self.f.insert(prime, exp + n);
    }

    pub fn push(&mut self, prime: u64) {
        self.add(prime, 1)
    }

    #[cfg(test)]
    fn product(&self) -> u64 {
        self.f
            .iter()
            .fold(1, |acc, (p, exp)| acc * p.pow(*exp as u32))
    }
}

impl fmt::Display for Factors {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        for (p, exp) in self.f.iter() {
            for _ in 0..*exp {
                write!(f, " {}", p)?
            }
        }

        Ok(())
    }
}

fn _factor<A: Arithmetic>(num: u64, f: Factors) -> Factors {
    use miller_rabin::Result::*;
    // Shadow the name, so the recursion automatically goes from “Big” arithmetic to small.
    let _factor = |n, f| {
        // TODO: Optimise with 32 and 64b versions
        _factor::<A>(n, f)
    };

    if num == 1 {
        return f;
    }

    let n = A::new(num);
    let divisor = match miller_rabin::test::<A>(n) {
        Prime => {
            let mut r = f;
            r.push(num);
            return r;
        }

        Composite(d) => d,
        Pseudoprime => rho::find_divisor::<A>(n),
    };

    let f = _factor(divisor, f);
    _factor(num / divisor, f)
}

pub fn factor(mut n: u64) -> Factors {
    let mut factors = Factors::one();

    if n < 2 {
        return factors;
    }

    let z = n.trailing_zeros();
    if z > 0 {
        factors.add(2, z as u8);
        n >>= z;
    }

    if n == 1 {
        return factors;
    }

    let (factors, n) = table::factor(n, factors);

    // TODO: Optimise with 32 and 64b versions
    _factor::<Montgomery>(n, factors)
}

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

    #[test]
    fn factor_recombines_small() {
        assert!((1..10_000)
            .map(|i| 2 * i + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_overflowing() {
        assert!((0..250)
            .map(|i| 2 * i + 2u64.pow(32) + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_strong_pseudoprime() {
        // This is a strong pseudoprime (wrt. miller_rabin::BASIS)
        //  and triggered a bug in rho::factor's codepath handling
        //  miller_rabbin::Result::Composite
        let pseudoprime = 17179869183;
        for _ in 0..20 {
            // Repeat the test 20 times, as it only fails some fraction
            // of the time.
            assert!(factor(pseudoprime).product() == pseudoprime);
        }
    }

    quickcheck! {
        fn factor_recombines(i: u64) -> bool {
            i == 0 || factor(i).product() == i
        }
    }
}
<|endoftext|>