<commit_before>use term::Term;
use expression::Expression;
use production::Production;
use grammar::Grammar;

named!(pub prod_lhs< &[u8], Term >,
    do_parse!(
            nt: delimited!(char!('<'), take_until!(">"), ws!(char!('>'))) >>
            ret: ws!(tag!("::=")) >>
            (Term::Nonterminal(String::from_utf8_lossy(nt).into_owned()))
    )
);

named!(pub terminal< &[u8], Term >,
    do_parse!(
        t: alt!(
            delimited!(char!('"'), take_until!("\""), ws!(char!('"'))) |
            delimited!(char!('\''), take_until!("'"), ws!(char!('\'')))
            ) >>
        (Term::Terminal(String::from_utf8_lossy(t).into_owned()))
    )
);

named!(pub nonterminal< &[u8], Term >,
    do_parse!(
        nt: delimited!(char!('<'), take_until!(">"), ws!(char!('>'))) >>
        ws!(not!(tag!("::="))) >>
        (Term::Nonterminal(String::from_utf8_lossy(nt).into_owned()))
    )
);

named!(pub term< &[u8], Term >, alt!(terminal | nonterminal));

named!(pub term_complete< &[u8], Term >,
    do_parse!(
        t: term >>
        eof!() >>
        (t)
    )
);

named!(pub expression_next,
    do_parse!(
        ws!(char!('|')) >>
        ret: recognize!(peek!(complete!(expression))) >>
        (ret)
    )
);

named!(pub expression< &[u8], Expression >,
    do_parse!(
        terms: many1!(term) >>
        ws!(
            alt!(
                recognize!(peek!(complete!(eof!()))) |
                recognize!(peek!(complete!(char!(';')))) |
                expression_next |
                recognize!(peek!(complete!(prod_lhs)))
            )
        ) >>
        (Expression::from_parts(terms))
    )
);

named!(pub expression_complete< &[u8], Expression >,
    do_parse!(
        e: expression >>
        eof!() >>
        (e)
    )
);

named!(pub production< &[u8], Production >,
    do_parse!(
        lhs: ws!(prod_lhs) >>
        rhs: many1!(expression) >>
        ws!(
            alt!(
                recognize!(peek!(complete!(eof!()))) |
                tag!(";") |
                recognize!(peek!(complete!(prod_lhs)))
            )
        ) >>
        (Production::from_parts(lhs, rhs))
    )
);

named!(pub production_complete< &[u8], Production >,
    do_parse!(
        p: production >>
        eof!() >>
        (p)
    )
);

named!(pub grammar< &[u8], Grammar >,
    do_parse!(
        prods: many1!(production) >>
        (Grammar::from_parts(prods))
    )
);

named!(pub grammar_complete< &[u8], Grammar >,
    do_parse!(
        g: grammar >>
        eof!() >>
        (g)
    )
);

// named!(pub terminal< &[u8], Term >,
//     do_parse!(
//         t: delimited!(char!('\"'), take_until!("\""), char!('\"')) >>
//         (Term::Terminal(String::from_utf8_lossy(t).into_owned()))
//     )
// );

// named!(pub nonterminal< &[u8], Term >,
//     do_parse!(
//         nt: delimited!(char!('<'), take_until!(">"), char!('>')) >>
//         (Term::Nonterminal(String::from_utf8_lossy(nt).into_owned()))
//     )
// );

// named!(pub term< &[u8], Term >, ws!(alt!(terminal | nonterminal)));

// named!(pub expression< &[u8], Expression >,
//     do_parse!(
//         terms: ws!(many1!(term)) >>
//         (Expression::from_parts(terms))
//     )
// );

// named!(pub production< &[u8], Production >,
//     do_parse!(
//         lhs: nonterminal >>
//         ws!(tag!("::=")) >>
//         rhs: dbg_dmp!(separated_nonempty_list_complete!(char!('|'), ws!(expression))) >>
//         opt!(complete!(char!(';'))) >>
//         (Production::from_parts(lhs, rhs))
//     )
// );

// named!(pub grammar< &[u8], Grammar >,
//     do_parse!(
//         prods: many1!(production) >>
//         (Grammar::from_parts(prods))
//     )
// );

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

    fn construct_terminal_tuple() -> (Term, String) {
        let terminal_pattern = "\"terminal pattern\"";
        let terminal_value = "terminal pattern";
        let terminal_object = Term::Terminal(String::from(terminal_value));

        (terminal_object, String::from(terminal_pattern))
    }

    #[test]
    fn terminal_match() {
        let terminal_tuple = construct_terminal_tuple();
        assert_eq!(
            terminal_tuple.0,
            terminal(terminal_tuple.1.as_bytes()).unwrap().1
        );
    }

    fn construct_nonterminal_tuple() -> (Term, String) {
        let nonterminal_pattern = "<nonterminal-pattern>";
        let nonterminal_value = "nonterminal-pattern";
        let nonterminal_object = Term::Nonterminal(String::from(nonterminal_value));

        (nonterminal_object, String::from(nonterminal_pattern))
    }

    #[test]
    fn nonterminal_match() {
        let nonterminal_tuple = construct_nonterminal_tuple();
        assert_eq!(
            nonterminal_tuple.0,
            nonterminal(nonterminal_tuple.1.as_bytes()).unwrap().1
        );
    }

    fn construct_expression_tuple() -> (Expression, String) {
        let nonterminal_tuple = construct_nonterminal_tuple();
        let terminal_tuple = construct_terminal_tuple();
        let expression_pattern = nonterminal_tuple.1 + &terminal_tuple.1;
        let expression_object = Expression::from_parts(vec![nonterminal_tuple.0, terminal_tuple.0]);

        (expression_object, expression_pattern)
    }

    #[test]
    fn expression_match() {
        let expression_tuple = construct_expression_tuple();
        assert_eq!(
            expression_tuple.0,
            expression(expression_tuple.1.as_bytes()).unwrap().1
        );
    }

    fn construct_production_tuple() -> (Production, String) {
        let expression_tuple = construct_expression_tuple();
        let nonterminal_tuple = construct_nonterminal_tuple();
        let terminal_tuple = construct_nonterminal_tuple();
        let production_pattern =
            nonterminal_tuple.1 + "::=" + &expression_tuple.1 + "|" + &terminal_tuple.1 + ";";
        let production_object = Production::from_parts(
            nonterminal_tuple.0,
            vec![
                expression_tuple.0.clone(),
                Expression::from_parts(vec![terminal_tuple.0]),
            ],
        );

        (production_object, production_pattern)
    }

    #[test]
    fn production_match() {
        let production_tuple = construct_production_tuple();
        let parsed = production(production_tuple.1.as_bytes());
        assert_eq!(production_tuple.0, parsed.unwrap().1);
    }

    fn construct_grammar_tuple() -> (Grammar, String) {
        let production_tuple = construct_production_tuple();
        let grammar_pattern = production_tuple.1.clone() + &production_tuple.1;
        let grammar_object = Grammar::from_parts(vec![
            construct_production_tuple().0.clone(),
            construct_production_tuple().0,
        ]);

        (grammar_object, String::from(grammar_pattern))
    }

    #[test]
    fn grammar_match() {
        let grammar_tuple = construct_grammar_tuple();
        assert_eq!(
            grammar_tuple.0,
            grammar(grammar_tuple.1.as_bytes()).unwrap().1
        );
    }
}
<commit_msg>removed commented code that was used as reference<commit_after>use term::Term;
use expression::Expression;
use production::Production;
use grammar::Grammar;

named!(pub prod_lhs< &[u8], Term >,
    do_parse!(
            nt: delimited!(char!('<'), take_until!(">"), ws!(char!('>'))) >>
            ret: ws!(tag!("::=")) >>
            (Term::Nonterminal(String::from_utf8_lossy(nt).into_owned()))
    )
);

named!(pub terminal< &[u8], Term >,
    do_parse!(
        t: alt!(
            delimited!(char!('"'), take_until!("\""), ws!(char!('"'))) |
            delimited!(char!('\''), take_until!("'"), ws!(char!('\'')))
            ) >>
        (Term::Terminal(String::from_utf8_lossy(t).into_owned()))
    )
);

named!(pub nonterminal< &[u8], Term >,
    do_parse!(
        nt: delimited!(char!('<'), take_until!(">"), ws!(char!('>'))) >>
        ws!(not!(tag!("::="))) >>
        (Term::Nonterminal(String::from_utf8_lossy(nt).into_owned()))
    )
);

named!(pub term< &[u8], Term >, alt!(terminal | nonterminal));

named!(pub term_complete< &[u8], Term >,
    do_parse!(
        t: term >>
        eof!() >>
        (t)
    )
);

named!(pub expression_next,
    do_parse!(
        ws!(char!('|')) >>
        ret: recognize!(peek!(complete!(expression))) >>
        (ret)
    )
);

named!(pub expression< &[u8], Expression >,
    do_parse!(
        terms: many1!(term) >>
        ws!(
            alt!(
                recognize!(peek!(complete!(eof!()))) |
                recognize!(peek!(complete!(char!(';')))) |
                expression_next |
                recognize!(peek!(complete!(prod_lhs)))
            )
        ) >>
        (Expression::from_parts(terms))
    )
);

named!(pub expression_complete< &[u8], Expression >,
    do_parse!(
        e: expression >>
        eof!() >>
        (e)
    )
);

named!(pub production< &[u8], Production >,
    do_parse!(
        lhs: ws!(prod_lhs) >>
        rhs: many1!(expression) >>
        ws!(
            alt!(
                recognize!(peek!(complete!(eof!()))) |
                tag!(";") |
                recognize!(peek!(complete!(prod_lhs)))
            )
        ) >>
        (Production::from_parts(lhs, rhs))
    )
);

named!(pub production_complete< &[u8], Production >,
    do_parse!(
        p: production >>
        eof!() >>
        (p)
    )
);

named!(pub grammar< &[u8], Grammar >,
    do_parse!(
        prods: many1!(production) >>
        (Grammar::from_parts(prods))
    )
);

named!(pub grammar_complete< &[u8], Grammar >,
    do_parse!(
        g: grammar >>
        eof!() >>
        (g)
    )
);

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

    fn construct_terminal_tuple() -> (Term, String) {
        let terminal_pattern = "\"terminal pattern\"";
        let terminal_value = "terminal pattern";
        let terminal_object = Term::Terminal(String::from(terminal_value));

        (terminal_object, String::from(terminal_pattern))
    }

    #[test]
    fn terminal_match() {
        let terminal_tuple = construct_terminal_tuple();
        assert_eq!(
            terminal_tuple.0,
            terminal(terminal_tuple.1.as_bytes()).unwrap().1
        );
    }

    fn construct_nonterminal_tuple() -> (Term, String) {
        let nonterminal_pattern = "<nonterminal-pattern>";
        let nonterminal_value = "nonterminal-pattern";
        let nonterminal_object = Term::Nonterminal(String::from(nonterminal_value));

        (nonterminal_object, String::from(nonterminal_pattern))
    }

    #[test]
    fn nonterminal_match() {
        let nonterminal_tuple = construct_nonterminal_tuple();
        assert_eq!(
            nonterminal_tuple.0,
            nonterminal(nonterminal_tuple.1.as_bytes()).unwrap().1
        );
    }

    fn construct_expression_tuple() -> (Expression, String) {
        let nonterminal_tuple = construct_nonterminal_tuple();
        let terminal_tuple = construct_terminal_tuple();
        let expression_pattern = nonterminal_tuple.1 + &terminal_tuple.1;
        let expression_object = Expression::from_parts(vec![nonterminal_tuple.0, terminal_tuple.0]);

        (expression_object, expression_pattern)
    }

    #[test]
    fn expression_match() {
        let expression_tuple = construct_expression_tuple();
        assert_eq!(
            expression_tuple.0,
            expression(expression_tuple.1.as_bytes()).unwrap().1
        );
    }

    fn construct_production_tuple() -> (Production, String) {
        let expression_tuple = construct_expression_tuple();
        let nonterminal_tuple = construct_nonterminal_tuple();
        let terminal_tuple = construct_nonterminal_tuple();
        let production_pattern =
            nonterminal_tuple.1 + "::=" + &expression_tuple.1 + "|" + &terminal_tuple.1 + ";";
        let production_object = Production::from_parts(
            nonterminal_tuple.0,
            vec![
                expression_tuple.0.clone(),
                Expression::from_parts(vec![terminal_tuple.0]),
            ],
        );

        (production_object, production_pattern)
    }

    #[test]
    fn production_match() {
        let production_tuple = construct_production_tuple();
        let parsed = production(production_tuple.1.as_bytes());
        assert_eq!(production_tuple.0, parsed.unwrap().1);
    }

    fn construct_grammar_tuple() -> (Grammar, String) {
        let production_tuple = construct_production_tuple();
        let grammar_pattern = production_tuple.1.clone() + &production_tuple.1;
        let grammar_object = Grammar::from_parts(vec![
            construct_production_tuple().0.clone(),
            construct_production_tuple().0,
        ]);

        (grammar_object, String::from(grammar_pattern))
    }

    #[test]
    fn grammar_match() {
        let grammar_tuple = construct_grammar_tuple();
        assert_eq!(
            grammar_tuple.0,
            grammar(grammar_tuple.1.as_bytes()).unwrap().1
        );
    }
}
<|endoftext|>


<commit_before>//! This module is strictly internal.
//!
//! These functions are used by `date()`, `time()` and `datetime()`.
//! They are currently not private, because the need to be accessible,
//! but are not useful by themselves.
//!
//! Please refer to the top-level functions instead, as they offer a better abstraction.
//!
//! **These functions may be made private later.**

use std::str;

use nom::{
    branch::alt,
    bytes::complete::{tag, take_while, take_while_m_n},
    character::complete::one_of,
    character::is_digit,
    combinator::{map, opt},
    sequence::preceded,
    IResult,
};

use crate::{Date, DateTime, Time};

#[cfg(test)]
mod tests;

fn take_n_digits(i: &[u8], n: usize) -> IResult<&[u8], u32> {
    let (i, digits) = take_while_m_n(n, n, is_digit)(i)?;

    let s = str::from_utf8(digits).expect("Invalid data, expected UTF-8 string");
    let res = s
        .parse()
        .expect("Invalid string, expected ASCII reprensation of a number");
    Ok((i, res))
}

fn sign(i: &[u8]) -> IResult<&[u8], i32> {
    map(alt((tag(b"-"), tag(b"+"))), |s: &[u8]| match s {
        b"-" => -1,
        _ => 1,
    })(i)
}

// [+/-] year
fn year(i: &[u8]) -> IResult<&[u8], i32> {
    // The sign is optional, but defaults to `+`
    let (i, s) = sign(i).unwrap_or((i, 1));
    let (i, year) = take_n_digits(i, 4)?;
    let year = s * year as i32;

    Ok((i, year))
}

fn n_digit_in_range(
    i: &[u8],
    n: usize,
    range: impl std::ops::RangeBounds<u32>,
) -> IResult<&[u8], u32> {
    let (new_i, number) = take_n_digits(i, n)?;

    if range.contains(&number) {
        Ok((new_i, number))
    } else {
        Err(nom::Err::Error((i, nom::error::ErrorKind::Eof)))
    }
}

// MM
fn month(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 2, 1..=12)
}

// DD
fn day(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 2, 1..=31)
}

// WW
fn week(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 2, 1..=52)
}

fn week_day(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 1, 1..=7)
}

// ordinal DDD
fn ord_day(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 3, 1..=366)
}

// YYYY-MM-DD
fn ymd_date(i: &[u8]) -> IResult<&[u8], Date> {
    let (i, y) = year(i)?;
    let (i, _) = opt(tag(b"-"))(i)?;
    let (i, m) = month(i)?;
    let (i, _) = opt(tag(b"-"))(i)?;
    let (i, d) = day(i)?;
    Ok((
        i,
        Date::YMD {
            year: y,
            month: m,
            day: d,
        },
    ))
}

// YYYY-DDD
fn ordinal_date(i: &[u8]) -> IResult<&[u8], Date> {
    let (i, y) = year(i)?;
    let (i, _) = opt(tag(b"-"))(i)?;
    let (i, d) = ord_day(i)?;
    Ok((i, Date::Ordinal { year: y, ddd: d }))
}

// YYYY-"W"WW-D
fn iso_week_date(i: &[u8]) -> IResult<&[u8], Date> {
    let (i, y) = year(i)?;
    let (i, _) = opt(tag(b"-"))(i)?;
    let (i, _) = tag(b"W")(i)?;
    let (i, w) = week(i)?;
    let (i, _) = opt(tag(b"-"))(i)?;
    let (i, d) = week_day(i)?;
    Ok((
        i,
        Date::Week {
            year: y,
            ww: w,
            d: d,
        },
    ))
}

pub fn parse_date(i: &[u8]) -> IResult<&[u8], Date> {
    alt((ymd_date, iso_week_date, ordinal_date))(i)
}

// TIME

// HH
fn hour(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 2, 0..=24)
}

// MM
fn minute(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 2, 0..=59)
}

fn second(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 2, 0..=60)
}

fn fractions(i: &[u8]) -> IResult<&[u8], f32> {
    let (i, digits) = take_while(is_digit)(i)?;
    let digits = str::from_utf8(digits).unwrap(); // This can't panic, `digits` will only include digits.
    let f = format!("0.{}", digits).parse().unwrap(); // This can't panic, the string is a valid `f32`.

    Ok((i, f))
}

fn millisecond(fraction: f32) -> u32 {
    (1000.0 * fraction) as u32
}

// HH:MM:[SS][.(m*)][(Z|+...|-...)]
pub fn parse_time(i: &[u8]) -> IResult<&[u8], Time> {
    let (i, h) = hour(i)?;
    let (i, _) = opt(tag(b":"))(i)?;
    let (i, m) = minute(i)?;
    let (i, s) = opt(preceded(opt(tag(b":")), second))(i)?;
    let (i, ms) = opt(map(preceded(one_of(",."), fractions), millisecond))(i)?;
    let (i, z) = match opt(alt((timezone_hour, timezone_utc)))(i) {
        Ok(ok) => ok,
        Err(nom::Err::Incomplete(_)) => (i, None),
        Err(e) => return Err(e),
    };

    Ok((
        i,
        Time {
            hour: h,
            minute: m,
            second: s.unwrap_or(0),
            millisecond: ms.unwrap_or(0),
            tz_offset_hours: z.unwrap_or((0, 0)).0,
            tz_offset_minutes: z.unwrap_or((0, 0)).1,
        },
    ))
}

fn timezone_hour(i: &[u8]) -> IResult<&[u8], (i32, i32)> {
    let (i, s) = sign(i)?;
    let (i, h) = hour(i)?;
    let (i, m) = if i.is_empty() {
        (i, 0)
    } else {
        let (i, _) = opt(tag(b":"))(i)?;
        minute(i)?
    };

    Ok((i, ((s * (h as i32), s * (m as i32)))))
}

fn timezone_utc(i: &[u8]) -> IResult<&[u8], (i32, i32)> {
    map(tag(b"Z"), |_| (0, 0))(i)
}

// Full ISO8601
pub fn parse_datetime(i: &[u8]) -> IResult<&[u8], DateTime> {
    let (i, d) = parse_date(i)?;
    let (i, _) = tag(b"T")(i)?;
    let (i, t) = parse_time(i)?;

    Ok((i, DateTime { date: d, time: t }))
}
<commit_msg>Extract timezone first<commit_after>//! This module is strictly internal.
//!
//! These functions are used by `date()`, `time()` and `datetime()`.
//! They are currently not private, because the need to be accessible,
//! but are not useful by themselves.
//!
//! Please refer to the top-level functions instead, as they offer a better abstraction.
//!
//! **These functions may be made private later.**

use std::str;

use nom::{
    branch::alt,
    bytes::complete::{tag, take_while, take_while_m_n},
    character::complete::one_of,
    character::is_digit,
    combinator::{map, opt},
    sequence::preceded,
    IResult,
};

use crate::{Date, DateTime, Time};

#[cfg(test)]
mod tests;

fn take_n_digits(i: &[u8], n: usize) -> IResult<&[u8], u32> {
    let (i, digits) = take_while_m_n(n, n, is_digit)(i)?;

    let s = str::from_utf8(digits).expect("Invalid data, expected UTF-8 string");
    let res = s
        .parse()
        .expect("Invalid string, expected ASCII reprensation of a number");
    Ok((i, res))
}

fn sign(i: &[u8]) -> IResult<&[u8], i32> {
    map(alt((tag(b"-"), tag(b"+"))), |s: &[u8]| match s {
        b"-" => -1,
        _ => 1,
    })(i)
}

// [+/-] year
fn year(i: &[u8]) -> IResult<&[u8], i32> {
    // The sign is optional, but defaults to `+`
    let (i, s) = sign(i).unwrap_or((i, 1));
    let (i, year) = take_n_digits(i, 4)?;
    let year = s * year as i32;

    Ok((i, year))
}

fn n_digit_in_range(
    i: &[u8],
    n: usize,
    range: impl std::ops::RangeBounds<u32>,
) -> IResult<&[u8], u32> {
    let (new_i, number) = take_n_digits(i, n)?;

    if range.contains(&number) {
        Ok((new_i, number))
    } else {
        Err(nom::Err::Error((i, nom::error::ErrorKind::Eof)))
    }
}

// MM
fn month(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 2, 1..=12)
}

// DD
fn day(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 2, 1..=31)
}

// WW
fn week(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 2, 1..=52)
}

fn week_day(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 1, 1..=7)
}

// ordinal DDD
fn ord_day(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 3, 1..=366)
}

// YYYY-MM-DD
fn ymd_date(i: &[u8]) -> IResult<&[u8], Date> {
    let (i, y) = year(i)?;
    let (i, _) = opt(tag(b"-"))(i)?;
    let (i, m) = month(i)?;
    let (i, _) = opt(tag(b"-"))(i)?;
    let (i, d) = day(i)?;
    Ok((
        i,
        Date::YMD {
            year: y,
            month: m,
            day: d,
        },
    ))
}

// YYYY-DDD
fn ordinal_date(i: &[u8]) -> IResult<&[u8], Date> {
    let (i, y) = year(i)?;
    let (i, _) = opt(tag(b"-"))(i)?;
    let (i, d) = ord_day(i)?;
    Ok((i, Date::Ordinal { year: y, ddd: d }))
}

// YYYY-"W"WW-D
fn iso_week_date(i: &[u8]) -> IResult<&[u8], Date> {
    let (i, y) = year(i)?;
    let (i, _) = opt(tag(b"-"))(i)?;
    let (i, _) = tag(b"W")(i)?;
    let (i, w) = week(i)?;
    let (i, _) = opt(tag(b"-"))(i)?;
    let (i, d) = week_day(i)?;
    Ok((
        i,
        Date::Week {
            year: y,
            ww: w,
            d: d,
        },
    ))
}

pub fn parse_date(i: &[u8]) -> IResult<&[u8], Date> {
    alt((ymd_date, iso_week_date, ordinal_date))(i)
}

// TIME

// HH
fn hour(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 2, 0..=24)
}

// MM
fn minute(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 2, 0..=59)
}

fn second(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 2, 0..=60)
}

fn fractions(i: &[u8]) -> IResult<&[u8], f32> {
    let (i, digits) = take_while(is_digit)(i)?;
    let digits = str::from_utf8(digits).unwrap(); // This can't panic, `digits` will only include digits.
    let f = format!("0.{}", digits).parse().unwrap(); // This can't panic, the string is a valid `f32`.

    Ok((i, f))
}

fn millisecond(fraction: f32) -> u32 {
    (1000.0 * fraction) as u32
}

// HH:MM:[SS][.(m*)][(Z|+...|-...)]
pub fn parse_time(i: &[u8]) -> IResult<&[u8], Time> {
    let (i, h) = hour(i)?;
    let (i, _) = opt(tag(b":"))(i)?;
    let (i, m) = minute(i)?;
    let (i, s) = opt(preceded(opt(tag(b":")), second))(i)?;
    let (i, ms) = opt(map(preceded(one_of(",."), fractions), millisecond))(i)?;
    let (i, z) = match opt(alt((timezone_hour, timezone_utc)))(i) {
        Ok(ok) => ok,
        Err(nom::Err::Incomplete(_)) => (i, None),
        Err(e) => return Err(e),
    };

    let (tz_offset_hours, tz_offset_minutes) = z.unwrap_or((0, 0));

    Ok((
        i,
        Time {
            hour: h,
            minute: m,
            second: s.unwrap_or(0),
            millisecond: ms.unwrap_or(0),
            tz_offset_hours,
            tz_offset_minutes,
        },
    ))
}

fn timezone_hour(i: &[u8]) -> IResult<&[u8], (i32, i32)> {
    let (i, s) = sign(i)?;
    let (i, h) = hour(i)?;
    let (i, m) = if i.is_empty() {
        (i, 0)
    } else {
        let (i, _) = opt(tag(b":"))(i)?;
        minute(i)?
    };

    Ok((i, ((s * (h as i32), s * (m as i32)))))
}

fn timezone_utc(i: &[u8]) -> IResult<&[u8], (i32, i32)> {
    map(tag(b"Z"), |_| (0, 0))(i)
}

// Full ISO8601
pub fn parse_datetime(i: &[u8]) -> IResult<&[u8], DateTime> {
    let (i, d) = parse_date(i)?;
    let (i, _) = tag(b"T")(i)?;
    let (i, t) = parse_time(i)?;

    Ok((i, DateTime { date: d, time: t }))
}
<|endoftext|>


<commit_before>//inherited mutability: player is mutable if let is mutable

//todo: Test in ticks
//      Implement player acceleration based on ticks between inputs.
//      Potentially ticks holding a button and ticks not
//      Rotation accel/vel
use game;

use std::cmp::{max, min};

pub use self::collision::collide;

#[deriving(Eq)]
pub enum Direction {
    Forward,
    Backward,
    Still
}

#[deriving(Eq)]
pub enum Rotation {
    Left,
    Right,
    Norot
}

pub fn rotate(p: &mut game::Player){
    use std::f32::consts::PI;
    if p.rot == Left{
        p.rotation += PI / 90.0;
    }
    if p.rot == Right{
        p.rotation -= PI / 90.0;
    }
}

pub fn accel(p: &mut game::Player){ //mut player:&mut player would allow to play w/ pointer
    if p.velocity >= -0.15 && p.velocity <= 0.15 {
        p.velocity += p.accel * 0.0001;
    }

    if p.velocity < -0.05 {
        p.velocity = -0.05;
    }

    if p.velocity >= 0.05 {
        p.velocity = 0.05
    }

    p.position += p.velocity;

    let (acc, amod) = accel_compute(p.dir, p.accel, p.accel_mod);

    p.accel = acc;
    p.accel_mod = amod;
}

pub fn accel_compute (dir: Direction, mut accel: f32, mut accel_mod: int) -> (f32, int) {
    //this will use accel/accel_mod to compute the rate of increase of acceleration.
    if dir == Forward {
        let bounds = [
            (-85, -75, 25),
            (-75, -60, 22),
            (-60, -41, 19),
            (-40, -15, 17),
            (0, 15, 12),
            (14, 40, 10),
            (40, 60, 8),
            (60, 75, 5),
            (75, 85, 2)
        ];

        accel_mod = max(accel_mod, -84);

        if accel_mod == 0 {
            accel_mod = 15;
        } else if accel_mod >= -15 && accel_mod < 0 {
            accel_mod = 0;
        } else {
            for &(lower, upper, increment) in bounds.iter() {
                if accel_mod >= lower && accel_mod <= upper {
                    accel_mod += increment;
                    break
                }
            }
        }

    } else if dir == Backward {
        let bounds = [
            (-85, -75, -2),
            (-75, -60, -5),
            (-60, -41, -8),
            (-40, -15, -10),
            (-15, 0, -12),
            (15, 40, -17),
            (40, 60, -19),
            (60, 75, -22),
            (75, 85, -25)
        ];

        accel_mod = min(accel_mod, 84);

        if accel_mod == 0 {
            accel_mod = -15;
        } else if accel_mod <= 15 && accel_mod > 0 {
            accel_mod = 0;
        } else {
            for &(lower, upper, increment) in bounds.iter() {
                if accel_mod >= lower && accel_mod <= upper {
                    accel_mod += increment;
                    break
                }
            }
        }
    }

    if accel <= 0.05 && accel >= -0.05 {
        accel = accel + (0.00003 * (accel_mod as f32));
    } else {
        accel = accel.signum() * 0.05;
    }

    (accel, accel_mod) //returns accel and accel mod
}

mod collision {
    use cgmath::angle::Rad;
    use cgmath::vector::{Vector, Vector2};
    use cgmath::matrix::{Matrix, Matrix2};
    use gl::types::GLfloat;
    use render::Sprite;
    use std::f32::consts::PI;

    type V = Vector2<GLfloat>;

    fn min(a: GLfloat, b: GLfloat) -> GLfloat {
        a.min(b)
    }

    fn max(a: GLfloat, b: GLfloat) -> GLfloat {
        a.max(b)
    }

    fn slope(a: V, b: V) -> GLfloat {
        (a.y - b.y) / (a.x - b.x)
    }

    fn line_intercept((a1, a2): (V, V), (b1, b2): (V, V)) -> f32 {
        let (x1, x2, y1, y2, m1, m2) = (a1.x, b1.x, a1.y, b1.y, slope(a1, a2), slope(b1, b2));

        ((m1*x1) - (m2*x2) - y1 + y2) / (m1 - m2)
    }

    fn intersect((a1, a2): (V, V), (b1, b2): (V, V)) -> Option<V> {
        debug!("Checking the intersection of the two lines, {} to {} and {} to {}", a1, a2, b1, b2);

        let x = line_intercept((a1, a2), (b1, b2));
        debug!("The lines, were they infinite, intersect at x = {}", x);

        let y = slope(a1, a2)*(x - a1.x) + a1.y;
        debug!("The corresponding y is {}", y);

        if x >= min(a1.x, a2.x) && x <= max(a1.x, a2.x) {
            debug!("It's within the first line's x values");
            if x >= min(b1.x, b2.x) && x <= max(b1.x, b2.x) {
                debug!("It's within the second line's x values");
                if y >= min(a1.y, a2.y) && y <= max(a1.y, a2.y) {
                    debug!("It's within the first line's y values");
                    if y >= min(b1.y, b2.y) && y <= max(b1.y, b2.y) {
                        debug!("It's within the second line's y values");
                        return Some(Vector2::new(x, y));
                    }
                }
            }
        }

        None
    }

    #[test]
    fn test_intersect() {
        let a = Vector2::new(1f32, 1f32);
        let b = Vector2::new(-1f32, -1f32);

        let c = Vector2::new(-1f32, 1f32);
        let d = Vector2::new(1f32, -1f32);

        assert_eq!(intersect((a, b), (c, d)), Some(Vector2::new(0f32, 0f32)));
    }

    /// Determines if two Sprites collide, assuming that they collide iff their
    /// (possibly rotated) bounding boxes collide, not using the texture in any
    /// way.
    pub fn collide(a: &Sprite, b: &Sprite) -> bool {

        // make lists of points making up each sprite, transformed with the
        // rotation

        let mut arot = a.rot;
        let mut brot = b.rot;

        // make sure their slopes aren't NaN :(
        if arot % (PI / 4.0) == 0.0 {
            arot += 0.01;
        }

        if brot % (PI / 4.0) == 0.0 {
            brot += 0.01;
        }

        let amat = Matrix2::from_angle(Rad { s: arot });
        let bmat = Matrix2::from_angle(Rad { s: brot });

        let pairs = [(0, 1), (1, 2), (2, 3), (3, 0)]; // which indices form lines we care about?

        let &Sprite {x, y, width, height, .. } = a;
        let apoints = [
            amat.mul_v(&Vector2::new(x, y)),
            amat.mul_v(&Vector2::new(x + width, y)),
            amat.mul_v(&Vector2::new(x + width, y + height)),
            amat.mul_v(&Vector2::new(x, y + height))
        ];

        let &Sprite {x, y, width, height, .. } = b;
        let bpoints = [
            bmat.mul_v(&Vector2::new(x, y)),
            bmat.mul_v(&Vector2::new(x + width, y)),
            bmat.mul_v(&Vector2::new(x + width, y + height)),
            bmat.mul_v(&Vector2::new(x, y + height))
        ];

        for &(a1, a2) in pairs.iter() {
            for &(b1, b2) in pairs.iter() {
                if intersect((apoints[a1], apoints[a2]), (bpoints[b1], bpoints[b2])) != None {
                    return true;
                }
            }
        }

        false
    }

    #[test]
    fn test_collide() {
        use std;

        let s1 = Sprite::new(0.0, 0.0, 1.0, 1.0, 0.0, unsafe { std::mem::uninit() });
        let s2 = Sprite::new(0.5, 0.5, 1.0, 1.0, 0.0, unsafe { std::mem::uninit() });

        assert_eq!(collide(&s1, &s2), true);

        unsafe {
            // since we're stubbing out the texture
            std::cast::forget(s1);
            std::cast::forget(s2);
        }

        let s1 = Sprite::new(0.0, 0.0, 1.0, 1.0, 0.0, unsafe { std::mem::uninit() });
        let s2 = Sprite::new(1.0, 1.0, 1.0, 1.0, 0.0, unsafe { std::mem::uninit() });

        assert_eq!(collide(&s1, &s2), true);

        unsafe {
            // since we're stubbing out the texture
            std::cast::forget(s1);
            std::cast::forget(s2);
        }

        let s1 = Sprite::new(0.0, 0.0, 1.0, 1.0, 0.0, unsafe { std::mem::uninit() });
        let s2 = Sprite::new(0.0, 0.0, 1.0, 1.0, 0.5, unsafe { std::mem::uninit() });

        assert_eq!(collide(&s1, &s2), true);

        unsafe {
            // since we're stubbing out the texture
            std::cast::forget(s1);
            std::cast::forget(s2);
        }
    }
}
<commit_msg>Tweak physics values<commit_after>//inherited mutability: player is mutable if let is mutable

//todo: Test in ticks
//      Implement player acceleration based on ticks between inputs.
//      Potentially ticks holding a button and ticks not
//      Rotation accel/vel
use game;

use std::cmp::{max, min};

pub use self::collision::collide;

#[deriving(Eq)]
pub enum Direction {
    Forward,
    Backward,
    Still
}

#[deriving(Eq)]
pub enum Rotation {
    Left,
    Right,
    Norot
}

pub fn rotate(p: &mut game::Player){
    use std::f32::consts::PI;
    if p.rot == Left{
        p.rotation += PI / 90.0;
    }
    if p.rot == Right{
        p.rotation -= PI / 90.0;
    }
}

pub fn accel(p: &mut game::Player){ //mut player:&mut player would allow to play w/ pointer
    let (acc, amod) = accel_compute(p.dir, p.accel, p.accel_mod);

    if p.velocity >= -0.15 && p.velocity <= 0.15 {
        p.velocity += p.accel * 0.0001;
    }

    if p.velocity < -0.008 {
        p.velocity = -0.008;
    }

    if p.velocity >= 0.008 {
        p.velocity = 0.008
    }

    p.position += p.velocity;

    p.accel = acc;
    p.accel_mod = amod;
}

pub fn accel_compute (dir: Direction, mut accel: f32, mut accel_mod: int) -> (f32, int) {
    //this will use accel/accel_mod to compute the rate of increase of acceleration.
    if dir == Forward {
        let bounds = [
            (-85, -75, 25),
            (-75, -60, 22),
            (-60, -41, 19),
            (-40, -15, 17),
            (0, 15, 12),
            (14, 40, 10),
            (40, 60, 8),
            (60, 75, 5),
            (75, 85, 2)
        ];

        accel_mod = max(accel_mod, -84);

        if accel_mod == 0 {
            accel_mod = 15;
        } else if accel_mod >= -15 && accel_mod < 0 {
            accel_mod = 0;
        } else {
            for &(lower, upper, increment) in bounds.iter() {
                if accel_mod >= lower && accel_mod <= upper {
                    accel_mod += increment;
                    break
                }
            }
        }

    } else if dir == Backward {
        let bounds = [
            (-85, -75, -10),
            (-75, -60, -5),
            (-60, -41, -8),
            (-40, -15, -10),
            (-15, 0, -12),
            (15, 40, -17),
            (40, 60, -19),
            (60, 75, -22),
            (75, 85, -25)
        ];

        accel_mod = min(accel_mod, 84);

        if accel_mod == 0 {
            accel_mod = -15;
        } else if accel_mod <= 15 && accel_mod > 0 {
            accel_mod = 0;
        } else {
            for &(lower, upper, increment) in bounds.iter() {
                if accel_mod >= lower && accel_mod <= upper {
                    accel_mod += increment;
                    break
                }
            }
        }
    }

    let max = 0.04;

    if accel >= -max && accel <= max {
        accel += 0.08 * (accel_mod as f32);
    } else {
        accel = accel.signum() * max;
    }

    (accel, accel_mod) //returns accel and accel mod
}

mod collision {
    use cgmath::angle::Rad;
    use cgmath::vector::{Vector, Vector2};
    use cgmath::matrix::{Matrix, Matrix2};
    use gl::types::GLfloat;
    use render::Sprite;
    use std::f32::consts::PI;

    type V = Vector2<GLfloat>;

    fn min(a: GLfloat, b: GLfloat) -> GLfloat {
        a.min(b)
    }

    fn max(a: GLfloat, b: GLfloat) -> GLfloat {
        a.max(b)
    }

    fn slope(a: V, b: V) -> GLfloat {
        (a.y - b.y) / (a.x - b.x)
    }

    fn line_intercept((a1, a2): (V, V), (b1, b2): (V, V)) -> f32 {
        let (x1, x2, y1, y2, m1, m2) = (a1.x, b1.x, a1.y, b1.y, slope(a1, a2), slope(b1, b2));

        ((m1*x1) - (m2*x2) - y1 + y2) / (m1 - m2)
    }

    fn intersect((a1, a2): (V, V), (b1, b2): (V, V)) -> Option<V> {
        debug!("Checking the intersection of the two lines, {} to {} and {} to {}", a1, a2, b1, b2);

        let x = line_intercept((a1, a2), (b1, b2));
        debug!("The lines, were they infinite, intersect at x = {}", x);

        let y = slope(a1, a2)*(x - a1.x) + a1.y;
        debug!("The corresponding y is {}", y);

        if x >= min(a1.x, a2.x) && x <= max(a1.x, a2.x) {
            debug!("It's within the first line's x values");
            if x >= min(b1.x, b2.x) && x <= max(b1.x, b2.x) {
                debug!("It's within the second line's x values");
                if y >= min(a1.y, a2.y) && y <= max(a1.y, a2.y) {
                    debug!("It's within the first line's y values");
                    if y >= min(b1.y, b2.y) && y <= max(b1.y, b2.y) {
                        debug!("It's within the second line's y values");
                        return Some(Vector2::new(x, y));
                    }
                }
            }
        }

        None
    }

    #[test]
    fn test_intersect() {
        let a = Vector2::new(1f32, 1f32);
        let b = Vector2::new(-1f32, -1f32);

        let c = Vector2::new(-1f32, 1f32);
        let d = Vector2::new(1f32, -1f32);

        assert_eq!(intersect((a, b), (c, d)), Some(Vector2::new(0f32, 0f32)));
    }

    /// Determines if two Sprites collide, assuming that they collide iff their
    /// (possibly rotated) bounding boxes collide, not using the texture in any
    /// way.
    pub fn collide(a: &Sprite, b: &Sprite) -> bool {

        // make lists of points making up each sprite, transformed with the
        // rotation

        let mut arot = a.rot;
        let mut brot = b.rot;

        // make sure their slopes aren't NaN :(
        if arot % (PI / 4.0) == 0.0 {
            arot += 0.01;
        }

        if brot % (PI / 4.0) == 0.0 {
            brot += 0.01;
        }

        let amat = Matrix2::from_angle(Rad { s: arot });
        let bmat = Matrix2::from_angle(Rad { s: brot });

        let pairs = [(0, 1), (1, 2), (2, 3), (3, 0)]; // which indices form lines we care about?

        let &Sprite {x, y, width, height, .. } = a;
        let apoints = [
            amat.mul_v(&Vector2::new(x, y)),
            amat.mul_v(&Vector2::new(x + width, y)),
            amat.mul_v(&Vector2::new(x + width, y + height)),
            amat.mul_v(&Vector2::new(x, y + height))
        ];

        let &Sprite {x, y, width, height, .. } = b;
        let bpoints = [
            bmat.mul_v(&Vector2::new(x, y)),
            bmat.mul_v(&Vector2::new(x + width, y)),
            bmat.mul_v(&Vector2::new(x + width, y + height)),
            bmat.mul_v(&Vector2::new(x, y + height))
        ];

        for &(a1, a2) in pairs.iter() {
            for &(b1, b2) in pairs.iter() {
                if intersect((apoints[a1], apoints[a2]), (bpoints[b1], bpoints[b2])) != None {
                    return true;
                }
            }
        }

        false
    }

    #[test]
    fn test_collide() {
        use std;

        let s1 = Sprite::new(0.0, 0.0, 1.0, 1.0, 0.0, unsafe { std::mem::uninit() });
        let s2 = Sprite::new(0.5, 0.5, 1.0, 1.0, 0.0, unsafe { std::mem::uninit() });

        assert_eq!(collide(&s1, &s2), true);

        unsafe {
            // since we're stubbing out the texture
            std::cast::forget(s1);
            std::cast::forget(s2);
        }

        let s1 = Sprite::new(0.0, 0.0, 1.0, 1.0, 0.0, unsafe { std::mem::uninit() });
        let s2 = Sprite::new(1.0, 1.0, 1.0, 1.0, 0.0, unsafe { std::mem::uninit() });

        assert_eq!(collide(&s1, &s2), true);

        unsafe {
            // since we're stubbing out the texture
            std::cast::forget(s1);
            std::cast::forget(s2);
        }

        let s1 = Sprite::new(0.0, 0.0, 1.0, 1.0, 0.0, unsafe { std::mem::uninit() });
        let s2 = Sprite::new(0.0, 0.0, 1.0, 1.0, 0.5, unsafe { std::mem::uninit() });

        assert_eq!(collide(&s1, &s2), true);

        unsafe {
            // since we're stubbing out the texture
            std::cast::forget(s1);
            std::cast::forget(s2);
        }
    }
}
<|endoftext|>


<commit_before>use std::ptr;
use std::error;
use std::fmt;
use std::borrow::BorrowMut;
use std::marker::PhantomData;
use std::ffi::CString;
use gl;
use gl::types::*;
use types::GLError;
use context::{AContext, ContextOf};
use shader::Shader;
use uniform_data::{UniformData, UniformDatumType, UniformPrimitiveType};

pub struct Program {
    gl_id: GLuint
}

impl Program {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl Drop for Program {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteProgram(self.gl_id);
        }
    }
}

unsafe fn _get_program_iv(program: &Program,
                          pname: GLenum,
                          params: *mut GLint)
{
    gl::GetProgramiv(program.gl_id(), pname, params);
    dbg_gl_sanity_check! {
        GLError::InvalidEnum => "`pname` is not an accepted value",
        GLError::InvalidValue => "`program` is not a value generated by OpenGL",
        GLError::InvalidOperation => "`program` does not refer to a program object",
        _ => "Unknown error"
    }
}

pub struct ProgramBuilder<'a, B, F, P, R, T>
    where B: 'a,
          F: 'a,
          P: 'a,
          R: 'a,
          T: 'a
{
    gl: &'a ContextOf<B, F, P, R, T>,
    shaders: &'a [Shader]
}

impl<'a, B, F, P, R, T> ProgramBuilder<'a, B, F, P, R, T>
    where B: 'a,
          F: 'a,
          P: 'a,
          R: 'a,
          T: 'a
{
    pub fn new(gl: &'a ContextOf<B, F, P, R, T>, shaders: &'a [Shader])
        -> Self
    {
        ProgramBuilder { gl: gl, shaders: shaders }
    }

    pub fn try_unwrap(self) -> Result<Program, GLError> {
        unsafe {
            let mut program = try! {
                self.gl.create_program().or_else(|_| {
                    let msg = "Error creating OpenGL program";
                    Err(GLError::Message(msg.to_owned()))
                })
            };

            for shader in self.shaders {
                self.gl.attach_shader(&mut program, shader);
            }

            try!(self.gl.link_program(&mut program));
            Ok(program)
        }
    }

    pub fn unwrap(self) -> Program {
        self.try_unwrap().unwrap()
    }
}

impl<B, F, P, R, T> ContextOf<B, F, P, R, T> {
    // TODO: Move this method into `ContextProgramExt`
    pub fn build_program<'a>(&'a self, shaders: &'a [Shader])
        -> ProgramBuilder<'a, B, F, P, R, T>
    {
        ProgramBuilder::new(self, shaders)
    }
}

pub trait ContextProgramExt {
    unsafe fn create_program(&self) -> Result<Program, ()>;
    fn attach_shader(&self, program: &mut Program, shader: &Shader);
    fn link_program(&self, program: &mut Program) -> Result<(), GLError>;
    fn get_program_info_log(&self, program: &Program) -> Option<String>;
    fn get_attrib_location<'a>(&self, program: &Program, name: &'a str)
        -> Result<ProgramAttrib, UnknownProgramAttrib<'a>>;
    fn get_uniform_location<'a>(&self, program: &Program, name: &'a str)
        -> Result<ProgramUniform, UnknownProgramUniform<'a>>;
}

impl<B, F, P, R, T> ContextProgramExt for ContextOf<B, F, P, R, T> {
    unsafe fn create_program(&self) -> Result<Program, ()> {
        let id = gl::CreateProgram();
        if id > 0 {
            Ok(Program { gl_id: id })
        }
        else {
            Err(())
        }
    }

    fn attach_shader(&self, program: &mut Program, shader: &Shader) {
        unsafe {
            gl::AttachShader(program.gl_id(), shader.gl_id());
            dbg_gl_error! {
                GLError::InvalidValue => "One of either `program` or `shader` is not an OpenGL object",
                GLError::InvalidOperation => "`shader` is already attached to `program`, `shader` is not a shader object, or `program` is not a program object",
                _ => "Unknown error"
            }
        }
    }

    fn link_program(&self, program: &mut Program) -> Result<(), GLError> {
        let success = unsafe {
            gl::LinkProgram(program.gl_id());
            dbg_gl_error! {
                GLError::InvalidValue => "`program` is not a value from OpenGL",
                GLError::InvalidOperation => "`program` is not a program object",
                _ => "Unknown error"
            }

            let mut link_status : GLint = 0;
            _get_program_iv(program,
                            gl::LINK_STATUS,
                            &mut link_status as *mut GLint);

            link_status == gl::TRUE as GLint
        };

        if success {
            Ok(())
        }
        else {
            let msg = match self.get_program_info_log(&program) {
                Some(s) => { s },
                None => { String::from("[Unknown program error]") }
            };
            Err(GLError::Message(msg))
        }
    }

    fn get_program_info_log(&self, program: &Program) -> Option<String> {
        unsafe {
            let mut info_length : GLint = 0;
            _get_program_iv(program,
                            gl::INFO_LOG_LENGTH,
                            &mut info_length as *mut GLint);

            if info_length > 0 {
                let mut bytes = Vec::<u8>::with_capacity(info_length as usize);

                gl::GetProgramInfoLog(program.gl_id(),
                                      info_length,
                                      ptr::null_mut(),
                                      bytes.as_mut_ptr() as *mut GLchar);
                dbg_gl_sanity_check! {
                    GLError::InvalidValue => "`program` is not a value generated by OpenGL, or `maxLength` < 0",
                    GLError::InvalidOperation => "`program` is not a program object",
                    _ => "Unknown error"
                }
                bytes.set_len((info_length - 1) as usize);

                String::from_utf8(bytes).ok()
            }
            else {
                None
            }
        }
    }

    fn get_attrib_location<'a>(&self, program: &Program, name: &'a str)
        -> Result<ProgramAttrib, UnknownProgramAttrib<'a>>
    {
        let err = Err(UnknownProgramAttrib { name: name });

        let c_str = match CString::new(name) {
            Ok(s) => { s },
            Err(_) => { return err }
        };
        // let c_str = try!(CString::new(name).or(Err(e)));
        let str_ptr = c_str.as_ptr() as *const GLchar;
        unsafe {
            let index = gl::GetAttribLocation(program.gl_id(), str_ptr);
            dbg_gl_error! {
                GLError::InvalidOperation => "`program` has not been linked, `program` is not a program object, or `program` is not a value generated by OpenGL",
                _ => "Unknown error"
            }

            if index >= 0 {
                Ok(ProgramAttrib { gl_index: index as GLuint })
            }
            else {
                err
            }
        }
    }

    fn get_uniform_location<'a>(&self, program: &Program, name: &'a str)
        -> Result<ProgramUniform, UnknownProgramUniform<'a>>
    {
        let err = Err(UnknownProgramUniform { name: name });

        let c_str = match CString::new(name) {
            Ok(s) => { s },
            Err(_) => { return err; }
        };
        // let c_str = try!(CString::new(name).or(Err(e)));
        let str_ptr = c_str.as_ptr() as *const GLchar;
        unsafe {
            let index = gl::GetUniformLocation(program.gl_id(), str_ptr);
            dbg_gl_error! {
                GLError::InvalidValue => "`program` is not a value generated by OpenGL",
                GLError::InvalidOperation => "`program` is not a program object, or has not been successfully linked",
                _ => "Unknown error"
            }

            if index >= 0 {
                Ok(ProgramUniform { gl_index: index as GLuint })
            }
            else {
                err
            }
        }
    }
}

// TODO: Add a macro to reduce this boilerplate
impl<'b, B, F, P, R, T> ContextProgramExt for &'b mut ContextOf<B, F, P, R, T> {
    unsafe fn create_program(&self) -> Result<Program, ()> {
        (**self).create_program()
    }

    fn attach_shader(&self, program: &mut Program, shader: &Shader) {
        (**self).attach_shader(program, shader);
    }

    fn link_program(&self, program: &mut Program) -> Result<(), GLError> {
        (**self).link_program(program)
    }

    fn get_program_info_log(&self, program: &Program) -> Option<String> {
        (**self).get_program_info_log(program)
    }

    fn get_attrib_location<'a>(&self, program: &Program, name: &'a str)
        -> Result<ProgramAttrib, UnknownProgramAttrib<'a>>
    {
        (**self).get_attrib_location(program, name)
    }

    fn get_uniform_location<'a>(&self, program: &Program, name: &'a str)
        -> Result<ProgramUniform, UnknownProgramUniform<'a>>
    {
        (**self).get_uniform_location(program, name)
    }
}

pub trait ProgramContext: AContext {
    type Rest: AContext;

    fn use_program<'a>(self, program: &'a mut Program)
        -> (ProgramBinding<'a>, Self::Rest);
}

impl<B, F, P, R, T> ProgramContext for ContextOf<B, F, P, R, T>
    where P: BorrowMut<ProgramBinder>
{
    type Rest = ContextOf<B, F, (), R, T>;

    fn use_program<'a>(self, program: &'a mut Program)
        -> (ProgramBinding<'a>, Self::Rest)
    {
        let (mut program_binder, rest) = self.split_program();
        (program_binder.borrow_mut().bind(program), rest)
    }
}

impl<'b, B, F, P, R, T> ProgramContext for &'b mut ContextOf<B, F, P, R, T>
    where P: BorrowMut<ProgramBinder>
{
    type Rest = ContextOf<&'b mut B, &'b mut F, (), &'b mut R, &'b mut T>;

    fn use_program<'a>(self, program: &'a mut Program)
        -> (ProgramBinding<'a>, Self::Rest)
    {
        let gl = self.mut_into();
        let (program_binder, rest): (&mut P, _) = gl.split_program();
        (program_binder.borrow_mut().bind(program), rest)
    }
}

pub struct ProgramBinding<'a> {
    phantom: PhantomData<&'a mut Program>
}

impl<'a> ProgramBinding<'a> {
    pub fn set_uniform<T>(&self, uniform: ProgramUniform, val: T)
        where T: UniformData
    {
        let idx = uniform.gl_index as GLint;
        let count = val.uniform_elements() as GLsizei;
        let ptr = val.uniform_bytes().as_ptr();
        unsafe {
            match T::uniform_datum_type() {
                UniformDatumType::Vec1(p) => {
                    match p {
                        UniformPrimitiveType::Float => {
                            gl::Uniform1fv(idx, count, ptr as *const GLfloat);
                        },
                        UniformPrimitiveType::Int => {
                            gl::Uniform1iv(idx, count, ptr as *const GLint);
                        }
                    }
                },
                UniformDatumType::Vec2(p) => {
                    match p {
                        UniformPrimitiveType::Float => {
                            gl::Uniform2fv(idx, count, ptr as *const GLfloat);
                        },
                        UniformPrimitiveType::Int => {
                            gl::Uniform2iv(idx, count, ptr as *const GLint);
                        }
                    }
                },
                UniformDatumType::Vec3(p) => {
                    match p {
                        UniformPrimitiveType::Float => {
                            gl::Uniform3fv(idx, count, ptr as *const GLfloat);
                        },
                        UniformPrimitiveType::Int => {
                            gl::Uniform3iv(idx, count, ptr as *const GLint);
                        }
                    }
                },
                UniformDatumType::Vec4(p) => {
                    match p {
                        UniformPrimitiveType::Float => {
                            gl::Uniform4fv(idx, count, ptr as *const GLfloat);
                        },
                        UniformPrimitiveType::Int => {
                            gl::Uniform4iv(idx, count, ptr as *const GLint);
                        }
                    }
                },
                UniformDatumType::Matrix2x2 => {
                    gl::UniformMatrix2fv(idx,
                                         count,
                                         gl::FALSE,
                                         ptr as *const GLfloat);
                },
                UniformDatumType::Matrix3x3 => {
                    gl::UniformMatrix3fv(idx,
                                         count,
                                         gl::FALSE,
                                         ptr as *const GLfloat);
                },
                UniformDatumType::Matrix4x4 => {
                    gl::UniformMatrix4fv(idx,
                                         count,
                                         gl::FALSE,
                                         ptr as *const GLfloat);
                },
            }

            dbg_gl_error! {
                GLError::InvalidOperation => "Invalid uniform operation",
                GLError::InvalidValue => "`count` < 0 or `transpose` is not GL_FALSE",
                _ => "Unknown error"
            }
        }
    }
}

pub struct ProgramBinder;
impl ProgramBinder {
    pub fn bind<'a>(&mut self, program: &'a mut Program) -> ProgramBinding<'a>
    {
        let binding = ProgramBinding { phantom: PhantomData };
        unsafe {
            gl::UseProgram(program.gl_id());
            dbg_gl_error! {
                GLError::InvalidValue => "`program` is neither 0 nor an object generated by OpenGL",
                GLError::InvalidOperation => "`program` is not a program object or `program` could not be made part of the current state",
                _ => "Unknown error"
            }
        }
        binding
    }
}

#[derive(Debug, Clone, Copy)]
pub struct ProgramAttrib {
    pub gl_index: GLuint
}

#[derive(Debug, Clone, Copy)]
pub struct ProgramUniform {
    pub gl_index: GLuint
}

#[derive(Debug)]
pub struct UnknownProgramAttrib<'a> {
    name: &'a str
}

impl<'a> fmt::Display for UnknownProgramAttrib<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Unknown program attribute: {:?}", self.name)
    }
}

impl<'a> error::Error for UnknownProgramAttrib<'a> {
    fn description(&self) -> &str {
        "The desired program attribute was not found"
    }
}

#[derive(Debug)]
pub struct UnknownProgramUniform<'a> {
    name: &'a str
}

impl<'a> fmt::Display for UnknownProgramUniform<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Unknown program uniform: {:?}", self.name)
    }
}

impl<'a> error::Error for UnknownProgramUniform<'a> {
    fn description(&self) -> &str {
        "The desired program uniform was not found"
    }
}
<commit_msg>Refactor `ProgramBuilder` to have one generic parameter<commit_after>use std::ptr;
use std::error;
use std::fmt;
use std::borrow::BorrowMut;
use std::marker::PhantomData;
use std::ffi::CString;
use gl;
use gl::types::*;
use types::GLError;
use context::{AContext, ContextOf};
use shader::Shader;
use uniform_data::{UniformData, UniformDatumType, UniformPrimitiveType};

pub struct Program {
    gl_id: GLuint
}

impl Program {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl Drop for Program {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteProgram(self.gl_id);
        }
    }
}

unsafe fn _get_program_iv(program: &Program,
                          pname: GLenum,
                          params: *mut GLint)
{
    gl::GetProgramiv(program.gl_id(), pname, params);
    dbg_gl_sanity_check! {
        GLError::InvalidEnum => "`pname` is not an accepted value",
        GLError::InvalidValue => "`program` is not a value generated by OpenGL",
        GLError::InvalidOperation => "`program` does not refer to a program object",
        _ => "Unknown error"
    }
}

pub struct ProgramBuilder<'a, C>
    where C: AContext + 'a
{
    gl: &'a C,
    shaders: &'a [Shader]
}

impl<'a, C> ProgramBuilder<'a, C>
    where C: AContext
{
    pub fn new(gl: &'a C, shaders: &'a [Shader])
        -> Self
    {
        ProgramBuilder { gl: gl, shaders: shaders }
    }

    pub fn try_unwrap(self) -> Result<Program, GLError> {
        unsafe {
            let mut program = try! {
                self.gl.create_program().or_else(|_| {
                    let msg = "Error creating OpenGL program";
                    Err(GLError::Message(msg.to_owned()))
                })
            };

            for shader in self.shaders {
                self.gl.attach_shader(&mut program, shader);
            }

            try!(self.gl.link_program(&mut program));
            Ok(program)
        }
    }

    pub fn unwrap(self) -> Program {
        self.try_unwrap().unwrap()
    }
}

impl<B, F, P, R, T> ContextOf<B, F, P, R, T> {
    // TODO: Move this method into `ContextProgramExt`
    pub fn build_program<'a>(&'a self, shaders: &'a [Shader])
        -> ProgramBuilder<'a, Self>
    {
        ProgramBuilder::new(self, shaders)
    }
}

pub trait ContextProgramExt {
    unsafe fn create_program(&self) -> Result<Program, ()>;
    fn attach_shader(&self, program: &mut Program, shader: &Shader);
    fn link_program(&self, program: &mut Program) -> Result<(), GLError>;
    fn get_program_info_log(&self, program: &Program) -> Option<String>;
    fn get_attrib_location<'a>(&self, program: &Program, name: &'a str)
        -> Result<ProgramAttrib, UnknownProgramAttrib<'a>>;
    fn get_uniform_location<'a>(&self, program: &Program, name: &'a str)
        -> Result<ProgramUniform, UnknownProgramUniform<'a>>;
}

impl<B, F, P, R, T> ContextProgramExt for ContextOf<B, F, P, R, T> {
    unsafe fn create_program(&self) -> Result<Program, ()> {
        let id = gl::CreateProgram();
        if id > 0 {
            Ok(Program { gl_id: id })
        }
        else {
            Err(())
        }
    }

    fn attach_shader(&self, program: &mut Program, shader: &Shader) {
        unsafe {
            gl::AttachShader(program.gl_id(), shader.gl_id());
            dbg_gl_error! {
                GLError::InvalidValue => "One of either `program` or `shader` is not an OpenGL object",
                GLError::InvalidOperation => "`shader` is already attached to `program`, `shader` is not a shader object, or `program` is not a program object",
                _ => "Unknown error"
            }
        }
    }

    fn link_program(&self, program: &mut Program) -> Result<(), GLError> {
        let success = unsafe {
            gl::LinkProgram(program.gl_id());
            dbg_gl_error! {
                GLError::InvalidValue => "`program` is not a value from OpenGL",
                GLError::InvalidOperation => "`program` is not a program object",
                _ => "Unknown error"
            }

            let mut link_status : GLint = 0;
            _get_program_iv(program,
                            gl::LINK_STATUS,
                            &mut link_status as *mut GLint);

            link_status == gl::TRUE as GLint
        };

        if success {
            Ok(())
        }
        else {
            let msg = match self.get_program_info_log(&program) {
                Some(s) => { s },
                None => { String::from("[Unknown program error]") }
            };
            Err(GLError::Message(msg))
        }
    }

    fn get_program_info_log(&self, program: &Program) -> Option<String> {
        unsafe {
            let mut info_length : GLint = 0;
            _get_program_iv(program,
                            gl::INFO_LOG_LENGTH,
                            &mut info_length as *mut GLint);

            if info_length > 0 {
                let mut bytes = Vec::<u8>::with_capacity(info_length as usize);

                gl::GetProgramInfoLog(program.gl_id(),
                                      info_length,
                                      ptr::null_mut(),
                                      bytes.as_mut_ptr() as *mut GLchar);
                dbg_gl_sanity_check! {
                    GLError::InvalidValue => "`program` is not a value generated by OpenGL, or `maxLength` < 0",
                    GLError::InvalidOperation => "`program` is not a program object",
                    _ => "Unknown error"
                }
                bytes.set_len((info_length - 1) as usize);

                String::from_utf8(bytes).ok()
            }
            else {
                None
            }
        }
    }

    fn get_attrib_location<'a>(&self, program: &Program, name: &'a str)
        -> Result<ProgramAttrib, UnknownProgramAttrib<'a>>
    {
        let err = Err(UnknownProgramAttrib { name: name });

        let c_str = match CString::new(name) {
            Ok(s) => { s },
            Err(_) => { return err }
        };
        // let c_str = try!(CString::new(name).or(Err(e)));
        let str_ptr = c_str.as_ptr() as *const GLchar;
        unsafe {
            let index = gl::GetAttribLocation(program.gl_id(), str_ptr);
            dbg_gl_error! {
                GLError::InvalidOperation => "`program` has not been linked, `program` is not a program object, or `program` is not a value generated by OpenGL",
                _ => "Unknown error"
            }

            if index >= 0 {
                Ok(ProgramAttrib { gl_index: index as GLuint })
            }
            else {
                err
            }
        }
    }

    fn get_uniform_location<'a>(&self, program: &Program, name: &'a str)
        -> Result<ProgramUniform, UnknownProgramUniform<'a>>
    {
        let err = Err(UnknownProgramUniform { name: name });

        let c_str = match CString::new(name) {
            Ok(s) => { s },
            Err(_) => { return err; }
        };
        // let c_str = try!(CString::new(name).or(Err(e)));
        let str_ptr = c_str.as_ptr() as *const GLchar;
        unsafe {
            let index = gl::GetUniformLocation(program.gl_id(), str_ptr);
            dbg_gl_error! {
                GLError::InvalidValue => "`program` is not a value generated by OpenGL",
                GLError::InvalidOperation => "`program` is not a program object, or has not been successfully linked",
                _ => "Unknown error"
            }

            if index >= 0 {
                Ok(ProgramUniform { gl_index: index as GLuint })
            }
            else {
                err
            }
        }
    }
}

// TODO: Add a macro to reduce this boilerplate
impl<'b, B, F, P, R, T> ContextProgramExt for &'b mut ContextOf<B, F, P, R, T> {
    unsafe fn create_program(&self) -> Result<Program, ()> {
        (**self).create_program()
    }

    fn attach_shader(&self, program: &mut Program, shader: &Shader) {
        (**self).attach_shader(program, shader);
    }

    fn link_program(&self, program: &mut Program) -> Result<(), GLError> {
        (**self).link_program(program)
    }

    fn get_program_info_log(&self, program: &Program) -> Option<String> {
        (**self).get_program_info_log(program)
    }

    fn get_attrib_location<'a>(&self, program: &Program, name: &'a str)
        -> Result<ProgramAttrib, UnknownProgramAttrib<'a>>
    {
        (**self).get_attrib_location(program, name)
    }

    fn get_uniform_location<'a>(&self, program: &Program, name: &'a str)
        -> Result<ProgramUniform, UnknownProgramUniform<'a>>
    {
        (**self).get_uniform_location(program, name)
    }
}

pub trait ProgramContext: AContext {
    type Rest: AContext;

    fn use_program<'a>(self, program: &'a mut Program)
        -> (ProgramBinding<'a>, Self::Rest);
}

impl<B, F, P, R, T> ProgramContext for ContextOf<B, F, P, R, T>
    where P: BorrowMut<ProgramBinder>
{
    type Rest = ContextOf<B, F, (), R, T>;

    fn use_program<'a>(self, program: &'a mut Program)
        -> (ProgramBinding<'a>, Self::Rest)
    {
        let (mut program_binder, rest) = self.split_program();
        (program_binder.borrow_mut().bind(program), rest)
    }
}

impl<'b, B, F, P, R, T> ProgramContext for &'b mut ContextOf<B, F, P, R, T>
    where P: BorrowMut<ProgramBinder>
{
    type Rest = ContextOf<&'b mut B, &'b mut F, (), &'b mut R, &'b mut T>;

    fn use_program<'a>(self, program: &'a mut Program)
        -> (ProgramBinding<'a>, Self::Rest)
    {
        let gl = self.mut_into();
        let (program_binder, rest): (&mut P, _) = gl.split_program();
        (program_binder.borrow_mut().bind(program), rest)
    }
}

pub struct ProgramBinding<'a> {
    phantom: PhantomData<&'a mut Program>
}

impl<'a> ProgramBinding<'a> {
    pub fn set_uniform<T>(&self, uniform: ProgramUniform, val: T)
        where T: UniformData
    {
        let idx = uniform.gl_index as GLint;
        let count = val.uniform_elements() as GLsizei;
        let ptr = val.uniform_bytes().as_ptr();
        unsafe {
            match T::uniform_datum_type() {
                UniformDatumType::Vec1(p) => {
                    match p {
                        UniformPrimitiveType::Float => {
                            gl::Uniform1fv(idx, count, ptr as *const GLfloat);
                        },
                        UniformPrimitiveType::Int => {
                            gl::Uniform1iv(idx, count, ptr as *const GLint);
                        }
                    }
                },
                UniformDatumType::Vec2(p) => {
                    match p {
                        UniformPrimitiveType::Float => {
                            gl::Uniform2fv(idx, count, ptr as *const GLfloat);
                        },
                        UniformPrimitiveType::Int => {
                            gl::Uniform2iv(idx, count, ptr as *const GLint);
                        }
                    }
                },
                UniformDatumType::Vec3(p) => {
                    match p {
                        UniformPrimitiveType::Float => {
                            gl::Uniform3fv(idx, count, ptr as *const GLfloat);
                        },
                        UniformPrimitiveType::Int => {
                            gl::Uniform3iv(idx, count, ptr as *const GLint);
                        }
                    }
                },
                UniformDatumType::Vec4(p) => {
                    match p {
                        UniformPrimitiveType::Float => {
                            gl::Uniform4fv(idx, count, ptr as *const GLfloat);
                        },
                        UniformPrimitiveType::Int => {
                            gl::Uniform4iv(idx, count, ptr as *const GLint);
                        }
                    }
                },
                UniformDatumType::Matrix2x2 => {
                    gl::UniformMatrix2fv(idx,
                                         count,
                                         gl::FALSE,
                                         ptr as *const GLfloat);
                },
                UniformDatumType::Matrix3x3 => {
                    gl::UniformMatrix3fv(idx,
                                         count,
                                         gl::FALSE,
                                         ptr as *const GLfloat);
                },
                UniformDatumType::Matrix4x4 => {
                    gl::UniformMatrix4fv(idx,
                                         count,
                                         gl::FALSE,
                                         ptr as *const GLfloat);
                },
            }

            dbg_gl_error! {
                GLError::InvalidOperation => "Invalid uniform operation",
                GLError::InvalidValue => "`count` < 0 or `transpose` is not GL_FALSE",
                _ => "Unknown error"
            }
        }
    }
}

pub struct ProgramBinder;
impl ProgramBinder {
    pub fn bind<'a>(&mut self, program: &'a mut Program) -> ProgramBinding<'a>
    {
        let binding = ProgramBinding { phantom: PhantomData };
        unsafe {
            gl::UseProgram(program.gl_id());
            dbg_gl_error! {
                GLError::InvalidValue => "`program` is neither 0 nor an object generated by OpenGL",
                GLError::InvalidOperation => "`program` is not a program object or `program` could not be made part of the current state",
                _ => "Unknown error"
            }
        }
        binding
    }
}

#[derive(Debug, Clone, Copy)]
pub struct ProgramAttrib {
    pub gl_index: GLuint
}

#[derive(Debug, Clone, Copy)]
pub struct ProgramUniform {
    pub gl_index: GLuint
}

#[derive(Debug)]
pub struct UnknownProgramAttrib<'a> {
    name: &'a str
}

impl<'a> fmt::Display for UnknownProgramAttrib<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Unknown program attribute: {:?}", self.name)
    }
}

impl<'a> error::Error for UnknownProgramAttrib<'a> {
    fn description(&self) -> &str {
        "The desired program attribute was not found"
    }
}

#[derive(Debug)]
pub struct UnknownProgramUniform<'a> {
    name: &'a str
}

impl<'a> fmt::Display for UnknownProgramUniform<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Unknown program uniform: {:?}", self.name)
    }
}

impl<'a> error::Error for UnknownProgramUniform<'a> {
    fn description(&self) -> &str {
        "The desired program uniform was not found"
    }
}
<|endoftext|>


<commit_before>use crate::ast::{Enum, Field, Struct, Variant};
use syn::{Member, Type};

impl Struct<'_> {
    pub(crate) fn from_field(&self) -> Option<&Field> {
        from_field(&self.fields)
    }

    pub(crate) fn source_field(&self) -> Option<&Field> {
        source_field(&self.fields)
    }

    pub(crate) fn backtrace_field(&self) -> Option<&Field> {
        backtrace_field(&self.fields)
    }

    // The #[backtrace] field, if it is not the same as the #[from] field.
    pub(crate) fn distinct_backtrace_field(&self) -> Option<&Field> {
        let backtrace_field = self.backtrace_field()?;
        if self.from_field().map_or(false, |from_field| {
            from_field.member == backtrace_field.member
        }) {
            None
        } else {
            Some(backtrace_field)
        }
    }
}

impl Enum<'_> {
    pub(crate) fn has_source(&self) -> bool {
        self.variants
            .iter()
            .any(|variant| variant.source_field().is_some() || variant.attrs.transparent.is_some())
    }

    pub(crate) fn has_backtrace(&self) -> bool {
        self.variants
            .iter()
            .any(|variant| variant.backtrace_field().is_some())
    }

    pub(crate) fn has_display(&self) -> bool {
        self.attrs.display.is_some()
            || self.attrs.transparent.is_some()
            || self
                .variants
                .iter()
                .any(|variant| variant.attrs.display.is_some())
            || self
                .variants
                .iter()
                .all(|variant| variant.attrs.transparent.is_some())
    }
}

impl Variant<'_> {
    pub(crate) fn from_field(&self) -> Option<&Field> {
        from_field(&self.fields)
    }

    pub(crate) fn source_field(&self) -> Option<&Field> {
        source_field(&self.fields)
    }

    pub(crate) fn backtrace_field(&self) -> Option<&Field> {
        backtrace_field(&self.fields)
    }

    pub(crate) fn distinct_backtrace_field(&self) -> Option<&Field> {
        let backtrace_field = self.backtrace_field()?;
        if self.from_field().map_or(false, |from_field| {
            from_field.member == backtrace_field.member
        }) {
            None
        } else {
            Some(backtrace_field)
        }
    }
}

impl Field<'_> {
    pub(crate) fn is_backtrace(&self) -> bool {
        type_is_backtrace(self.ty)
    }
}

fn from_field<'a, 'b>(fields: &'a [Field<'b>]) -> Option<&'a Field<'b>> {
    for field in fields {
        if field.attrs.from.is_some() {
            return Some(field);
        }
    }
    None
}

fn source_field<'a, 'b>(fields: &'a [Field<'b>]) -> Option<&'a Field<'b>> {
    for field in fields {
        if field.attrs.from.is_some() || field.attrs.source.is_some() {
            return Some(field);
        }
    }
    for field in fields {
        match &field.member {
            Member::Named(ident) if ident == "source" => return Some(field),
            _ => {}
        }
    }
    None
}

fn backtrace_field<'a, 'b>(fields: &'a [Field<'b>]) -> Option<&'a Field<'b>> {
    for field in fields {
        if field.attrs.backtrace.is_some() {
            return Some(field);
        }
    }
    for field in fields {
        if field.is_backtrace() {
            return Some(field);
        }
    }
    None
}

fn type_is_backtrace(ty: &Type) -> bool {
    let path = match ty {
        Type::Path(ty) => &ty.path,
        _ => return false,
    };

    let last = path.segments.last().unwrap();
    last.ident == "Backtrace" && last.arguments.is_empty()
}
<commit_msg>Factor out distinct backtrace logic<commit_after>use crate::ast::{Enum, Field, Struct, Variant};
use syn::{Member, Type};

impl Struct<'_> {
    pub(crate) fn from_field(&self) -> Option<&Field> {
        from_field(&self.fields)
    }

    pub(crate) fn source_field(&self) -> Option<&Field> {
        source_field(&self.fields)
    }

    pub(crate) fn backtrace_field(&self) -> Option<&Field> {
        backtrace_field(&self.fields)
    }

    pub(crate) fn distinct_backtrace_field(&self) -> Option<&Field> {
        let backtrace_field = self.backtrace_field()?;
        distinct_backtrace_field(backtrace_field, self.from_field())
    }
}

impl Enum<'_> {
    pub(crate) fn has_source(&self) -> bool {
        self.variants
            .iter()
            .any(|variant| variant.source_field().is_some() || variant.attrs.transparent.is_some())
    }

    pub(crate) fn has_backtrace(&self) -> bool {
        self.variants
            .iter()
            .any(|variant| variant.backtrace_field().is_some())
    }

    pub(crate) fn has_display(&self) -> bool {
        self.attrs.display.is_some()
            || self.attrs.transparent.is_some()
            || self
                .variants
                .iter()
                .any(|variant| variant.attrs.display.is_some())
            || self
                .variants
                .iter()
                .all(|variant| variant.attrs.transparent.is_some())
    }
}

impl Variant<'_> {
    pub(crate) fn from_field(&self) -> Option<&Field> {
        from_field(&self.fields)
    }

    pub(crate) fn source_field(&self) -> Option<&Field> {
        source_field(&self.fields)
    }

    pub(crate) fn backtrace_field(&self) -> Option<&Field> {
        backtrace_field(&self.fields)
    }

    pub(crate) fn distinct_backtrace_field(&self) -> Option<&Field> {
        let backtrace_field = self.backtrace_field()?;
        distinct_backtrace_field(backtrace_field, self.from_field())
    }
}

impl Field<'_> {
    pub(crate) fn is_backtrace(&self) -> bool {
        type_is_backtrace(self.ty)
    }
}

fn from_field<'a, 'b>(fields: &'a [Field<'b>]) -> Option<&'a Field<'b>> {
    for field in fields {
        if field.attrs.from.is_some() {
            return Some(field);
        }
    }
    None
}

fn source_field<'a, 'b>(fields: &'a [Field<'b>]) -> Option<&'a Field<'b>> {
    for field in fields {
        if field.attrs.from.is_some() || field.attrs.source.is_some() {
            return Some(field);
        }
    }
    for field in fields {
        match &field.member {
            Member::Named(ident) if ident == "source" => return Some(field),
            _ => {}
        }
    }
    None
}

fn backtrace_field<'a, 'b>(fields: &'a [Field<'b>]) -> Option<&'a Field<'b>> {
    for field in fields {
        if field.attrs.backtrace.is_some() {
            return Some(field);
        }
    }
    for field in fields {
        if field.is_backtrace() {
            return Some(field);
        }
    }
    None
}

// The #[backtrace] field, if it is not the same as the #[from] field.
fn distinct_backtrace_field<'a, 'b>(
    backtrace_field: &'a Field<'b>,
    from_field: Option<&Field>,
) -> Option<&'a Field<'b>> {
    if from_field.map_or(false, |from_field| {
        from_field.member == backtrace_field.member
    }) {
        None
    } else {
        Some(backtrace_field)
    }
}

fn type_is_backtrace(ty: &Type) -> bool {
    let path = match ty {
        Type::Path(ty) => &ty.path,
        _ => return false,
    };

    let last = path.segments.last().unwrap();
    last.ident == "Backtrace" && last.arguments.is_empty()
}
<|endoftext|>


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

#[cfg(any(test, feature = "long_benchmarks"))]
pub mod tests;
pub mod codec;
pub mod error;
pub mod network;

use futures::{Async, Poll, Stream};
use futures::stream::Fuse;

use std::time::SystemTime;
use std::cmp::Ordering;

use node::{ExternalMessage, NodeTimeout};

pub use self::network::{NetworkEvent, NetworkRequest};

#[derive(Debug)]
pub enum Event {
    Network(NetworkEvent),
    Timeout(NodeTimeout),
    Api(ExternalMessage),
}

pub trait EventHandler {
    fn handle_event(&mut self, event: Event);
}

#[derive(Debug, PartialEq, Eq)]
pub struct TimeoutRequest(pub SystemTime, pub NodeTimeout);

impl PartialOrd for TimeoutRequest {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for TimeoutRequest {
    fn cmp(&self, other: &Self) -> Ordering {
        (&self.0, &self.1).cmp(&(&other.0, &other.1)).reverse()
    }
}

impl Into<Event> for NetworkEvent {
    fn into(self) -> Event {
        Event::Network(self)
    }
}

impl Into<Event> for NodeTimeout {
    fn into(self) -> Event {
        Event::Timeout(self)
    }
}

impl Into<Event> for ExternalMessage {
    fn into(self) -> Event {
        Event::Api(self)
    }
}

#[derive(Debug)]
pub struct EventsAggregator<S1, S2, S3>
where
    S1: Stream,
    S2: Stream,
    S3: Stream,
{
    timeout: Fuse<S1>,
    network: Fuse<S2>,
    api: Fuse<S3>,
}

impl<S1, S2, S3> EventsAggregator<S1, S2, S3>
where
    S1: Stream,
    S2: Stream,
    S3: Stream,
{
    pub fn new(timeout: S1, network: S2, api: S3) -> EventsAggregator<S1, S2, S3> {
        EventsAggregator {
            network: network.fuse(),
            timeout: timeout.fuse(),
            api: api.fuse(),
        }
    }
}

impl<S1, S2, S3> Stream for EventsAggregator<S1, S2, S3>
where
    S1: Stream<Item = NodeTimeout>,
    S2: Stream<
        Item = NetworkEvent,
        Error = S1::Error,
    >,
    S3: Stream<
        Item = ExternalMessage,
        Error = S1::Error,
    >,
{
    type Item = Event;
    type Error = S1::Error;

    fn poll(&mut self) -> Poll<Option<Event>, Self::Error> {
        let mut stream_finished = false;
        // Check timeout events
        match self.timeout.poll()? {
            Async::Ready(Some(item)) => return Ok(Async::Ready(Some(Event::Timeout(item)))),
            // Just finish stream
            Async::Ready(None) => stream_finished = true,
            Async::NotReady => {}
        };
        // Check network events
        match self.network.poll()? {
            Async::Ready(Some(item)) => return Ok(Async::Ready(Some(Event::Network(item)))),
            // Just finish stream
            Async::Ready(None) => stream_finished = true,
            Async::NotReady => {}
        };
        // Check api events
        match self.api.poll()? {
            Async::Ready(Some(item)) => return Ok(Async::Ready(Some(Event::Api(item)))),
            // Just finish stream
            Async::Ready(None) => stream_finished = true,
            Async::NotReady => {}
        };

        Ok(if stream_finished {
            Async::Ready(None)
        } else {
            Async::NotReady
        })
    }
}
<commit_msg>Remove Fuse wrappers from events module<commit_after>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[cfg(any(test, feature = "long_benchmarks"))]
pub mod tests;
pub mod codec;
pub mod error;
pub mod network;

use futures::{Async, Poll, Stream};

use std::time::SystemTime;
use std::cmp::Ordering;

use node::{ExternalMessage, NodeTimeout};

pub use self::network::{NetworkEvent, NetworkRequest};

#[derive(Debug)]
pub enum Event {
    Network(NetworkEvent),
    Timeout(NodeTimeout),
    Api(ExternalMessage),
}

pub trait EventHandler {
    fn handle_event(&mut self, event: Event);
}

#[derive(Debug, PartialEq, Eq)]
pub struct TimeoutRequest(pub SystemTime, pub NodeTimeout);

impl PartialOrd for TimeoutRequest {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for TimeoutRequest {
    fn cmp(&self, other: &Self) -> Ordering {
        (&self.0, &self.1).cmp(&(&other.0, &other.1)).reverse()
    }
}

impl Into<Event> for NetworkEvent {
    fn into(self) -> Event {
        Event::Network(self)
    }
}

impl Into<Event> for NodeTimeout {
    fn into(self) -> Event {
        Event::Timeout(self)
    }
}

impl Into<Event> for ExternalMessage {
    fn into(self) -> Event {
        Event::Api(self)
    }
}

#[derive(Debug)]
pub struct EventsAggregator<S1, S2, S3>
where
    S1: Stream,
    S2: Stream,
    S3: Stream,
{
    done: bool,
    timeout: S1,
    network: S2,
    api: S3,
}

impl<S1, S2, S3> EventsAggregator<S1, S2, S3>
where
    S1: Stream,
    S2: Stream,
    S3: Stream,
{
    pub fn new(timeout: S1, network: S2, api: S3) -> EventsAggregator<S1, S2, S3> {
        EventsAggregator {
            done: false,
            network: network,
            timeout: timeout,
            api: api,
        }
    }
}

impl<S1, S2, S3> Stream for EventsAggregator<S1, S2, S3>
where
    S1: Stream<Item = NodeTimeout>,
    S2: Stream<
        Item = NetworkEvent,
        Error = S1::Error,
    >,
    S3: Stream<
        Item = ExternalMessage,
        Error = S1::Error,
    >,
{
    type Item = Event;
    type Error = S1::Error;

    fn poll(&mut self) -> Poll<Option<Event>, Self::Error> {
        if self.done {
            Ok(Async::Ready(None))
        } else {
            // Check timeout events
            match self.timeout.poll()? {
                Async::Ready(Some(item)) => {
                    return Ok(Async::Ready(Some(Event::Timeout(item))));
                }
                // Just finish stream
                Async::Ready(None) => {
                    self.done = true;
                    return Ok(Async::Ready(None));
                }
                Async::NotReady => {}
            };
            // Check network events
            match self.network.poll()? {
                Async::Ready(Some(item)) => {
                    return Ok(Async::Ready(Some(Event::Network(item))));
                }
                // Just finish stream
                Async::Ready(None) => {
                    self.done = true;
                    return Ok(Async::Ready(None));
                }
                Async::NotReady => {}
            };
            // Check api events
            match self.api.poll()? {
                Async::Ready(Some(item)) => {
                    return Ok(Async::Ready(Some(Event::Api(item))));
                }
                // Just finish stream
                Async::Ready(None) => {
                    self.done = true;
                    return Ok(Async::Ready(None));
                }
                Async::NotReady => {}
            };

            Ok(Async::NotReady)
        }
    }
}
<|endoftext|>


<commit_before>extern crate pkg_config;

use pkg_config::{Config, Error};
use std::env;
use std::io;
use std::io::prelude::*;
use std::process;

fn main() {
    if cfg!(feature = "use_glib") {
        // This include cairo linker flags
        if let Err(s) = find("cairo-gobject") {
            let _ = writeln!(io::stderr(), "{}", s);
            process::exit(1);
        }
    } else {
        if let Err(s) = find("cairo") {
            let _ = writeln!(io::stderr(), "{}", s);
            process::exit(1);
        }
    }
}

fn find(name: &str) -> Result<(), Error> {
    let package_name = name;
    let shared_libs = [name];
    let version = if cfg!(feature = "1.14") {
        "1.14"
    } else if cfg!(feature = "1.12") {
        "1.12"
    } else {
        "1.10"
    };

    if let Ok(lib_dir) = env::var("GTK_LIB_DIR") {
        for lib_ in shared_libs.iter() {
            println!("cargo:rustc-link-lib=dylib={}", lib_);
        }
        println!("cargo:rustc-link-search=native={}", lib_dir);
        return Ok(());
    }

    let target = env::var("TARGET").unwrap();
    let hardcode_shared_libs = target.contains("windows");

    let mut config = Config::new();
    config.atleast_version(version);
    config.print_system_libs(false);

    if hardcode_shared_libs {
        config.cargo_metadata(false);
    }
    match config.probe(package_name) {
        Ok(library) => {
            if hardcode_shared_libs {
                for lib_ in shared_libs.iter() {
                    println!("cargo:rustc-link-lib=dylib={}", lib_);
                }
                for path in library.link_paths.iter() {
                    println!("cargo:rustc-link-search=native={}", path.to_str().unwrap());
                }
            }
            Ok(())
        }
        Err(Error::EnvNoPkgConfig(_)) | Err(Error::Command { .. }) => {
            for lib_ in shared_libs.iter() {
                println!("cargo:rustc-link-lib=dylib={}", lib_);
            }
            Ok(())
        }
        Err(err) => Err(err),
    }
}
<commit_msg>Fix build.rs if shared libraries are not taken from pkg-config<commit_after>extern crate pkg_config;

use pkg_config::{Config, Error};
use std::env;
use std::io;
use std::io::prelude::*;
use std::process;

fn main() {
    if cfg!(feature = "use_glib") {
        // This include cairo linker flags
        if let Err(s) = find("cairo-gobject", &["cairo", "cairo-gobject"]) {
            let _ = writeln!(io::stderr(), "{}", s);
            process::exit(1);
        }
    } else {
        if let Err(s) = find("cairo", &["cairo"]) {
            let _ = writeln!(io::stderr(), "{}", s);
            process::exit(1);
        }
    }
}

fn find(package_name: &str, shared_libs: &[&str]) -> Result<(), Error> {
    let version = if cfg!(feature = "1.14") {
        "1.14"
    } else if cfg!(feature = "1.12") {
        "1.12"
    } else {
        "1.10"
    };

    if let Ok(lib_dir) = env::var("GTK_LIB_DIR") {
        for lib_ in shared_libs.iter() {
            println!("cargo:rustc-link-lib=dylib={}", lib_);
        }
        println!("cargo:rustc-link-search=native={}", lib_dir);
        return Ok(());
    }

    let target = env::var("TARGET").unwrap();
    let hardcode_shared_libs = target.contains("windows");

    let mut config = Config::new();
    config.atleast_version(version);
    config.print_system_libs(false);

    if hardcode_shared_libs {
        config.cargo_metadata(false);
    }
    match config.probe(package_name) {
        Ok(library) => {
            if hardcode_shared_libs {
                for lib_ in shared_libs.iter() {
                    println!("cargo:rustc-link-lib=dylib={}", lib_);
                }
                for path in library.link_paths.iter() {
                    println!("cargo:rustc-link-search=native={}", path.to_str().unwrap());
                }
            }
            Ok(())
        }
        Err(Error::EnvNoPkgConfig(_)) | Err(Error::Command { .. }) => {
            for lib_ in shared_libs.iter() {
                println!("cargo:rustc-link-lib=dylib={}", lib_);
            }
            Ok(())
        }
        Err(err) => Err(err),
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Justin Noah, All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::net::{IpAddr, SocketAddr, UdpSocket};

use bincode::serde::{deserialize};
use chrono::{UTC};
use rand::{Rng, thread_rng};
use rusqlite::SqliteConnection;

use parse_packets::*;

// struct used by update announce to make passing data easy (vs. 4 more parameters)
struct ID {
    info_hash:  Vec<u8>,
    ip:         u32,
    port:       u16,
    peer_id:    Vec<u8>,
    remaining:  i64,
}

// Generate a UUID to make the client happy
fn gen_uuid() -> i64 {
    let mut rng = thread_rng();
    let mut uuid: i64 = UTC::now().timestamp();
    uuid <<= 32;
    uuid | rng.gen::<u32>() as i64
}

// On announce, update the client's remaining and last_active info
// Get the Seeders and Leechers for the provided info_hash
fn update_announce(conn: &SqliteConnection, id: &ID, data: &ClientAnnounce) -> (Vec<(i32,i32)>,i32, i32) {

    // Update the user info
    conn.execute(
        "INSERT OR REPLACE INTO torrent (info_hash, ip, port, peer_id, remaining, last_active)
        VALUES (?, ?, ?, ?, ?, strftime('%s', 'now'))",
        &[&id.info_hash, &(id.ip as i32), &(id.port as i32),
          &id.peer_id, &id.remaining]
    ).unwrap();

    // Info Hash swarm IP and ports
    // i32 due to current rusqlite type handling
    let mut swarm: Vec<(i32, i32)> = Vec::new();

    // Get Seeders
    let mut stmt = conn.prepare(
        "SELECT ip,port,COUNT(*)
         FROM torrent
         WHERE info_hash = ? AND remaining = 0
         GROUP BY ip,port"
    ).unwrap();
    let mut rows = stmt.query(&[&data.info_hash]).unwrap();

    // Each row produces a count, update it as we continue along
    let mut seeders: i32 = 0;
    while let Some(result_row) = rows.next() {
        let row = result_row.unwrap();
        let i: i32 = row.get(0);
        let p: i32 = row.get(1);
        swarm.push((i,p));
        let c: i32 = row.get(2);
        if c > seeders {
            seeders = c;
        }
    }

    // Get Leechers
    let mut stmt = conn.prepare(
        "SELECT ip,port,COUNT(*)
         FROM torrent
         WHERE info_hash = ? AND remaining > 0
         GROUP BY ip,port"
    ).unwrap();
    let mut rows = stmt.query(&[&data.info_hash]).unwrap();

    // Each row produces a count, update it as we continue along
    let mut leechers: i32 = 0;
    while let Some(result_row) = rows.next() {
        let row = result_row.unwrap();
        let i: i32 = row.get(0);
        let p: i32 = row.get(1);
        swarm.push((i,p));
        let c: i32 = row.get(2);
        if c > leechers {
            leechers = c;
        }
    }

    // Return the swarm, seeders, and leechers for packeting
    (swarm, seeders, leechers)
}

pub fn handle_response(tsock: UdpSocket, src: &SocketAddr, packet: Vec<u8>, conn: &SqliteConnection) {
    // Split the packet into header and body parts
    let mut packet_header = packet;
    let packet_body = packet_header.split_off(16);

    // parse the header to act on it
    let header = parse_header(&packet_header);

    match header.action {
        0 => {
            if header.connection_id == 0x41727101980 {
                // Cool Story, we got a new connection.
                // We need to generate an unique id for this client.
                // 32bits of the current time in nanoseconds combined with 32bits of
                // random numbers
                let uuid = gen_uuid();

                // Now they're in the db, let's say hi
                let encoded = encode_connect_response(uuid, header.transaction_id);
                tsock.send_to(&encoded, src).unwrap();
            }
        },
        1 => {
            // Decode the announce info
            let decoded: ClientAnnounce = decode_client_announce(&packet_body);

            // handle an IP of 0
            let mut ip = decoded.ip;
            if ip == 0 {
                ip = match src.ip() {
                    IpAddr::V4(x) => {
                        deserialize(&x.octets()).unwrap()
                    },
                    _ => panic!("This is possible?")
                };
            }

            // Package up the announce info for DB consumption
            let id = ID {
                info_hash: decoded.info_hash.clone(),
                ip: ip,
                port: decoded.port,
                peer_id: decoded.peer_id.clone(),
                remaining: decoded.remaining,
            };

            // Get the swarm, seeder, and leecher info
            let (swarm, seeders, leechers) = update_announce(conn, &id, &decoded);

            // Send it back to the client
            let serv_announce = encode_server_announce(
                header.transaction_id, swarm, decoded.num_want, leechers, seeders
            );
            tsock.send_to(&serv_announce, src).unwrap();
        },
        _ => {
            let err_packet = encode_error(header.transaction_id, "Unsupported Action");
            tsock.send_to(&err_packet, src).unwrap();
        },
    }
}
<commit_msg>properly use fixed arrays<commit_after>// Copyright 2015 Justin Noah, All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::net::{IpAddr, SocketAddr, UdpSocket};

use bincode::serde::{deserialize};
use chrono::{UTC};
use rand::{Rng, thread_rng};
use rusqlite::SqliteConnection;

use parse_packets::*;

// struct used by update announce to make passing data easy (vs. 4 more parameters)
struct ID {
    info_hash:  Vec<u8>,
    ip:         u32,
    port:       u16,
    peer_id:    Vec<u8>,
    remaining:  i64,
}

// Generate a UUID to make the client happy
fn gen_uuid() -> i64 {
    let mut rng = thread_rng();
    let mut uuid: i64 = UTC::now().timestamp();
    uuid <<= 32;
    uuid | rng.gen::<u32>() as i64
}

// On announce, update the client's remaining and last_active info
// Get the Seeders and Leechers for the provided info_hash
fn update_announce(conn: &SqliteConnection, id: &ID, data: &ClientAnnounce) -> (Vec<(i32,i32)>,i32, i32) {
    // [u8; 20] -> Vec<u8>
    let mut hash: Vec<u8> = Vec::with_capacity(20);
    hash.extend_from_slice(&data.info_hash);

    // Update the user info
    conn.execute(
        "INSERT OR REPLACE INTO torrent (info_hash, ip, port, peer_id, remaining, last_active)
        VALUES (?, ?, ?, ?, ?, strftime('%s', 'now'))",
        &[&id.info_hash, &(id.ip as i32), &(id.port as i32),
          &id.peer_id, &id.remaining]
    ).unwrap();

    // Info Hash swarm IP and ports
    // i32 due to current rusqlite type handling
    let mut swarm: Vec<(i32, i32)> = Vec::new();

    // Get Seeders
    let mut stmt = conn.prepare(
        "SELECT ip,port,COUNT(*)
         FROM torrent
         WHERE info_hash = ? AND remaining = 0
         GROUP BY ip,port"
    ).unwrap();
    let mut rows = stmt.query(&[&hash]).unwrap();

    // Each row produces a count, update it as we continue along
    let mut seeders: i32 = 0;
    while let Some(result_row) = rows.next() {
        let row = result_row.unwrap();
        let i: i32 = row.get(0);
        let p: i32 = row.get(1);
        swarm.push((i,p));
        let c: i32 = row.get(2);
        if c > seeders {
            seeders = c;
        }
    }

    // Get Leechers
    let mut stmt = conn.prepare(
        "SELECT ip,port,COUNT(*)
         FROM torrent
         WHERE info_hash = ? AND remaining > 0
         GROUP BY ip,port"
    ).unwrap();
    let mut rows = stmt.query(&[&hash]).unwrap();

    // Each row produces a count, update it as we continue along
    let mut leechers: i32 = 0;
    while let Some(result_row) = rows.next() {
        let row = result_row.unwrap();
        let i: i32 = row.get(0);
        let p: i32 = row.get(1);
        swarm.push((i,p));
        let c: i32 = row.get(2);
        if c > leechers {
            leechers = c;
        }
    }

    // Return the swarm, seeders, and leechers for packeting
    (swarm, seeders, leechers)
}

pub fn handle_response(tsock: UdpSocket, src: &SocketAddr, packet: Vec<u8>, conn: &SqliteConnection) {
    // Split the packet into header and body parts
    let mut packet_header = packet;
    let packet_body = packet_header.split_off(16);

    // parse the header to act on it
    let header = parse_header(&packet_header);

    match header.action {
        0 => {
            if header.connection_id == 0x41727101980 {
                // Cool Story, we got a new connection.
                // We need to generate an unique id for this client.
                // 32bits of the current time in nanoseconds combined with 32bits of
                // random numbers
                let uuid = gen_uuid();

                // Now they're in the db, let's say hi
                let encoded = encode_connect_response(uuid, header.transaction_id);
                tsock.send_to(&encoded, src).unwrap();
            }
        },
        1 => {
            // Decode the announce info
            let decoded: ClientAnnounce = decode_client_announce(&packet_body);

            // handle an IP of 0
            let mut ip = decoded.ip;
            if ip == 0 {
                ip = match src.ip() {
                    IpAddr::V4(x) => {
                        deserialize(&x.octets()).unwrap()
                    },
                    _ => panic!("This is possible?")
                };
            }

            // Package up the announce info for DB consumption
            let mut hash: Vec<u8> = Vec::with_capacity(20);
            hash.extend_from_slice(&decoded.info_hash);
            let mut peer_id: Vec<u8> = Vec::with_capacity(20);
            peer_id.extend_from_slice(&decoded.peer_id);
            let id = ID {
                info_hash: hash,
                ip: ip,
                port: decoded.port,
                peer_id: peer_id,
                remaining: decoded.remaining,
            };

            // Get the swarm, seeder, and leecher info
            let (swarm, seeders, leechers) = update_announce(conn, &id, &decoded);

            // Send it back to the client
            let serv_announce = encode_server_announce(
                header.transaction_id, swarm, decoded.num_want, leechers, seeders
            );
            tsock.send_to(&serv_announce, src).unwrap();
        },
        _ => {
            let err_packet = encode_error(header.transaction_id, "Unsupported Action");
            tsock.send_to(&err_packet, src).unwrap();
        },
    }
}
<|endoftext|>