<commit_before>use crate::schema::{evaluation_events, score_awards, badge_awards};
use crate::submission::{self, Submission, SubmissionStatus};
use diesel::prelude::*;
use diesel::sql_types::{Double, Text, Bool};
use juniper::FieldResult;
use std::error::Error;
use std::thread;
use turingarena::evaluation::mem::Evaluation;
use turingarena::evaluation::Event;
use turingarena::problem::driver::{ProblemDriver, ProblemPack};
use turingarena::award::{Score, AwardName};
use turingarena_task_maker::driver::IoiProblemDriver;

/// An evaluation event
#[derive(Queryable, Serialize, Deserialize, Clone, Debug)]
pub struct EvaluationEvent {
    /// id of the submission
    submission_id: String,

    /// serial number of the event
    serial: i32,

    /// value of the event, serialized
    event_json: String,
}

#[juniper::object]
impl EvaluationEvent {
    /// serial number of the event
    fn serial(&self) -> i32 {
        self.serial
    }

    /// value of this evaluation event
    fn event(&self) -> FieldResult<Event> {
        Ok(serde_json::from_str(&self.event_json)?)
    }

    /// events as JSON format
    /// This is currently provided only as a woraround the fact that
    /// events doesn't work, and should be removed in the future!
    fn event_json(&self) -> &String {
        &self.event_json
    }
}

#[derive(Insertable)]
#[table_name = "evaluation_events"]
struct EvaluationEventInput<'a> {
    submission_id: &'a str,
    serial: i32,
    event_json: String,
}

#[derive(Insertable)]
#[table_name = "score_awards"]
struct ScoreAwardInput<'a> {
    submission_id: &'a str,
    award_name: &'a str,
    score: f64,
}

#[derive(Insertable)]
#[table_name = "badge_awards"]
struct BadgeAwardInput<'a> {
    submission_id: &'a str,
    award_name: &'a str,
    badge: bool,
}

#[derive(Queryable)]
pub struct ScoreAward {
    /// Id of the submission
    #[allow(dead_code)]
    submission_id: String,

    /// Id of the scorable
    award_name: String,

    /// Score of the submission
    score: f64,
}

#[derive(Queryable)]
pub struct BadgeAward {
    /// Id of the submission
    #[allow(dead_code)]
    submission_id: String,

    /// Id of the scorable
    award_name: String,

    /// Score of the submission
    badge: bool,
}

#[juniper::object]
impl ScoreAward {
    /// The score
    fn score(&self) -> Score {
        Score(self.score)
    }

    /// Name of the award
    fn award_name(&self) -> AwardName {
        AwardName(self.award_name.clone())
    }
}

#[juniper::object]
impl BadgeAward {
    /// The badge
    fn badge(&self) -> bool {
        self.badge
    }

    /// Name of the award
    fn award_name(&self) -> AwardName {
        AwardName(self.award_name.clone())
    }
}

#[derive(QueryableByName)]
pub struct MaxScoreAward {
    #[sql_type = "Text"]
    scorable_id: String,

    #[sql_type = "Double"]
    score: f64,

    #[sql_type = "Text"]
    submission_id: String,
}

#[derive(QueryableByName)]
pub struct BestBadgeAward {
    #[sql_type = "Text"]
    scorable_id: String,

    #[sql_type = "Bool"]
    badge: bool,

    #[sql_type = "Text"]
    submission_id: String,
}

/// Maximum score award
#[juniper::object]
impl MaxScoreAward {
    /// Id of the most recent submission that made the max score
    fn submission_id(&self) -> &String {
        &self.submission_id
    }

    /// The score
    fn score(&self) -> Score {
        Score(self.score)
    }

    /// Id of the scorable
    fn scorable_id(&self) -> &String {
        &self.scorable_id
    }
}

/// Beste badge award
#[juniper::object]
impl BestBadgeAward {
    /// Id of the most recent submission that made the max score
    fn submission_id(&self) -> &String {
        &self.submission_id
    }

    /// The score
    fn badge(&self) -> bool {
        self.badge
    }

    /// Id of the scorable
    fn scorable_id(&self) -> &String {
        &self.scorable_id
    }
}

fn insert_event(
    conn: &SqliteConnection,
    serial: i32,
    submission_id: &str,
    event: &Event,
) -> Result<(), Box<dyn Error>> {
    if let Event::Score(score_event) = event {
        let score_award_input = ScoreAwardInput {
            award_name: &score_event.award_name.0,
            score: score_event.score.0,
            submission_id,
        };
        diesel::insert_into(score_awards::table)
            .values(&score_award_input)
            .execute(conn)?;
    }
    if let Event::Badge(badge_event) = event {
        let badge_award_input = BadgeAwardInput {
            award_name: &badge_event.award_name.0,
            badge: badge_event.badge,
            submission_id,
        };
        diesel::insert_into(badge_awards::table)
            .values(&badge_award_input)
            .execute(conn)?;
    }
    let event_input = EvaluationEventInput {
        serial,
        submission_id,
        event_json: serde_json::to_string(event)?,
    };
    diesel::insert_into(evaluation_events::table)
        .values(&event_input)
        .execute(conn)?;
    Ok(())
}

/// return a list of evaluation events for the specified evaluation
pub fn query_events(
    conn: &SqliteConnection,
    submission_id: &str,
) -> QueryResult<Vec<EvaluationEvent>> {
    evaluation_events::table
        .filter(evaluation_events::dsl::submission_id.eq(submission_id))
        .load(conn)
}

/// Get the best score award for (user, problem)
pub fn query_score_awards_of_user_and_problem(
    conn: &SqliteConnection,
    user_id: &str,
    problem_name: &str,
) -> QueryResult<Vec<MaxScoreAward>> {
    diesel::sql_query(
        "
        SELECT sc.award_id, MAX(sc.score) as score, (
            SELECT s.id
            FROM submissions s JOIN badge_awards sci ON s.id = sci.submission_id
            WHERE sci.score = score AND sci.award_id = sc.award_id
            ORDER BY s.created_at DESC
            LIMIT 1
        ) as submission_id
        FROM badge_awards sc JOIN submissions s ON sc.submission_id = s.id
        WHERE s.problem_name = ? AND s.user_id = ?
        GROUP BY sc.award_id
    ",
    )
        .bind::<Text, _>(problem_name)
        .bind::<Text, _>(user_id)
        .load::<MaxScoreAward>(conn)
}

/// Get the best award badge for (user, problem)
pub fn query_badge_awards_of_user_and_problem(
    conn: &SqliteConnection,
    user_id: &str,
    problem_name: &str,
) -> QueryResult<Vec<BestBadgeAward>> {
    diesel::sql_query(
        "
        SELECT sc.award_id, MAX(sc.badge) as badge, (
            SELECT s.id
            FROM submissions s JOIN badge_awards sci ON s.id = sci.submission_id
            WHERE sci.badge = badge AND sci.award_id = sc.award_id
            ORDER BY s.created_at DESC
            LIMIT 1
        ) as submission_id
        FROM badge_awards sc JOIN submissions s ON sc.submission_id = s.id
        WHERE s.problem_name = ? AND s.user_id = ?
        GROUP BY sc.award_id
    ",
    )
        .bind::<Text, _>(problem_name)
        .bind::<Text, _>(user_id)
        .load::<BestBadgeAward>(conn)
}

/// Get the score awards of (user, problem, submission)
pub fn query_score_awards(
    conn: &SqliteConnection,
    submission_id: &str,
) -> QueryResult<Vec<ScoreAward>> {
    score_awards::table
        .filter(score_awards::dsl::submission_id.eq(submission_id))
        .load(conn)
}

/// Get the badge awards of (user, problem, submission)
pub fn query_badge_awards(
    conn: &SqliteConnection,
    submission_id: &str,
) -> QueryResult<Vec<BadgeAward>> {
    badge_awards::table
        .filter(badge_awards::dsl::submission_id.eq(submission_id))
        .load(conn)
}

/// start the evaluation thread
pub fn evaluate(
    problem_pack: ProblemPack,
    submission: &Submission,
    db_connection: SqliteConnection,
) -> QueryResult<()> {
    let submission_id = submission.id.clone();
    let submission = submission.to_mem_submission(&db_connection)?;
    thread::spawn(move || {
        let Evaluation(receiver) = IoiProblemDriver::evaluate(problem_pack, submission);
        for (serial, event) in receiver.into_iter().enumerate() {
            insert_event(&db_connection, serial as i32, &submission_id, &event).unwrap();
        }
        submission::set_status(&db_connection, &submission_id, SubmissionStatus::Success).unwrap();
    });
    Ok(())
}
<commit_msg>contest: rename some missing `scorable` -> `award`<commit_after>use crate::schema::{evaluation_events, score_awards, badge_awards};
use crate::submission::{self, Submission, SubmissionStatus};
use diesel::prelude::*;
use diesel::sql_types::{Double, Text, Bool};
use juniper::FieldResult;
use std::error::Error;
use std::thread;
use turingarena::evaluation::mem::Evaluation;
use turingarena::evaluation::Event;
use turingarena::problem::driver::{ProblemDriver, ProblemPack};
use turingarena::award::{Score, AwardName};
use turingarena_task_maker::driver::IoiProblemDriver;

/// An evaluation event
#[derive(Queryable, Serialize, Deserialize, Clone, Debug)]
pub struct EvaluationEvent {
    /// id of the submission
    submission_id: String,

    /// serial number of the event
    serial: i32,

    /// value of the event, serialized
    event_json: String,
}

#[juniper::object]
impl EvaluationEvent {
    /// serial number of the event
    fn serial(&self) -> i32 {
        self.serial
    }

    /// value of this evaluation event
    fn event(&self) -> FieldResult<Event> {
        Ok(serde_json::from_str(&self.event_json)?)
    }

    /// events as JSON format
    /// This is currently provided only as a woraround the fact that
    /// events doesn't work, and should be removed in the future!
    fn event_json(&self) -> &String {
        &self.event_json
    }
}

#[derive(Insertable)]
#[table_name = "evaluation_events"]
struct EvaluationEventInput<'a> {
    submission_id: &'a str,
    serial: i32,
    event_json: String,
}

#[derive(Insertable)]
#[table_name = "score_awards"]
struct ScoreAwardInput<'a> {
    submission_id: &'a str,
    award_name: &'a str,
    score: f64,
}

#[derive(Insertable)]
#[table_name = "badge_awards"]
struct BadgeAwardInput<'a> {
    submission_id: &'a str,
    award_name: &'a str,
    badge: bool,
}

#[derive(Queryable)]
pub struct ScoreAward {
    /// Id of the submission
    #[allow(dead_code)]
    submission_id: String,

    /// Name of the award
    award_name: String,

    /// Score of the submission
    score: f64,
}

#[derive(Queryable)]
pub struct BadgeAward {
    /// Id of the submission
    #[allow(dead_code)]
    submission_id: String,

    /// Name of the award
    award_name: String,

    /// Score of the submission
    badge: bool,
}

#[juniper::object]
impl ScoreAward {
    /// The score
    fn score(&self) -> Score {
        Score(self.score)
    }

    /// Name of the award
    fn award_name(&self) -> AwardName {
        AwardName(self.award_name.clone())
    }
}

#[juniper::object]
impl BadgeAward {
    /// The badge
    fn badge(&self) -> bool {
        self.badge
    }

    /// Name of the award
    fn award_name(&self) -> AwardName {
        AwardName(self.award_name.clone())
    }
}

#[derive(QueryableByName)]
pub struct MaxScoreAward {
    #[sql_type = "Text"]
    award_name: String,

    #[sql_type = "Double"]
    score: f64,

    #[sql_type = "Text"]
    submission_id: String,
}

#[derive(QueryableByName)]
pub struct BestBadgeAward {
    #[sql_type = "Text"]
    award_name: String,

    #[sql_type = "Bool"]
    badge: bool,

    #[sql_type = "Text"]
    submission_id: String,
}

/// Maximum score award
#[juniper::object]
impl MaxScoreAward {
    /// Id of the most recent submission that made the max score
    fn submission_id(&self) -> &String {
        &self.submission_id
    }

    /// The score
    fn score(&self) -> Score {
        Score(self.score)
    }

    /// Name of the award
    fn award_name(&self) -> &String {
        &self.award_name
    }
}

/// Beste badge award
#[juniper::object]
impl BestBadgeAward {
    /// Id of the most recent submission that made the max score
    fn submission_id(&self) -> &String {
        &self.submission_id
    }

    /// The score
    fn badge(&self) -> bool {
        self.badge
    }

    /// Name of the award
    fn award_name(&self) -> &String {
        &self.award_name
    }
}

fn insert_event(
    conn: &SqliteConnection,
    serial: i32,
    submission_id: &str,
    event: &Event,
) -> Result<(), Box<dyn Error>> {
    if let Event::Score(score_event) = event {
        let score_award_input = ScoreAwardInput {
            award_name: &score_event.award_name.0,
            score: score_event.score.0,
            submission_id,
        };
        diesel::insert_into(score_awards::table)
            .values(&score_award_input)
            .execute(conn)?;
    }
    if let Event::Badge(badge_event) = event {
        let badge_award_input = BadgeAwardInput {
            award_name: &badge_event.award_name.0,
            badge: badge_event.badge,
            submission_id,
        };
        diesel::insert_into(badge_awards::table)
            .values(&badge_award_input)
            .execute(conn)?;
    }
    let event_input = EvaluationEventInput {
        serial,
        submission_id,
        event_json: serde_json::to_string(event)?,
    };
    diesel::insert_into(evaluation_events::table)
        .values(&event_input)
        .execute(conn)?;
    Ok(())
}

/// return a list of evaluation events for the specified evaluation
pub fn query_events(
    conn: &SqliteConnection,
    submission_id: &str,
) -> QueryResult<Vec<EvaluationEvent>> {
    evaluation_events::table
        .filter(evaluation_events::dsl::submission_id.eq(submission_id))
        .load(conn)
}

/// Get the best score award for (user, problem)
pub fn query_score_awards_of_user_and_problem(
    conn: &SqliteConnection,
    user_id: &str,
    problem_name: &str,
) -> QueryResult<Vec<MaxScoreAward>> {
    diesel::sql_query(
        "
        SELECT sc.award_id, MAX(sc.score) as score, (
            SELECT s.id
            FROM submissions s JOIN badge_awards sci ON s.id = sci.submission_id
            WHERE sci.score = score AND sci.award_id = sc.award_id
            ORDER BY s.created_at DESC
            LIMIT 1
        ) as submission_id
        FROM badge_awards sc JOIN submissions s ON sc.submission_id = s.id
        WHERE s.problem_name = ? AND s.user_id = ?
        GROUP BY sc.award_id
    ",
    )
        .bind::<Text, _>(problem_name)
        .bind::<Text, _>(user_id)
        .load::<MaxScoreAward>(conn)
}

/// Get the best award badge for (user, problem)
pub fn query_badge_awards_of_user_and_problem(
    conn: &SqliteConnection,
    user_id: &str,
    problem_name: &str,
) -> QueryResult<Vec<BestBadgeAward>> {
    diesel::sql_query(
        "
        SELECT sc.award_id, MAX(sc.badge) as badge, (
            SELECT s.id
            FROM submissions s JOIN badge_awards sci ON s.id = sci.submission_id
            WHERE sci.badge = badge AND sci.award_id = sc.award_id
            ORDER BY s.created_at DESC
            LIMIT 1
        ) as submission_id
        FROM badge_awards sc JOIN submissions s ON sc.submission_id = s.id
        WHERE s.problem_name = ? AND s.user_id = ?
        GROUP BY sc.award_id
    ",
    )
        .bind::<Text, _>(problem_name)
        .bind::<Text, _>(user_id)
        .load::<BestBadgeAward>(conn)
}

/// Get the score awards of (user, problem, submission)
pub fn query_score_awards(
    conn: &SqliteConnection,
    submission_id: &str,
) -> QueryResult<Vec<ScoreAward>> {
    score_awards::table
        .filter(score_awards::dsl::submission_id.eq(submission_id))
        .load(conn)
}

/// Get the badge awards of (user, problem, submission)
pub fn query_badge_awards(
    conn: &SqliteConnection,
    submission_id: &str,
) -> QueryResult<Vec<BadgeAward>> {
    badge_awards::table
        .filter(badge_awards::dsl::submission_id.eq(submission_id))
        .load(conn)
}

/// start the evaluation thread
pub fn evaluate(
    problem_pack: ProblemPack,
    submission: &Submission,
    db_connection: SqliteConnection,
) -> QueryResult<()> {
    let submission_id = submission.id.clone();
    let submission = submission.to_mem_submission(&db_connection)?;
    thread::spawn(move || {
        let Evaluation(receiver) = IoiProblemDriver::evaluate(problem_pack, submission);
        for (serial, event) in receiver.into_iter().enumerate() {
            insert_event(&db_connection, serial as i32, &submission_id, &event).unwrap();
        }
        submission::set_status(&db_connection, &submission_id, SubmissionStatus::Success).unwrap();
    });
    Ok(())
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use std::fmt::Debug;
use std::ops::{Add, Mul};

use {Transform, Vector3f};
use interaction::SurfaceInteraction;
use paramset::TextureParams;
use spectrum::Spectrum;
use texture::{PlanarMapping2D, Texture, TextureMapping2D, UVMapping2D};

#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum AAMethod {
    None,
    ClosedForm,
}

#[derive(Debug)]
pub struct CheckerboardTexture<T> {
    tex1: Arc<Texture<T>>,
    tex2: Arc<Texture<T>>,
    mapping: Box<TextureMapping2D>,
    aa_method: AAMethod,
}

impl<T> CheckerboardTexture<T> {
    pub fn new(
        tex1: Arc<Texture<T>>,
        tex2: Arc<Texture<T>>,
        mapping: Box<TextureMapping2D>,
        aa_method: AAMethod,
    ) -> CheckerboardTexture<T> {
        CheckerboardTexture {
            tex1,
            tex2,
            mapping,
            aa_method,
        }
    }
}

impl CheckerboardTexture<Spectrum> {
    pub fn create_spectrum(
        _tex2world: &Transform,
        tp: &TextureParams,
    ) -> CheckerboardTexture<Spectrum> {
        let dim = tp.find_int("dimension", 2);
        if dim != 2 && dim != 3 {
            panic!("{} dimensional checkerboard texture not supported", dim);
        }
        let tex1 = tp.get_spectrum_texture("tex1", &Spectrum::white());
        let tex2 = tp.get_spectrum_texture("tex2", &Spectrum::black());
        if dim == 2 {
            // Initialize 2D texture mapping `map` from `tp`
            let typ = tp.find_string("mapping", "uv");
            let map: Box<TextureMapping2D> = if typ == "uv" {
                let su = tp.find_float("uscale", 1.0);
                let sv = tp.find_float("vscale", 1.0);
                let du = tp.find_float("udelta", 0.0);
                let dv = tp.find_float("vdelta", 0.0);
                Box::new(UVMapping2D::new(su, sv, du, dv))
            } else if typ == "spherical" {
                unimplemented!()
            } else if typ == "cylindrical" {
                unimplemented!()
            } else if typ == "planar" {
                let vs = tp.find_vector3f("v1", Vector3f::new(1.0, 0.0, 0.0));
                let vt = tp.find_vector3f("v2", Vector3f::new(0.0, 1.0, 0.0));
                let ds = tp.find_float("udelta", 0.0);
                let dt = tp.find_float("vdelta", 0.0);
                Box::new(PlanarMapping2D::new(vs, vt, ds, dt))
            } else {
                error!("2D texture mapping {} unknown", typ);
                Box::new(UVMapping2D::new(1.0, 1.0, 0.0, 0.0))
            };

            // Compute `aaMethod` for `CheckerboardTexture`
            let aa = tp.find_string("aamode", "closedform");
            let aa_method = if aa == "none" {
                AAMethod::None
            } else if aa == "closedform" {
                AAMethod::ClosedForm
            } else {
                warn!("Unknown aamethod \"{}\" found for CheckerboardTexture. Using closedform instead",
                      aa);
                AAMethod::ClosedForm
            };
            CheckerboardTexture::new(tex1, tex2, map, aa_method)
        } else {
            unimplemented!()
        }
    }
}

impl<T> Texture<T> for CheckerboardTexture<T>
where
    T: Debug,
    T: Mul<f32, Output = T>,
    T: Add<Output = T>,
{
    fn evaluate(&self, si: &SurfaceInteraction) -> T {
        let (st, dstdx, dstdy) = self.mapping.map(si);
        match self.aa_method {
            AAMethod::None => {
                if (st.x.floor() as u32 + st.y.floor() as u32) % 2 == 0 {
                    self.tex1.evaluate(si)
                } else {
                    self.tex2.evaluate(si)
                }
            }
            AAMethod::ClosedForm => {
                // Compute closed-form box-filtered _Checkerboard2DTexture_ value

                // Evaluate single check if filter is entirely inside one of them
                let ds = f32::max(f32::abs(dstdx[0]), f32::abs(dstdy[0]));
                let dt = f32::max(f32::abs(dstdx[1]), f32::abs(dstdy[1]));
                let s0 = st[0] - ds;
                let s1 = st[0] + ds;
                let t0 = st[1] - dt;
                let t1 = st[1] + dt;
                if f32::floor(s0) == f32::floor(s1) && f32::floor(t0) == f32::floor(t1) {
                    // Point sample _Checkerboard2DTexture_
                    if (f32::floor(st[0]) as i32 + f32::floor(st[1]) as i32) % 2 == 0 {
                        return self.tex1.evaluate(si);
                    } else {
                        return self.tex2.evaluate(si);
                    }
                }

                // Apply box filter to checkerboard region
                fn bump_int(x: f32) -> i32 {
                    (f32::floor(x / 2.0) + 2.0 * f32::max(x / 2.0 - f32::floor(x / 2.0) - 0.5, 0.0))
                        as i32
                }
                let sint = (bump_int(s1) - bump_int(s0)) as f32 / (2.0 * ds);
                let tint = (bump_int(t1) - bump_int(t0)) as f32 / (2.0 * dt);
                let mut area2 = sint + tint - 2.0 * sint * tint;
                if ds > 1.0 || dt > 1.0 {
                    area2 = 0.5
                };
                self.tex1.evaluate(si) * (1.0 - area2) + self.tex2.evaluate(si) * area2
            }
        }
    }
}
<commit_msg>Fix bug in checkerboard texture<commit_after>use std::sync::Arc;
use std::fmt::Debug;
use std::ops::{Add, Mul};

use {Transform, Vector3f};
use interaction::SurfaceInteraction;
use paramset::TextureParams;
use spectrum::Spectrum;
use texture::{PlanarMapping2D, Texture, TextureMapping2D, UVMapping2D};

#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum AAMethod {
    None,
    ClosedForm,
}

#[derive(Debug)]
pub struct CheckerboardTexture<T> {
    tex1: Arc<Texture<T>>,
    tex2: Arc<Texture<T>>,
    mapping: Box<TextureMapping2D>,
    aa_method: AAMethod,
}

impl<T> CheckerboardTexture<T> {
    pub fn new(
        tex1: Arc<Texture<T>>,
        tex2: Arc<Texture<T>>,
        mapping: Box<TextureMapping2D>,
        aa_method: AAMethod,
    ) -> CheckerboardTexture<T> {
        CheckerboardTexture {
            tex1,
            tex2,
            mapping,
            aa_method,
        }
    }
}

impl CheckerboardTexture<Spectrum> {
    pub fn create_spectrum(
        _tex2world: &Transform,
        tp: &TextureParams,
    ) -> CheckerboardTexture<Spectrum> {
        let dim = tp.find_int("dimension", 2);
        if dim != 2 && dim != 3 {
            panic!("{} dimensional checkerboard texture not supported", dim);
        }
        let tex1 = tp.get_spectrum_texture("tex1", &Spectrum::white());
        let tex2 = tp.get_spectrum_texture("tex2", &Spectrum::black());
        if dim == 2 {
            // Initialize 2D texture mapping `map` from `tp`
            let typ = tp.find_string("mapping", "uv");
            let map: Box<TextureMapping2D> = if typ == "uv" {
                let su = tp.find_float("uscale", 1.0);
                let sv = tp.find_float("vscale", 1.0);
                let du = tp.find_float("udelta", 0.0);
                let dv = tp.find_float("vdelta", 0.0);
                Box::new(UVMapping2D::new(su, sv, du, dv))
            } else if typ == "spherical" {
                unimplemented!()
            } else if typ == "cylindrical" {
                unimplemented!()
            } else if typ == "planar" {
                let vs = tp.find_vector3f("v1", Vector3f::new(1.0, 0.0, 0.0));
                let vt = tp.find_vector3f("v2", Vector3f::new(0.0, 1.0, 0.0));
                let ds = tp.find_float("udelta", 0.0);
                let dt = tp.find_float("vdelta", 0.0);
                Box::new(PlanarMapping2D::new(vs, vt, ds, dt))
            } else {
                error!("2D texture mapping {} unknown", typ);
                Box::new(UVMapping2D::new(1.0, 1.0, 0.0, 0.0))
            };

            // Compute `aaMethod` for `CheckerboardTexture`
            let aa = tp.find_string("aamode", "closedform");
            let aa_method = if aa == "none" {
                AAMethod::None
            } else if aa == "closedform" {
                AAMethod::ClosedForm
            } else {
                warn!("Unknown aamethod \"{}\" found for CheckerboardTexture. Using closedform instead",
                      aa);
                AAMethod::ClosedForm
            };
            CheckerboardTexture::new(tex1, tex2, map, aa_method)
        } else {
            unimplemented!()
        }
    }
}

impl<T> Texture<T> for CheckerboardTexture<T>
where
    T: Debug,
    T: Mul<f32, Output = T>,
    T: Add<Output = T>,
{
    fn evaluate(&self, si: &SurfaceInteraction) -> T {
        let (st, dstdx, dstdy) = self.mapping.map(si);
        match self.aa_method {
            AAMethod::None => {
                if (st.x.floor() as u32 + st.y.floor() as u32) % 2 == 0 {
                    self.tex1.evaluate(si)
                } else {
                    self.tex2.evaluate(si)
                }
            }
            AAMethod::ClosedForm => {
                // Compute closed-form box-filtered _Checkerboard2DTexture_ value

                // Evaluate single check if filter is entirely inside one of them
                let ds = f32::max(f32::abs(dstdx[0]), f32::abs(dstdy[0]));
                let dt = f32::max(f32::abs(dstdx[1]), f32::abs(dstdy[1]));
                let s0 = st[0] - ds;
                let s1 = st[0] + ds;
                let t0 = st[1] - dt;
                let t1 = st[1] + dt;
                if f32::floor(s0) == f32::floor(s1) && f32::floor(t0) == f32::floor(t1) {
                    // Point sample _Checkerboard2DTexture_
                    if (f32::floor(st[0]) as i32 + f32::floor(st[1]) as i32) % 2 == 0 {
                        return self.tex1.evaluate(si);
                    } else {
                        return self.tex2.evaluate(si);
                    }
                }

                // Apply box filter to checkerboard region
                fn bump_int(x: f32) -> f32 {
                    f32::floor(x / 2.0) + 2.0 * f32::max(x / 2.0 - f32::floor(x / 2.0) - 0.5, 0.0)
                }
                let sint = (bump_int(s1) - bump_int(s0)) / (2.0 * ds);
                let tint = (bump_int(t1) - bump_int(t0)) / (2.0 * dt);
                let mut area2 = sint + tint - 2.0 * sint * tint;
                if ds > 1.0 || dt > 1.0 {
                    area2 = 0.5
                };
                self.tex1.evaluate(si) * (1.0 - area2) + self.tex2.evaluate(si) * area2
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::process::{Command, Stdio};
use std::io::Cursor;
use std::sync::Arc;
use std::time::Duration;
use std::os::unix::process::ExitStatusExt;

use tokio::prelude::*;
use tokio::prelude::future::Either;
use tokio::timer::timeout;
use tokio_process::CommandExt;
use tokio::{io::{flush, read_exact, write_all}, net::unix::UnixStream};
use bytes::{BytesMut, Buf, BufMut};

use crate::{ExecBackend, UnixSocketBackend};

fn strsig(sig: i32) -> &'static str {
    match sig {
        1 => "Hangup",
        2 => "Interrupt",
        3 => "Quit",
        4 => "Illegal instruction",
        5 => "Trace/breakpoint trap",
        6 => "Aborted",
        7 => "Bus error",
        8 => "Floating point exception",
        9 => "Killed",
        10 => "User defined signal 1",
        11 => "Segmentation fault",
        12 => "User defined signal 2",
        13 => "Broken pipe",
        14 => "Alarm clock",
        15 => "Terminated",
        16 => "Stack fault",
        17 => "Child exited",
        18 => "Continued",
        19 => "Stopped (signal)",
        20 => "Stopped",
        21 => "Stopped (tty input)",
        22 => "Stopped (tty output)",
        23 => "Urgent I/O condition",
        24 => "CPU time limit exceeded",
        25 => "File size limit exceeded",
        26 => "Virtual timer expired",
        27 => "Profiling timer expired",
        28 => "Window changed",
        29 => "I/O possible",
        30 => "Power failure",
        31 => "Bad system call",
        _ => "Unknown signal"
    }
}

fn strsigabbrev(sig: i32) -> &'static str {
    match sig {
        1 => "SIGHUP",
        2 => "SIGINT",
        3 => "SIGQUIT",
        4 => "SIGILL",
        5 => "SIGTRAP",
        6 => "SIGABRT",
        7 => "SIGBUS",
        8 => "SIGFPE",
        9 => "SIGKILL",
        10 => "SIGUSR1",
        11 => "SIGSEGV",
        12 => "SIGUSR2",
        13 => "SIGPIPE",
        14 => "SIGALRM",
        15 => "SIGTERM",
        16 => "SIGSTKFLT",
        17 => "SIGCHLD",
        18 => "SIGCONT",
        19 => "SIGSTOP",
        20 => "SIGTSTP",
        21 => "SIGTTIN",
        22 => "SIGTTOU",
        23 => "SIGURG",
        24 => "SIGXCPU",
        25 => "SIGXFSZ",
        26 => "SIGVTALRM",
        27 => "SIGPROF",
        28 => "SIGWINCH",
        29 => "SIGPOLL",
        30 => "SIGPWR",
        31 => "SIGSYS",
        _ => "(unknown)"
    }
}

pub fn exec<'a, T>(
    lang: Arc<ExecBackend>,
    timeout: Option<usize>,
    code: T) -> impl Future<Item = String, Error = String> + 'a
        where T: AsRef<[u8]> + 'a {
    let timeout_arg = timeout
        .map(|t| format!("{}{}", lang.timeout_prefix.as_ref().map(String::as_str).unwrap_or(""), t));
    let timeout_arg_ref = timeout_arg.as_ref().map(String::as_str);
    if let Some(path) = lang.cmdline.iter().nth(0) {
        let mut cmd = Command::new(path);
        cmd.args(lang.cmdline.iter()
            .skip(1)
            .filter_map(|a| if a == "{TIMEOUT}" {
                timeout_arg_ref
            } else {
                Some(a.as_ref())
            }))
            .stdin(Stdio::piped()).stdout(Stdio::piped()).stderr(Stdio::piped());
        debug!("spawning {:?}", cmd);
        Either::A(cmd.spawn_async()
            .map_err(|e| format!("failed to exec: {}", e))
            .into_future()
            .and_then(|mut child| {
                child.stdin().take().ok_or_else(|| "stdin missing".to_owned()).into_future()
                    .and_then(|stdin|
                        write_all(stdin, code)
                            .map_err(|e| format!("failed to write to stdin: {}", e))
                    )
                    .and_then(move |_| {
                        let stdout = match child.stdout().take() {
                            // FIXME configurable max
                            Some(io) => Either::A(helper::read_up_to(io, vec![0u8; 1024])
                                .map(|(_, mut v, s)| {
                                    v.truncate(s);
                                    v
                                })),
                            None => Either::B(Ok(Vec::new()).into_future()),
                        };
                        let stderr = match child.stderr().take() {
                            // FIXME configurable max
                            Some(io) => Either::A(helper::read_up_to(io, vec![0u8; 1024])
                                .map(|(_, mut v, s)| {
                                    v.truncate(s);
                                    v
                                })),
                            None => Either::B(Ok(Vec::new()).into_future()),
                        };
                        child.join3(stdout, stderr)
                    }.map_err(|e| format!("failed to wait for process: {}", e)))
            })
            .map_err(|e| format!("unknown error in exec: {}", e))
            .map(|(status, stdout, stderr)| {
                let mut r = format!("{}{}",
                    String::from_utf8_lossy(&stderr),
                    String::from_utf8_lossy(&stdout),
                );
                if !status.success() {
                    if !r.ends_with('\n') {
                        r.push_str("\n");
                    }
                    if let Some(code) = status.code() {
                        r.push_str(&format!("exited with status {}\n", code));
                    } else if let Some(code) = status.signal() {
                        r.push_str(&format!("signalled with {} ({})\n", strsig(code), strsigabbrev(code)));
                    } else {
                        r.push_str("exited with unknown failure\n");
                    }
                }
                r
            }))
    } else {
        Either::B(Err("empty cmdline".to_owned()).into_future())
    }
}

macro_rules! persistent {
    ($lang:expr, $connfut:expr, $timeout:expr, $buf:expr) => ({
        let buf = $buf;
        let fut = $connfut
            .map_err(|e| format!("error connecting: {}", e))
            .and_then(move |s| write_all(s, buf)
                .map_err(|e| format!("error writing: {}", e)))
            .and_then(|(s, _)| flush(s)
                .map_err(|e| format!("error flushing: {}", e)))
            .and_then(|s| read_exact(s, [0u8; 4])
                .map_err(|e| format!("error reading result length: {}", e)));
        if let Some(timeout) = $timeout {
            Either::A(fut.timeout(Duration::from_secs(timeout as u64)))
        } else {
            Either::B(fut.map_err(|e| timeout::Error::inner(e)))
        }.then(|r| match r {
            Ok((s, lenb)) => Either::A(read_exact(s, {
                // FIXME configurable max
                let outlen = Cursor::new(lenb).get_u32_le().min(1024) as usize;
                let mut buf = BytesMut::with_capacity(outlen);
                buf.resize(outlen, 0);
                buf
            }).map_err(|e| format!("error reading result: {}", e))
                .map(|(_, ref outb)| String::from_utf8_lossy(outb).into_owned())),
            Err(e) => Either::B(if e.is_elapsed() {
                Err("time limit exceeded".to_owned()).into_future()
            } else {
                Err(format!("error: {}", e)).into_future()
            })
        }).map_err(move |e| {
            do_persistent_timeout(&$lang.timeout_cmdline);
            e
        })
    });
}

pub fn unix<'a, T, U>(
    lang: Arc<UnixSocketBackend>,
    timeout: Option<usize>,
    context: Option<U>,
    code: T) -> impl Future<Item = String, Error = String> + 'a
        where
            T: AsRef<[u8]>,
            U: AsRef<[u8]> {
    persistent!(lang,
        UnixStream::connect(&lang.socket_addr),
        timeout,
        make_persistent_input(timeout, context, code))
}

fn do_persistent_timeout(cmdline: &Option<Vec<String>>) {
    if let Some(cmdline) = cmdline.as_ref() {
        if let Some(path) = cmdline.iter().nth(0) {
            debug!("timeout kill: launching {:?}", cmdline);
            tokio::spawn(Command::new(path)
                .args(cmdline.iter().skip(1))
                .spawn_async()
                .map_err(|e| error!("failed to exec for timeout kill: {}", e))
                .into_future()
                .and_then(|c| c
                    .map_err(|e| error!("failed to exec for timeout kill: {}", e)))
                    .map(|_| ()));
        }
    }
}

fn make_persistent_input<T, U>(timeout: Option<usize>, context: Option<T>, code: U) -> BytesMut
    where
        T: AsRef<[u8]>,
        U: AsRef<[u8]> {
    let timeout = timeout.unwrap_or(0usize) as u32;
    let contextb = context.as_ref().map(|x| x.as_ref()).unwrap_or(&super::EMPTY_U8);
    let codeb = code.as_ref();
    let contextblen = contextb.len() as u32;
    let codeblen = codeb.len() as u32;

    let mut buf = BytesMut::with_capacity(12usize + contextblen as usize + codeblen as usize);
    buf.put_u32_le(timeout*1000);
    buf.put_u32_le(contextblen);
    buf.put_u32_le(codeblen);
    buf.put(&contextb[..contextblen as usize]);
    buf.put(&codeb[..codeblen as usize]);
    buf
}

mod helper {
    // https://docs.rs/tokio-io/0.1.10/src/tokio_io/io/read_exact.rs.html

    use std::io;
    use std::mem;

    use futures::{Poll, Future};

    use tokio::io::AsyncRead;

    #[derive(Debug)]
    pub struct ReadUpTo<A, T> {
        state: State<A, T>,
    }

    #[derive(Debug)]
    enum State<A, T> {
        Reading {
            a: A,
            buf: T,
            pos: usize,
        },
        Empty,
    }

    pub fn read_up_to<A, T>(a: A, buf: T) -> ReadUpTo<A, T>
        where A: AsyncRead,
            T: AsMut<[u8]>,
    {
        ReadUpTo {
            state: State::Reading {
                a,
                buf,
                pos: 0,
            },
        }
    }

    impl<A, T> Future for ReadUpTo<A, T>
        where A: AsyncRead,
            T: AsMut<[u8]>,
    {
        type Item = (A, T, usize);
        type Error = io::Error;

        fn poll(&mut self) -> Poll<(A, T, usize), io::Error> {
            match self.state {
                State::Reading { ref mut a, ref mut buf, ref mut pos } => {
                    let buf = buf.as_mut();
                    while *pos < buf.len() {
                        let n = try_ready!(a.poll_read(&mut buf[*pos..]));
                        *pos += n;
                        if n == 0 {
                            break;
                        }
                    }
                }
                State::Empty => panic!("poll a ReadUpTo after it's done"),
            }

            match mem::replace(&mut self.state, State::Empty) {
                State::Reading { a, buf, pos } => Ok((a, buf, pos).into()),
                State::Empty => panic!(),
            }
        }
    }
}
<commit_msg>Substitute {TIMEOUT} with 0 if no timeout, instead of removing<commit_after>use std::process::{Command, Stdio};
use std::io::Cursor;
use std::sync::Arc;
use std::time::Duration;
use std::os::unix::process::ExitStatusExt;

use tokio::prelude::*;
use tokio::prelude::future::Either;
use tokio::timer::timeout;
use tokio_process::CommandExt;
use tokio::{io::{flush, read_exact, write_all}, net::unix::UnixStream};
use bytes::{BytesMut, Buf, BufMut};

use crate::{ExecBackend, UnixSocketBackend};

fn strsig(sig: i32) -> &'static str {
    match sig {
        1 => "Hangup",
        2 => "Interrupt",
        3 => "Quit",
        4 => "Illegal instruction",
        5 => "Trace/breakpoint trap",
        6 => "Aborted",
        7 => "Bus error",
        8 => "Floating point exception",
        9 => "Killed",
        10 => "User defined signal 1",
        11 => "Segmentation fault",
        12 => "User defined signal 2",
        13 => "Broken pipe",
        14 => "Alarm clock",
        15 => "Terminated",
        16 => "Stack fault",
        17 => "Child exited",
        18 => "Continued",
        19 => "Stopped (signal)",
        20 => "Stopped",
        21 => "Stopped (tty input)",
        22 => "Stopped (tty output)",
        23 => "Urgent I/O condition",
        24 => "CPU time limit exceeded",
        25 => "File size limit exceeded",
        26 => "Virtual timer expired",
        27 => "Profiling timer expired",
        28 => "Window changed",
        29 => "I/O possible",
        30 => "Power failure",
        31 => "Bad system call",
        _ => "Unknown signal"
    }
}

fn strsigabbrev(sig: i32) -> &'static str {
    match sig {
        1 => "SIGHUP",
        2 => "SIGINT",
        3 => "SIGQUIT",
        4 => "SIGILL",
        5 => "SIGTRAP",
        6 => "SIGABRT",
        7 => "SIGBUS",
        8 => "SIGFPE",
        9 => "SIGKILL",
        10 => "SIGUSR1",
        11 => "SIGSEGV",
        12 => "SIGUSR2",
        13 => "SIGPIPE",
        14 => "SIGALRM",
        15 => "SIGTERM",
        16 => "SIGSTKFLT",
        17 => "SIGCHLD",
        18 => "SIGCONT",
        19 => "SIGSTOP",
        20 => "SIGTSTP",
        21 => "SIGTTIN",
        22 => "SIGTTOU",
        23 => "SIGURG",
        24 => "SIGXCPU",
        25 => "SIGXFSZ",
        26 => "SIGVTALRM",
        27 => "SIGPROF",
        28 => "SIGWINCH",
        29 => "SIGPOLL",
        30 => "SIGPWR",
        31 => "SIGSYS",
        _ => "(unknown)"
    }
}

pub fn exec<'a, T>(
    lang: Arc<ExecBackend>,
    timeout: Option<usize>,
    code: T) -> impl Future<Item = String, Error = String> + 'a
        where T: AsRef<[u8]> + 'a {
    let timeout_arg = format!("{}{}",
        lang.timeout_prefix.as_ref().map(String::as_str).unwrap_or(""),
        timeout.unwrap_or(0));
    if let Some(path) = lang.cmdline.iter().nth(0) {
        let mut cmd = Command::new(path);
        cmd.args(lang.cmdline.iter()
            .skip(1)
            .map(|a| if a == "{TIMEOUT}" {
                &timeout_arg
            } else {
                &a
            }))
            .stdin(Stdio::piped()).stdout(Stdio::piped()).stderr(Stdio::piped());
        debug!("spawning {:?}", cmd);
        Either::A(cmd.spawn_async()
            .map_err(|e| format!("failed to exec: {}", e))
            .into_future()
            .and_then(|mut child| {
                child.stdin().take().ok_or_else(|| "stdin missing".to_owned()).into_future()
                    .and_then(|stdin|
                        write_all(stdin, code)
                            .map_err(|e| format!("failed to write to stdin: {}", e))
                    )
                    .and_then(move |_| {
                        let stdout = match child.stdout().take() {
                            // FIXME configurable max
                            Some(io) => Either::A(helper::read_up_to(io, vec![0u8; 1024])
                                .map(|(_, mut v, s)| {
                                    v.truncate(s);
                                    v
                                })),
                            None => Either::B(Ok(Vec::new()).into_future()),
                        };
                        let stderr = match child.stderr().take() {
                            // FIXME configurable max
                            Some(io) => Either::A(helper::read_up_to(io, vec![0u8; 1024])
                                .map(|(_, mut v, s)| {
                                    v.truncate(s);
                                    v
                                })),
                            None => Either::B(Ok(Vec::new()).into_future()),
                        };
                        child.join3(stdout, stderr)
                    }.map_err(|e| format!("failed to wait for process: {}", e)))
            })
            .map_err(|e| format!("unknown error in exec: {}", e))
            .map(|(status, stdout, stderr)| {
                let mut r = format!("{}{}",
                    String::from_utf8_lossy(&stderr),
                    String::from_utf8_lossy(&stdout),
                );
                if !status.success() {
                    if !r.ends_with('\n') {
                        r.push_str("\n");
                    }
                    if let Some(code) = status.code() {
                        r.push_str(&format!("exited with status {}\n", code));
                    } else if let Some(code) = status.signal() {
                        r.push_str(&format!("signalled with {} ({})\n", strsig(code), strsigabbrev(code)));
                    } else {
                        r.push_str("exited with unknown failure\n");
                    }
                }
                r
            }))
    } else {
        Either::B(Err("empty cmdline".to_owned()).into_future())
    }
}

macro_rules! persistent {
    ($lang:expr, $connfut:expr, $timeout:expr, $buf:expr) => ({
        let buf = $buf;
        let fut = $connfut
            .map_err(|e| format!("error connecting: {}", e))
            .and_then(move |s| write_all(s, buf)
                .map_err(|e| format!("error writing: {}", e)))
            .and_then(|(s, _)| flush(s)
                .map_err(|e| format!("error flushing: {}", e)))
            .and_then(|s| read_exact(s, [0u8; 4])
                .map_err(|e| format!("error reading result length: {}", e)));
        if let Some(timeout) = $timeout {
            Either::A(fut.timeout(Duration::from_secs(timeout as u64)))
        } else {
            Either::B(fut.map_err(|e| timeout::Error::inner(e)))
        }.then(|r| match r {
            Ok((s, lenb)) => Either::A(read_exact(s, {
                // FIXME configurable max
                let outlen = Cursor::new(lenb).get_u32_le().min(1024) as usize;
                let mut buf = BytesMut::with_capacity(outlen);
                buf.resize(outlen, 0);
                buf
            }).map_err(|e| format!("error reading result: {}", e))
                .map(|(_, ref outb)| String::from_utf8_lossy(outb).into_owned())),
            Err(e) => Either::B(if e.is_elapsed() {
                Err("time limit exceeded".to_owned()).into_future()
            } else {
                Err(format!("error: {}", e)).into_future()
            })
        }).map_err(move |e| {
            do_persistent_timeout(&$lang.timeout_cmdline);
            e
        })
    });
}

pub fn unix<'a, T, U>(
    lang: Arc<UnixSocketBackend>,
    timeout: Option<usize>,
    context: Option<U>,
    code: T) -> impl Future<Item = String, Error = String> + 'a
        where
            T: AsRef<[u8]>,
            U: AsRef<[u8]> {
    persistent!(lang,
        UnixStream::connect(&lang.socket_addr),
        timeout,
        make_persistent_input(timeout, context, code))
}

fn do_persistent_timeout(cmdline: &Option<Vec<String>>) {
    if let Some(cmdline) = cmdline.as_ref() {
        if let Some(path) = cmdline.iter().nth(0) {
            debug!("timeout kill: launching {:?}", cmdline);
            tokio::spawn(Command::new(path)
                .args(cmdline.iter().skip(1))
                .spawn_async()
                .map_err(|e| error!("failed to exec for timeout kill: {}", e))
                .into_future()
                .and_then(|c| c
                    .map_err(|e| error!("failed to exec for timeout kill: {}", e)))
                    .map(|_| ()));
        }
    }
}

fn make_persistent_input<T, U>(timeout: Option<usize>, context: Option<T>, code: U) -> BytesMut
    where
        T: AsRef<[u8]>,
        U: AsRef<[u8]> {
    let timeout = timeout.unwrap_or(0usize) as u32;
    let contextb = context.as_ref().map(|x| x.as_ref()).unwrap_or(&super::EMPTY_U8);
    let codeb = code.as_ref();
    let contextblen = contextb.len() as u32;
    let codeblen = codeb.len() as u32;

    let mut buf = BytesMut::with_capacity(12usize + contextblen as usize + codeblen as usize);
    buf.put_u32_le(timeout*1000);
    buf.put_u32_le(contextblen);
    buf.put_u32_le(codeblen);
    buf.put(&contextb[..contextblen as usize]);
    buf.put(&codeb[..codeblen as usize]);
    buf
}

mod helper {
    // https://docs.rs/tokio-io/0.1.10/src/tokio_io/io/read_exact.rs.html

    use std::io;
    use std::mem;

    use futures::{Poll, Future};

    use tokio::io::AsyncRead;

    #[derive(Debug)]
    pub struct ReadUpTo<A, T> {
        state: State<A, T>,
    }

    #[derive(Debug)]
    enum State<A, T> {
        Reading {
            a: A,
            buf: T,
            pos: usize,
        },
        Empty,
    }

    pub fn read_up_to<A, T>(a: A, buf: T) -> ReadUpTo<A, T>
        where A: AsyncRead,
            T: AsMut<[u8]>,
    {
        ReadUpTo {
            state: State::Reading {
                a,
                buf,
                pos: 0,
            },
        }
    }

    impl<A, T> Future for ReadUpTo<A, T>
        where A: AsyncRead,
            T: AsMut<[u8]>,
    {
        type Item = (A, T, usize);
        type Error = io::Error;

        fn poll(&mut self) -> Poll<(A, T, usize), io::Error> {
            match self.state {
                State::Reading { ref mut a, ref mut buf, ref mut pos } => {
                    let buf = buf.as_mut();
                    while *pos < buf.len() {
                        let n = try_ready!(a.poll_read(&mut buf[*pos..]));
                        *pos += n;
                        if n == 0 {
                            break;
                        }
                    }
                }
                State::Empty => panic!("poll a ReadUpTo after it's done"),
            }

            match mem::replace(&mut self.state, State::Empty) {
                State::Reading { a, buf, pos } => Ok((a, buf, pos).into()),
                State::Empty => panic!(),
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate quick_xml;

use std::io::{BufRead};

use quick_xml::{XmlReader, Event, AsStr, Element};
use quick_xml::error::ResultPos;
use std::fmt;

#[test]
fn sample_1_short() {
    test(
        include_bytes!("documents/sample_1.xml"),
        include_bytes!("documents/sample_1_short.txt"),
        true
    );
}

// #[test]
// fn sample_1_full() {
//     test(
//         include_bytes!("documents/sample_1.xml"),
//         include_bytes!("documents/sample_1_full.txt"),
//         false
//     );
// }

#[test]
fn sample_2_short() {
    test(
        include_bytes!("documents/sample_2.xml"),
        include_bytes!("documents/sample_2_short.txt"),
        true
    );
}

// #[test]
// fn sample_2_full() {
//     test(
//         include_bytes!("documents/sample_2.xml"),
//         include_bytes!("documents/sample_2_full.txt"),
//         false
//     );
// }

// #[test]
// fn sample_3_short() {
//     test(
//         include_bytes!("documents/sample_3.xml"),
//         include_bytes!("documents/sample_3_short.txt"),
//         true
//     );
// }

// #[test]
// fn sample_3_full() {
//     test(
//         include_bytes!("documents/sample_3.xml"),
//         include_bytes!("documents/sample_3_full.txt"),
//         false
//     );
// }

// #[test]
// fn sample_4_short() {
//     test(
//         include_bytes!("documents/sample_4.xml"),
//         include_bytes!("documents/sample_4_short.txt"),
//         true
//     );
// }

// #[test]
// fn sample_4_full() {
//     test(
//         include_bytes!("documents/sample_4.xml"),
//         include_bytes!("documents/sample_4_full.txt"),
//         false
//     );
//
// }
//

#[test]
fn eof_1() {
    test(
        br#"<?xml"#,
        br#"Malformed xml: Unescaped XmlDecl event"#,
        true
    );
}

#[test]
fn bad_1() {
    test(
        br#"<?xml&.,"#,
        br#"1:6 Malformed xml: Unescaped XmlDecl event"#,
        true
    );
}

#[test]
fn dashes_in_comments() {
    test(
        br#"<hello/>"#,
        br#"
            |1:14 Malformed xml: Unexpected token '--'
        "#,
        false
    );

    test(
        br#"<hello/>"#,
        br#"
            |1:14 Malformed xml: Unexpected token '--'
        "#,
        true
    );
}

#[test]
fn tabs_1() {
    test(
        b"\t\t",
        br#"
            StartElement(a)
            StartElement(b)
            EndElement(b)
            EndElement(a)
            EndDocument
        "#,
        true
    );
}
//
// #[test]
// fn issue_83_duplicate_attributes() {
//     test(
//         br#"<hello><some-tag a='10' a="20"></hello>"#,
//         br#"
//             |StartElement(hello)
//             |1:30 Attribute 'a' is redefined
//         "#,
//         true
//     );
// }

#[test]
fn issue_93_large_characters_in_entity_references() {
    test(
        r#"<hello>&𤶼;</hello>"#.as_bytes(),
        r#"
            |StartElement(hello)
            |1:10 Malformed xml: Unexpected entity: 𤶼
            |EndElement(hello)
        "#.as_bytes(),
        true
    )
}

#[test]
fn issue_98_cdata_ending_with_right_bracket() {
    test(
        br#"<hello><![CDATA[Foo [Bar]]]></hello>"#,
        br#"
            |StartElement(hello)
            |Characters()
            |CData("Foo [Bar]")
            |Characters()
            |EndElement(hello)
            |EndDocument
        "#,
        false
    )
}

#[test]
fn issue_105_unexpected_double_dash() {
    test(
        br#"<hello>-- </hello>"#,
        br#"
            |StartElement(hello)
            |Characters("-- ")
            |EndElement(hello)
            |EndDocument
        "#,
        false
    );

    test(
        br#"<hello>--</hello>"#,
        br#"
            |StartElement(hello)
            |Characters("--")
            |EndElement(hello)
            |EndDocument
        "#,
        false
    );

    test(
        br#"<hello>--></hello>"#,
        br#"
            |StartElement(hello)
            |Characters("-->")
            |EndElement(hello)
            |EndDocument
        "#,
        false
    );

    test(
        br#"<hello><![CDATA[--]]></hello>"#,
        br#"
            |StartElement(hello)
            |Characters()
            |CData("--")
            |Characters()
            |EndElement(hello)
            |EndDocument
        "#,
        false
    );
}

// #[test]
// fn issue_attribues_have_no_default_namespace () {
//     test(
//         br#"<hello xmlns="urn:foo" x="y"/>"#,
//         br#"
//             |StartElement({urn:foo}hello [x="y"])
//             |EndElement({urn:foo}hello)
//             |EndDocument
//         "#,
//         true
//     );
// }

// clones a lot but that's fine
fn convert_to_quick_xml(s: &str) -> String {

    let mut s = match s.trim() {
        ts if ts.starts_with('|') => &ts[1..],
        s => s
    };

    if !s.is_empty() && s.as_bytes()[0] >= b'0' && s.as_bytes()[0] <= b'9' {
        let p = s.chars().position(|c| c == ' ').unwrap();
        s = &s[(p + 1) ..];
    }

    if s.starts_with("Whitespace") {
        format!("Character{}", s)
    } else {
        s.to_owned()
    }
}

fn test(input: &[u8], output: &[u8], is_short: bool) {

    let mut reader = XmlReader::from_reader(input)
        .trim_text(is_short)
        .check_comments(true)
        .namespaced();

    let mut spec_lines = output.lines()
        .map(|line| line.unwrap())
        .enumerate()
        .map(|(i, line)| (i, convert_to_quick_xml(&line)))
        .filter(|&(_, ref line)| !line.trim().is_empty());

    if !is_short {
        reader.next();
    }

    loop {
        let e = reader.next();

        let line = format!("{}", OptEvent(e));

        if let Some((n, spec)) = spec_lines.next() {
            if line != spec {
                const SPLITTER: &'static str = "-------------------";
                panic!("\n{}\nUnexpected event at line {}:\nExpected: {}\nFound:    {}\n{}\n",
                       SPLITTER, n + 1, spec, line, SPLITTER);
            }
        } else {
            if line == "EndDocument" {
                break;
            }
            panic!("Unexpected event: {}", line);
        }
    }
}

fn namespace_name(n: &Option<Vec<u8>>, e: &Element) -> String {
    match n {
        &Some(ref n) =>
            format!("{{{}}}{}", n.as_str().unwrap(), e.name().as_str().unwrap()),
        &None => e.name().as_str().unwrap().to_owned(),
    }
}

struct OptEvent(Option<ResultPos<(Option<Vec<u8>>, Event)>>);

impl fmt::Display for OptEvent {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.0 {
            Some(Ok((ref n, Event::Start(ref e)))) => {
                let atts: String = e.attributes().unescaped().map(|a| a.unwrap())
                    .filter(|&(k, _)| k.len() < 5 || &k[..5] != b"xmlns")
                    .map(|(k, v)| format!("{}={:?}", k.as_str().unwrap(), v.as_str().unwrap()))
                    .collect::<Vec<_>>().join(", ");

                let name = namespace_name(n, e);

                if atts.is_empty() {
                    write!(f, "StartElement({})", &name)
                } else {
                    write!(f, "StartElement({} [{}])", &name, &atts)
                }
            },
            Some(Ok((ref n, Event::End(ref e)))) =>
                write!(f, "EndElement({})", namespace_name(n, e)),
            Some(Ok((_, Event::Comment(ref e)))) =>
                write!(f, "Comment({:?})", e.content().as_str().unwrap()),
            Some(Ok((_, Event::CData(ref e)))) =>
                write!(f, "CData({:?})", e.content().as_str().unwrap()),
            Some(Ok((_, Event::Text(ref e)))) => {
                match e.unescaped_content() {
                    Ok(c) => {
                        if c.is_empty() {
                            write!(f, "Characters()")
                        } else {
                            write!(f, "Characters({:?})", c.as_str().unwrap())
                        }
                    },
                    Err((ref e, _)) => write!(f, "{}", e),
                }
            },
            Some(Ok((_, Event::Decl(ref e)))) => {
                let version = e.version().unwrap().as_str().unwrap();
                let encoding = e.encoding().unwrap().unwrap().as_str().unwrap();
                write!(f, "StartDocument({}, {})", version, encoding)
            },
            None => write!(f, "EndDocument"),
            Some(Ok((_, Event::PI(ref e)))) =>
                write!(f, "ProcessingInstruction({}={:?})",
                    e.name().as_str().unwrap(), e.content().as_str().unwrap()),
            Some(Err((ref e, _))) => write!(f, "{}", e),
            Some(Ok((_, Event::DocType(ref e)))) =>
                write!(f, "DocType({})", e.content().as_str().unwrap()),
        }
    }
}
<commit_msg>make 1_full and 2_full work<commit_after>extern crate quick_xml;

use std::io::{BufRead};

use quick_xml::{XmlReader, Event, AsStr, Element};
use quick_xml::error::ResultPos;
use std::fmt;

#[test]
fn sample_1_short() {
    test(
        include_bytes!("documents/sample_1.xml"),
        include_bytes!("documents/sample_1_short.txt"),
        true
    );
}

#[test]
fn sample_1_full() {
    test(
        include_bytes!("documents/sample_1.xml"),
        include_bytes!("documents/sample_1_full.txt"),
        false
    );
}

#[test]
fn sample_2_short() {
    test(
        include_bytes!("documents/sample_2.xml"),
        include_bytes!("documents/sample_2_short.txt"),
        true
    );
}

#[test]
fn sample_2_full() {
    test(
        include_bytes!("documents/sample_2.xml"),
        include_bytes!("documents/sample_2_full.txt"),
        false
    );
}

// #[test]
// fn sample_3_short() {
//     test(
//         include_bytes!("documents/sample_3.xml"),
//         include_bytes!("documents/sample_3_short.txt"),
//         true
//     );
// }

// #[test]
// fn sample_3_full() {
//     test(
//         include_bytes!("documents/sample_3.xml"),
//         include_bytes!("documents/sample_3_full.txt"),
//         false
//     );
// }

// #[test]
// fn sample_4_short() {
//     test(
//         include_bytes!("documents/sample_4.xml"),
//         include_bytes!("documents/sample_4_short.txt"),
//         true
//     );
// }

// #[test]
// fn sample_4_full() {
//     test(
//         include_bytes!("documents/sample_4.xml"),
//         include_bytes!("documents/sample_4_full.txt"),
//         false
//     );
//
// }
//

#[test]
fn eof_1() {
    test(
        br#"<?xml"#,
        br#"Malformed xml: Unescaped XmlDecl event"#,
        true
    );
}

#[test]
fn bad_1() {
    test(
        br#"<?xml&.,"#,
        br#"1:6 Malformed xml: Unescaped XmlDecl event"#,
        true
    );
}

#[test]
fn dashes_in_comments() {
    test(
        br#"<hello/>"#,
        br#"
            |1:14 Malformed xml: Unexpected token '--'
        "#,
        false
    );

    test(
        br#"<hello/>"#,
        br#"
            |1:14 Malformed xml: Unexpected token '--'
        "#,
        true
    );
}

#[test]
fn tabs_1() {
    test(
        b"\t\t",
        br#"
            StartElement(a)
            StartElement(b)
            EndElement(b)
            EndElement(a)
            EndDocument
        "#,
        true
    );
}
//
// #[test]
// fn issue_83_duplicate_attributes() {
//     test(
//         br#"<hello><some-tag a='10' a="20"></hello>"#,
//         br#"
//             |StartElement(hello)
//             |1:30 Attribute 'a' is redefined
//         "#,
//         true
//     );
// }

#[test]
fn issue_93_large_characters_in_entity_references() {
    test(
        r#"<hello>&𤶼;</hello>"#.as_bytes(),
        r#"
            |StartElement(hello)
            |1:10 Malformed xml: Unexpected entity: 𤶼
            |EndElement(hello)
        "#.as_bytes(),
        true
    )
}

#[test]
fn issue_98_cdata_ending_with_right_bracket() {
    test(
        br#"<hello><![CDATA[Foo [Bar]]]></hello>"#,
        br#"
            |StartElement(hello)
            |Characters()
            |CData("Foo [Bar]")
            |Characters()
            |EndElement(hello)
            |EndDocument
        "#,
        false
    )
}

#[test]
fn issue_105_unexpected_double_dash() {
    test(
        br#"<hello>-- </hello>"#,
        br#"
            |StartElement(hello)
            |Characters("-- ")
            |EndElement(hello)
            |EndDocument
        "#,
        false
    );

    test(
        br#"<hello>--</hello>"#,
        br#"
            |StartElement(hello)
            |Characters("--")
            |EndElement(hello)
            |EndDocument
        "#,
        false
    );

    test(
        br#"<hello>--></hello>"#,
        br#"
            |StartElement(hello)
            |Characters("-->")
            |EndElement(hello)
            |EndDocument
        "#,
        false
    );

    test(
        br#"<hello><![CDATA[--]]></hello>"#,
        br#"
            |StartElement(hello)
            |Characters()
            |CData("--")
            |Characters()
            |EndElement(hello)
            |EndDocument
        "#,
        false
    );
}

// #[test]
// fn issue_attribues_have_no_default_namespace () {
//     test(
//         br#"<hello xmlns="urn:foo" x="y"/>"#,
//         br#"
//             |StartElement({urn:foo}hello [x="y"])
//             |EndElement({urn:foo}hello)
//             |EndDocument
//         "#,
//         true
//     );
// }

// clones a lot but that's fine
fn convert_to_quick_xml(s: &str) -> String {

    let mut s = match s.trim() {
        ts if ts.starts_with('|') => &ts[1..],
        s => s
    };

    if !s.is_empty() && s.as_bytes()[0] >= b'0' && s.as_bytes()[0] <= b'9' {
        let p = s.chars().position(|c| c == ' ').unwrap();
        s = &s[(p + 1) ..];
    }

    if s.starts_with("Whitespace") {
        format!("Characters{}", &s[10..])
    } else {
        s.to_owned()
    }
}

fn test(input: &[u8], output: &[u8], is_short: bool) {

    let mut reader = XmlReader::from_reader(input)
        .trim_text(is_short)
        .check_comments(true)
        .namespaced();

    let mut spec_lines = output.lines()
        .map(|line| line.unwrap())
        .enumerate()
        .map(|(i, line)| (i, convert_to_quick_xml(&line)))
        .filter(|&(_, ref line)| !line.trim().is_empty());

    if !is_short {
        reader.next();
    }

    loop {
        let e = reader.next();

        let line = format!("{}", OptEvent(e));

        if let Some((n, spec)) = spec_lines.next() {
            if spec == "EndDocument" {
                break;
            }
            if line != spec {
                const SPLITTER: &'static str = "-------------------";
                panic!("\n{}\nUnexpected event at line {}:\nExpected: {}\nFound:    {}\n{}\n",
                       SPLITTER, n + 1, spec, line, SPLITTER);
            }
        } else {
            if line == "EndDocument" {
                break;
            }
            panic!("Unexpected event: {}", line);
        }

        if !is_short && line.starts_with("StartDocument") {
            // advance next Characters(empty space) ...
            if let Some(Ok((_, Event::Text(ref e)))) = reader.next() {
                if e.content().iter().any(|b| match *b {
                    b' ' | b'\r' | b'\n' | b'\t' => false,
                    _ => true,
                }) {
                    panic!("XmlReader expects empty Text event after a StartDocument");
                }
            } else {
                panic!("XmlReader expects empty Text event after a StartDocument");
            }
        }
    }
}

fn namespace_name(n: &Option<Vec<u8>>, e: &Element) -> String {
    match n {
        &Some(ref n) =>
            format!("{{{}}}{}", n.as_str().unwrap(), e.name().as_str().unwrap()),
        &None => e.name().as_str().unwrap().to_owned(),
    }
}

struct OptEvent(Option<ResultPos<(Option<Vec<u8>>, Event)>>);

impl fmt::Display for OptEvent {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.0 {
            Some(Ok((ref n, Event::Start(ref e)))) => {
                let atts: String = e.attributes().unescaped().map(|a| a.unwrap())
                    .filter(|&(k, _)| k.len() < 5 || &k[..5] != b"xmlns")
                    .map(|(k, v)| format!("{}={:?}", k.as_str().unwrap(), v.as_str().unwrap()))
                    .collect::<Vec<_>>().join(", ");

                let name = namespace_name(n, e);

                if atts.is_empty() {
                    write!(f, "StartElement({})", &name)
                } else {
                    write!(f, "StartElement({} [{}])", &name, &atts)
                }
            },
            Some(Ok((ref n, Event::End(ref e)))) =>
                write!(f, "EndElement({})", namespace_name(n, e)),
            Some(Ok((_, Event::Comment(ref e)))) =>
                write!(f, "Comment({:?})", e.content().as_str().unwrap()),
            Some(Ok((_, Event::CData(ref e)))) =>
                write!(f, "CData({:?})", e.content().as_str().unwrap()),
            Some(Ok((_, Event::Text(ref e)))) => {
                match e.unescaped_content() {
                    Ok(c) => {
                        if c.is_empty() {
                            write!(f, "Characters()")
                        } else {
                            write!(f, "Characters({:?})", c.as_str().unwrap())
                        }
                    },
                    Err((ref e, _)) => write!(f, "{}", e),
                }
            },
            Some(Ok((_, Event::Decl(ref e)))) => {
                let version = e.version().unwrap().as_str().unwrap();
                let encoding = e.encoding().unwrap().unwrap().as_str().unwrap();
                write!(f, "StartDocument({}, {})", version, encoding)
            },
            None => write!(f, "EndDocument"),
            Some(Ok((_, Event::PI(ref e)))) =>
                write!(f, "ProcessingInstruction({}={:?})",
                    e.name().as_str().unwrap(), e.content().as_str().unwrap()),
            Some(Err((ref e, _))) => write!(f, "{}", e),
            Some(Ok((_, Event::DocType(ref e)))) =>
                write!(f, "DocType({})", e.content().as_str().unwrap()),
        }
    }
}
<|endoftext|>


<commit_before>use std::io::{Write,Result};
use std::str;

pub struct FauxStdout {
    buffer: String
}

impl Write for FauxStdout {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        match str::from_utf8(buf) {
            Err(e) => panic!(e),
            Ok(s) => {
                self.buffer += s;
                return Ok(s.len());
            }
        }
    }

    fn flush(&mut self) -> Result<()> {
        Ok(())
    }
}
<commit_msg>Add FauxStdout::new() fn<commit_after>use std::io::{Write,Result};
use std::str;

pub struct FauxStdout {
    buffer: String
}

impl FauxStdout {
    pub fn new() -> FauxStdout {
        FauxStdout { buffer: String::new() }
    }
}

impl Write for FauxStdout {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        match str::from_utf8(buf) {
            Err(e) => panic!(e),
            Ok(s) => {
                self.buffer += s;
                return Ok(s.len());
            }
        }
    }

    fn flush(&mut self) -> Result<()> {
        Ok(())
    }
}
<|endoftext|>


<commit_before>use utils::{
    execute,
    fetch_updates,
    with_slot,
};

#[test]
// The output decoder does not emit any changes for deletions from a table without a primary key.
// This is because Postgres doesn't give the decoder any tuple information in this scenario.
fn delete_without_primary_key() {
    with_slot("no_primary_table", "id int, name text, whatever float", |c| {
        execute(c, "insert into no_primary_table (id, name, whatever) values ($1, $2, $3)", &[&1, &"hello", &3.2]);
        execute(c, "delete from no_primary_table where id = 1", &[]);
        assert_eq!(fetch_updates(c).len(), 1);
    });
}
<commit_msg>Adds tests for a bunch of data types<commit_after>use utils::{
    execute,
    fetch_updates,
    with_slot,
};

use rustc_serialize::json::{as_pretty_json};

#[test]
// The output decoder does not emit any changes for deletions from a table without a primary key.
// This is because Postgres doesn't give the decoder any tuple information in this scenario.
fn delete_without_primary_key() {
    with_slot("no_primary_table", "id int, name text, whatever float", |c| {
        execute(c, "insert into no_primary_table (id, name, whatever) values ($1, $2, $3)", &[&1, &"hello", &3.2]);
        execute(c, "delete from no_primary_table where id = 1", &[]);
        assert_eq!(fetch_updates(c).len(), 1);
    });
}

// TODO: Add these all to the test
// -------------------------------
// date
// double precision
// inet
// integer
// interval [ fields ] [ (p) ]
// json
// jsonb
// line
// lseg
// macaddr
// money
// numeric [ (p, s) ]
// path
// pg_lsn
// point
// polygon
// real
// text
// time [ (p) ] [ without time zone ]
// time [ (p) ] with time zone
// timestamp [ (p) ] [ without time zone ]
// timestamp [ (p) ] with time zone
// tsquery
// tsvector
// txid_snapshot
// uuid
// xml
#[test]
fn works_with_all_datatypes() {
    let columns = "                        \
        id              int primary key,   \
        abool           boolean,           \
        anint           int,               \
        abigint         bigint,            \
        asmallint       smallint,          \
        aserialnint     serial,            \
        aserialbigint   bigserial,         \
        aserialsmallint smallserial,       \
        somebits        BIT(3),            \
        somemorebits    bit varying,       \
        abox            box,               \
        somebytes       bytea,             \
        somechars       character(3),      \
        morechars       character varying, \
        addr            cidr,              \
        circ            circle
    ";

    let values = "             \
        1,                     \
        true,                  \
        1,                     \
        1,                     \
        1,                     \
        1,                     \
        1,                     \
        1,                     \
        B'101',                \
        B'101',                \
        '((0,0),(1,1))',       \
        E'\x0123456789ABCDEF', \
        'abc',                 \
        'abcdef',              \
        '192.168.100.128/25',  \
        '((0,0), 1)'           \
    ";

    with_slot("datatypes", columns, |c| {
        execute(c, &format!("insert into datatypes values ({})", values)[..], &[]);
        println!("{}", as_pretty_json(&fetch_updates(c)));
        assert_eq!(fetch_updates(c).len(), 1);
    });
}
<|endoftext|>


<commit_before>//! Frame parsers and data handlers
//!
//! Parse various frame types and return a fully-constructed object. See individual functions for
//! their descriptions.

use structs::{Frame, Callsign, InformationField};
use constants;
use util;

pub fn parse_frame(raw_frame: &[u8]) -> Frame {
    for win in raw_frame.windows(2) {
        if win == constants::ADDR_INFO_DELIM {
            return parse_frame_ax25(raw_frame);
        }
    }
    parse_frame_text(raw_frame)
}

pub fn parse_frame_text(raw_frame: &[u8]) -> Frame {
    // src>dest[,path]:info
    let src_dest:  usize = raw_frame.iter().position(|x| *x == b'>').unwrap();
    let path_info: usize = raw_frame.iter().position(|x| *x == b':').unwrap();

    let source: Callsign = parse_callsign_text(&raw_frame[..src_dest]);
    let mut dest: Callsign = Callsign::new();
    let info: InformationField = parse_info_field(&raw_frame[(path_info + 1)..]);

    // Full path slice
    let mut _path: Vec<Callsign> = Vec::new();
    let _paths: &[u8] = &raw_frame[src_dest + 1..path_info];
    for (ind, path) in _paths.split(|x| *x == b',').enumerate() {
        if ind == 0 {
            dest = parse_callsign_text(path);
        } else {
            _path.push(parse_callsign_text(path));
        }
    }
    Frame {
        source: source,
        destination: dest,
        path: _path,
        info: info
    }
}

pub fn parse_frame_ax25(raw_frame: &[u8]) -> Frame {
    let parsed_frame: Frame = Frame::new();
    parsed_frame
}

pub fn parse_callsign(raw_callsign: &[u8]) -> Callsign {
    parse_callsign_text(raw_callsign)
}

pub fn parse_callsign_text(raw_callsign: &[u8]) -> Callsign {
    let mut _callsign: String = String::from_utf8(raw_callsign.to_vec()).unwrap();
    let mut ssid: u8 = 0;
    let mut digi: bool = false;

    if _callsign.contains('*') {
        _callsign.trim_matches('*');
        digi = true;
    }
    let pos: Option<usize> = _callsign.find('-');
    match pos {
        Some(x) => {
            _callsign = {
                let (call, id): (&str, &str) = _callsign.split_at(x);
                ssid = id[1..].parse::<u8>().unwrap();
                call.to_string()
            };
        },
        None => {}
    }
    Callsign {
        callsign: _callsign,
        ssid: ssid,
        digi: digi
    }
}

pub fn parse_callsign_ax25(raw_callsign: &[u8], kiss_call: bool) -> Callsign {
    Callsign::new()
}

pub fn parse_info_field(raw_data: &[u8]) -> InformationField {
    // TODO: use char to get map entry
    let first_byte: &u8 = raw_data.first().unwrap();
    let data_type: String = constants::DATA_TYPE_MAP.get(first_byte).unwrap().to_string();
    InformationField {
        data: raw_data.to_vec(),
        data_type,
        safe: true
    }
}

pub fn default_data_handler(data: &[u8], data_type: &str) -> String {
    String::new()
}
<commit_msg>parse_frame_ax25<commit_after>//! Frame parsers and data handlers
//!
//! Parse various frame types and return a fully-constructed object. See individual functions for
//! their descriptions.

use structs::{Frame, Callsign, InformationField};
use constants;
use util;

pub fn parse_frame(raw_frame: &[u8]) -> Frame {
    for win in raw_frame.windows(2) {
        if win == constants::ADDR_INFO_DELIM {
            return parse_frame_ax25(raw_frame);
        }
    }
    parse_frame_text(raw_frame)
}

pub fn parse_frame_text(raw_frame: &[u8]) -> Frame {
    // src>dest[,path]:info
    let src_dest:  usize = raw_frame.iter().position(|x| *x == b'>').unwrap();
    let path_info: usize = raw_frame.iter().position(|x| *x == b':').unwrap();

    let source: Callsign = parse_callsign_text(&raw_frame[..src_dest]);
    let mut dest: Callsign = Callsign::new();
    let info: InformationField = parse_info_field(&raw_frame[(path_info + 1)..]);

    // Full path slice
    let mut _path: Vec<Callsign> = Vec::new();
    let _paths: &[u8] = &raw_frame[src_dest + 1..path_info];
    for (ind, path) in _paths.split(|x| *x == b',').enumerate() {
        if ind == 0 {
            dest = parse_callsign_text(path);
        } else {
            _path.push(parse_callsign_text(path));
        }
    }
    Frame {
        source: source,
        destination: dest,
        path: _path,
        info: info
    }
}

pub fn parse_frame_ax25(raw_frame: &[u8]) -> Frame {
    let mut _frame: &[u8] = raw_frame;
    let mut kiss_call: bool = false;

    if _frame.starts_with(&[constants::KISS_DATA_FRAME]) {
        let mut ind: usize = 0;
        for (id, byt) in _frame.iter().enumerate() {
            if byt == &constants::KISS_DATA_FRAME {
                continue;
            } else {
                ind = id;
                break;
            }
        }
        _frame = &_frame[ind..];
        kiss_call = true;
    }
    if _frame.ends_with(&[constants::KISS_DATA_FRAME]) {
        let mut ind: usize = 0;
        for (id, byt) in _frame.iter().rev().enumerate() {
            if byt == &constants::KISS_DATA_FRAME {
                continue;
            } else {
                ind = id;
                break;
            }
        }
        _frame = &_frame[..(_frame.len() - ind)];
        kiss_call = true;
    }

    let mut info_pos: usize = 0;
    for win in _frame.windows(2) {
        if win == constants::ADDR_INFO_DELIM {
            break;
        }
        info_pos += 1;
    }
    let (frame_addressing, _) = _frame.split_at(info_pos);
    let (_, mut info_field)   = _frame.split_at(info_pos + 2);
    if info_field.ends_with(&[0xff, 0x07]) {
        info_field = &info_field[..(info_field.len() - 2)];
    }
    let dest: Callsign = parse_callsign_ax25(&frame_addressing, kiss_call);
    let src: Callsign = parse_callsign_ax25(&frame_addressing[7..], kiss_call);

    let mut path: Vec<Callsign> = Vec::new();
    for chunk in frame_addressing[14..].chunks(7) {
        path.push(parse_callsign_ax25(chunk, false));
    }

    Frame {
        source: src,
        destination: dest,
        path: path,
        info: parse_info_field(info_field),
    }
}

pub fn parse_callsign(raw_callsign: &[u8]) -> Callsign {
    parse_callsign_text(raw_callsign)
}

pub fn parse_callsign_text(raw_callsign: &[u8]) -> Callsign {
    let mut _callsign: String = String::from_utf8(raw_callsign.to_vec()).unwrap();
    let mut ssid: u8 = 0;
    let mut digi: bool = false;

    if _callsign.contains('*') {
        _callsign.trim_matches('*');
        digi = true;
    }
    let pos: Option<usize> = _callsign.find('-');
    match pos {
        Some(x) => {
            _callsign = {
                let (call, id): (&str, &str) = _callsign.split_at(x);
                ssid = id[1..].parse::<u8>().unwrap();
                call.to_string()
            };
        },
        None => {}
    }
    Callsign {
        callsign: _callsign,
        ssid: ssid,
        digi: digi
    }
}

pub fn parse_callsign_ax25(raw_callsign: &[u8], kiss_call: bool) -> Callsign {
    Callsign::new()
}

pub fn parse_info_field(raw_data: &[u8]) -> InformationField {
    let first_byte: &u8 = raw_data.first().unwrap();
    let data_type: String = constants::DATA_TYPE_MAP.get(first_byte).unwrap().to_string();
    InformationField {
        data: raw_data.to_vec(),
        data_type: data_type,
        safe: true
    }
}

pub fn default_data_handler(data: &[u8], data_type: &str) -> String {
    String::new()
}
<|endoftext|>


<commit_before>//! Partitions a list of files into disjoint subsets.
//!
//! Files which do not belong to any explicitly configured `FileSet` belong to
//! the default `FileSet`.
use std::fmt;

use fst::{IntoStreamer, Streamer};
use rustc_hash::FxHashMap;

use crate::{FileId, Vfs, VfsPath};

#[derive(Default, Clone, Eq, PartialEq)]
pub struct FileSet {
    files: FxHashMap<VfsPath, FileId>,
    paths: FxHashMap<FileId, VfsPath>,
}

impl FileSet {
    pub fn len(&self) -> usize {
        self.files.len()
    }
    pub fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
        let mut base = self.paths[&anchor].clone();
        base.pop();
        let path = base.join(path)?;
        let res = self.files.get(&path).copied();
        res
    }
    pub fn insert(&mut self, file_id: FileId, path: VfsPath) {
        self.files.insert(path.clone(), file_id);
        self.paths.insert(file_id, path);
    }
    pub fn iter(&self) -> impl Iterator<Item = FileId> + '_ {
        self.paths.keys().copied()
    }
}

impl fmt::Debug for FileSet {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("FileSet").field("n_files", &self.files.len()).finish()
    }
}

#[derive(Debug)]
pub struct FileSetConfig {
    n_file_sets: usize,
    map: fst::Map<Vec<u8>>,
}

impl Default for FileSetConfig {
    fn default() -> Self {
        FileSetConfig::builder().build()
    }
}

impl FileSetConfig {
    pub fn builder() -> FileSetConfigBuilder {
        FileSetConfigBuilder::default()
    }
    pub fn partition(&self, vfs: &Vfs) -> Vec<FileSet> {
        let mut scratch_space = Vec::new();
        let mut res = vec![FileSet::default(); self.len()];
        for (file_id, path) in vfs.iter() {
            let root = self.classify(&path, &mut scratch_space);
            res[root].insert(file_id, path.clone())
        }
        res
    }
    fn len(&self) -> usize {
        self.n_file_sets
    }
    fn classify(&self, path: &VfsPath, scratch_space: &mut Vec<u8>) -> usize {
        scratch_space.clear();
        path.encode(scratch_space);
        let automaton = PrefixOf::new(scratch_space.as_slice());
        let mut longest_prefix = self.len() - 1;
        let mut stream = self.map.search(automaton).into_stream();
        while let Some((_, v)) = stream.next() {
            longest_prefix = v as usize;
        }
        longest_prefix
    }
}

pub struct FileSetConfigBuilder {
    roots: Vec<Vec<VfsPath>>,
}

impl Default for FileSetConfigBuilder {
    fn default() -> Self {
        FileSetConfigBuilder { roots: Vec::new() }
    }
}

impl FileSetConfigBuilder {
    pub fn len(&self) -> usize {
        self.roots.len()
    }
    pub fn add_file_set(&mut self, roots: Vec<VfsPath>) {
        self.roots.push(roots)
    }
    pub fn build(self) -> FileSetConfig {
        let n_file_sets = self.roots.len() + 1;
        let map = {
            let mut entries = Vec::new();
            for (i, paths) in self.roots.into_iter().enumerate() {
                for p in paths {
                    let mut buf = Vec::new();
                    p.encode(&mut buf);
                    entries.push((buf, i as u64));
                }
            }
            entries.sort();
            entries.dedup_by(|(a, _), (b, _)| a == b);
            fst::Map::from_iter(entries).unwrap()
        };
        FileSetConfig { n_file_sets, map }
    }
}

struct PrefixOf<'a> {
    prefix_of: &'a [u8],
}

impl<'a> PrefixOf<'a> {
    fn new(prefix_of: &'a [u8]) -> Self {
        Self { prefix_of }
    }
}

impl fst::Automaton for PrefixOf<'_> {
    type State = usize;
    fn start(&self) -> usize {
        0
    }
    fn is_match(&self, &state: &usize) -> bool {
        state != !0
    }
    fn can_match(&self, &state: &usize) -> bool {
        state != !0
    }
    fn accept(&self, &state: &usize, byte: u8) -> usize {
        if self.prefix_of.get(state) == Some(&byte) {
            state + 1
        } else {
            !0
        }
    }
}

#[test]
fn test_partitioning() {
    let mut file_set = FileSetConfig::builder();
    file_set.add_file_set(vec![VfsPath::new_virtual_path("/foo".into())]);
    file_set.add_file_set(vec![VfsPath::new_virtual_path("/foo/bar/baz".into())]);
    let file_set = file_set.build();

    let mut vfs = Vfs::default();
    vfs.set_file_contents(VfsPath::new_virtual_path("/foo/src/lib.rs".into()), Some(Vec::new()));
    vfs.set_file_contents(
        VfsPath::new_virtual_path("/foo/src/bar/baz/lib.rs".into()),
        Some(Vec::new()),
    );
    vfs.set_file_contents(
        VfsPath::new_virtual_path("/foo/bar/baz/lib.rs".into()),
        Some(Vec::new()),
    );
    vfs.set_file_contents(VfsPath::new_virtual_path("/quux/lib.rs".into()), Some(Vec::new()));

    let partition = file_set.partition(&vfs).into_iter().map(|it| it.len()).collect::<Vec<_>>();
    assert_eq!(partition, vec![2, 1, 1]);
}
<commit_msg>Add one more test<commit_after>//! Partitions a list of files into disjoint subsets.
//!
//! Files which do not belong to any explicitly configured `FileSet` belong to
//! the default `FileSet`.
use std::fmt;

use fst::{IntoStreamer, Streamer};
use rustc_hash::FxHashMap;

use crate::{FileId, Vfs, VfsPath};

#[derive(Default, Clone, Eq, PartialEq)]
pub struct FileSet {
    files: FxHashMap<VfsPath, FileId>,
    paths: FxHashMap<FileId, VfsPath>,
}

impl FileSet {
    pub fn len(&self) -> usize {
        self.files.len()
    }
    pub fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
        let mut base = self.paths[&anchor].clone();
        base.pop();
        let path = base.join(path)?;
        let res = self.files.get(&path).copied();
        res
    }
    pub fn insert(&mut self, file_id: FileId, path: VfsPath) {
        self.files.insert(path.clone(), file_id);
        self.paths.insert(file_id, path);
    }
    pub fn iter(&self) -> impl Iterator<Item = FileId> + '_ {
        self.paths.keys().copied()
    }
}

impl fmt::Debug for FileSet {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("FileSet").field("n_files", &self.files.len()).finish()
    }
}

#[derive(Debug)]
pub struct FileSetConfig {
    n_file_sets: usize,
    map: fst::Map<Vec<u8>>,
}

impl Default for FileSetConfig {
    fn default() -> Self {
        FileSetConfig::builder().build()
    }
}

impl FileSetConfig {
    pub fn builder() -> FileSetConfigBuilder {
        FileSetConfigBuilder::default()
    }
    pub fn partition(&self, vfs: &Vfs) -> Vec<FileSet> {
        let mut scratch_space = Vec::new();
        let mut res = vec![FileSet::default(); self.len()];
        for (file_id, path) in vfs.iter() {
            let root = self.classify(&path, &mut scratch_space);
            res[root].insert(file_id, path.clone())
        }
        res
    }
    fn len(&self) -> usize {
        self.n_file_sets
    }
    fn classify(&self, path: &VfsPath, scratch_space: &mut Vec<u8>) -> usize {
        scratch_space.clear();
        path.encode(scratch_space);
        let automaton = PrefixOf::new(scratch_space.as_slice());
        let mut longest_prefix = self.len() - 1;
        let mut stream = self.map.search(automaton).into_stream();
        while let Some((_, v)) = stream.next() {
            longest_prefix = v as usize;
        }
        longest_prefix
    }
}

pub struct FileSetConfigBuilder {
    roots: Vec<Vec<VfsPath>>,
}

impl Default for FileSetConfigBuilder {
    fn default() -> Self {
        FileSetConfigBuilder { roots: Vec::new() }
    }
}

impl FileSetConfigBuilder {
    pub fn len(&self) -> usize {
        self.roots.len()
    }
    pub fn add_file_set(&mut self, roots: Vec<VfsPath>) {
        self.roots.push(roots)
    }
    pub fn build(self) -> FileSetConfig {
        let n_file_sets = self.roots.len() + 1;
        let map = {
            let mut entries = Vec::new();
            for (i, paths) in self.roots.into_iter().enumerate() {
                for p in paths {
                    let mut buf = Vec::new();
                    p.encode(&mut buf);
                    entries.push((buf, i as u64));
                }
            }
            entries.sort();
            entries.dedup_by(|(a, _), (b, _)| a == b);
            fst::Map::from_iter(entries).unwrap()
        };
        FileSetConfig { n_file_sets, map }
    }
}

struct PrefixOf<'a> {
    prefix_of: &'a [u8],
}

impl<'a> PrefixOf<'a> {
    fn new(prefix_of: &'a [u8]) -> Self {
        Self { prefix_of }
    }
}

impl fst::Automaton for PrefixOf<'_> {
    type State = usize;
    fn start(&self) -> usize {
        0
    }
    fn is_match(&self, &state: &usize) -> bool {
        state != !0
    }
    fn can_match(&self, &state: &usize) -> bool {
        state != !0
    }
    fn accept(&self, &state: &usize, byte: u8) -> usize {
        if self.prefix_of.get(state) == Some(&byte) {
            state + 1
        } else {
            !0
        }
    }
}

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

    #[test]
    fn path_prefix() {
        let mut file_set = FileSetConfig::builder();
        file_set.add_file_set(vec![VfsPath::new_virtual_path("/foo".into())]);
        file_set.add_file_set(vec![VfsPath::new_virtual_path("/foo/bar/baz".into())]);
        let file_set = file_set.build();

        let mut vfs = Vfs::default();
        vfs.set_file_contents(
            VfsPath::new_virtual_path("/foo/src/lib.rs".into()),
            Some(Vec::new()),
        );
        vfs.set_file_contents(
            VfsPath::new_virtual_path("/foo/src/bar/baz/lib.rs".into()),
            Some(Vec::new()),
        );
        vfs.set_file_contents(
            VfsPath::new_virtual_path("/foo/bar/baz/lib.rs".into()),
            Some(Vec::new()),
        );
        vfs.set_file_contents(VfsPath::new_virtual_path("/quux/lib.rs".into()), Some(Vec::new()));

        let partition = file_set.partition(&vfs).into_iter().map(|it| it.len()).collect::<Vec<_>>();
        assert_eq!(partition, vec![2, 1, 1]);
    }

    #[test]
    fn name_prefix() {
        let mut file_set = FileSetConfig::builder();
        file_set.add_file_set(vec![VfsPath::new_virtual_path("/foo".into())]);
        file_set.add_file_set(vec![VfsPath::new_virtual_path("/foo-things".into())]);
        let file_set = file_set.build();

        let mut vfs = Vfs::default();
        vfs.set_file_contents(
            VfsPath::new_virtual_path("/foo/src/lib.rs".into()),
            Some(Vec::new()),
        );
        vfs.set_file_contents(
            VfsPath::new_virtual_path("/foo-things/src/lib.rs".into()),
            Some(Vec::new()),
        );

        let partition = file_set.partition(&vfs).into_iter().map(|it| it.len()).collect::<Vec<_>>();
        assert_eq!(partition, vec![1, 1, 0]);
    }
}
<|endoftext|>