<commit_before>use std::io::Read;
use std::ops::RangeInclusive;

use itertools::Itertools;
use itertools::MinMaxResult;
use nom::bytes::complete::tag;
use nom::combinator::map;
use nom::sequence::preceded;
use nom::sequence::separated_pair;
use nom::IResult;

use crate::common::read_input;

#[inline]
fn solve_quadratic(a: f64, b: f64, c: f64) -> Option<f64> {
    let d = b * b - 4. * a * c;

    if d < 0. {
        None
    } else {
        // Don't care about the smaller solution due to problem statement
        Some((-b - d.sqrt()) / 2. / a)
    }
}

fn position(initial: i32, time: i32) -> i32 {
    time * (2 * initial - time + 1) / 2
}

fn find_hit(initial: i32, range: &RangeInclusive<i32>) -> Option<RangeInclusive<i32>> {
    // y position at time x: f(x) = x * (1 + initial + initial - x) / 2
    //                            = -1/2x^2 + (initial + 0.5)x
    //
    // to hit, find x := (max(box) + min(box)) / 2 = f(x)
    //                                             = -1/2x^2 + (initial + 0.5)x
    // -1/2x^2 + (initial + 0.5)x - (max(box) + min(box)) / 2 = 0
    let middle = (*range.start() + *range.end()) as f64 / 2.;
    let b = initial as f64 + 0.5;
    let hit = solve_quadratic(-0.5, b, -middle)? as i32;

    if hit < 0 {
        // Should not happen because of the shape but for correctness
        None
    } else {
        let min_hit = (0..=hit)
            .rev()
            .take_while(|&n| range.contains(&position(initial, n)))
            .min();

        let max_hit = ((hit + 1)..)
            .take_while(|&n| range.contains(&position(initial, n)))
            .max();

        match (min_hit, max_hit) {
            (Some(min), Some(max)) => Some(min..=max),
            (Some(val), None) | (None, Some(val)) => Some(val..=val),
            _ => None,
        }
    }
}

fn find_speed(x: i32, range: &RangeInclusive<i32>) -> Option<RangeInclusive<i32>> {
    let mut min = 0;
    let mut max = *range.end();

    // Need to tweak the formula as x slows down
    let x_pos = |speed| position(speed, speed.min(x));

    while max >= min {
        let speed = (max + min) / 2;

        let pos = x_pos(speed);

        if range.contains(&x_pos(speed)) {
            let min_speed = (0..speed)
                .rev()
                .take_while(|&speed| range.contains(&x_pos(speed)))
                .min()
                .unwrap_or(speed);

            let max_speed = ((speed + 1)..)
                .take_while(|&speed| range.contains(&x_pos(speed)))
                .max()
                .unwrap_or(speed);
            return Some(min_speed..=max_speed);
        } else if pos < *range.start() {
            min = speed + 1;
        } else {
            max = speed - 1;
        }
    }

    None
}

fn parse_range(input: &[u8]) -> IResult<&[u8], RangeInclusive<i32>> {
    use nom::character::complete::i32;

    map(separated_pair(i32, tag(".."), i32), |(start, end)| {
        start..=end
    })(input)
}

fn parse_input(input: &[u8]) -> IResult<&[u8], (RangeInclusive<i32>, RangeInclusive<i32>)> {
    preceded(
        tag("target area: x="),
        separated_pair(parse_range, tag(", y="), parse_range),
    )(input)
}

pub fn part1(input: &mut dyn Read) -> String {
    let (x_range, y_range) = read_input(input, parse_input);

    let check_value = |y_speed| {
        let mut time = find_hit(y_speed, &y_range)?;

        if time.any(|time| find_speed(time, &x_range).is_some()) {
            Some(position(y_speed, y_speed))
        } else {
            None
        }
    };

    debug_assert!(*y_range.start() < 0);
    let y_max = -*y_range.start();

    (0..y_max)
        .filter_map(check_value)
        .max()
        .unwrap()
        .to_string()
}

pub fn part2(input: &mut dyn Read) -> String {
    let (x_range, y_range) = read_input(input, parse_input);

    let num_options = |y_speed| {
        let time = find_hit(y_speed, &y_range)?;
        let range = time
            .filter_map(|time| find_speed(time, &x_range))
            .flat_map(|x| [*x.start(), *x.end()])
            .minmax();

        Some(match range {
            MinMaxResult::NoElements => 0,
            MinMaxResult::OneElement(_) => 1,
            MinMaxResult::MinMax(min, max) => max - min + 1,
        })
    };

    debug_assert!(*y_range.start() < 0);
    let y_max = -*y_range.start();

    (-y_max..y_max)
        .filter_map(num_options)
        .sum::<i32>()
        .to_string()
}

#[cfg(test)]
mod tests {
    use crate::test_implementation;

    use super::*;

    const SAMPLE: &[u8] = &*b"target area: x=20..30, y=-10..-5";

    #[test]
    fn test_find_hit() {
        assert_eq!(find_hit(2, &(-10..=-5)), Some(7..=7));
        assert_eq!(find_hit(3, &(-10..=-5)), Some(9..=9));
        assert_eq!(find_hit(0, &(-10..=-5)), Some(4..=5));
    }

    #[test]
    fn sample_part1() {
        test_implementation(part1, SAMPLE, 45);
    }

    #[test]
    fn sample_part2() {
        test_implementation(part2, SAMPLE, 112);
    }
}
<commit_msg>Use math instead of binary search<commit_after>use std::io::Read;
use std::ops::RangeInclusive;

use itertools::Itertools;
use itertools::MinMaxResult;
use nom::bytes::complete::tag;
use nom::combinator::map;
use nom::sequence::preceded;
use nom::sequence::separated_pair;
use nom::IResult;

use crate::common::read_input;

#[inline]
fn solve_quadratic(a: f64, b: f64, c: f64) -> Option<f64> {
    let d = b * b - 4. * a * c;

    if d < 0. {
        None
    } else {
        // Don't care about the smaller solution due to problem statement
        if a > 0. {
            Some((-b + d.sqrt()) / 2. / a)
        } else {
            Some((-b - d.sqrt()) / 2. / a)
        }
    }
}

fn position(initial: i32, time: i32) -> i32 {
    time * (2 * initial - time + 1) / 2
}

fn find_hit(initial: i32, range: &RangeInclusive<i32>) -> Option<RangeInclusive<i32>> {
    // y position at time x: f(x) = x * (1 + initial + initial - x) / 2
    //                            = -1/2x^2 + (initial + 0.5)x
    //
    // to hit, find x := (max(box) + min(box)) / 2 = f(x)
    //                                             = -1/2x^2 + (initial + 0.5)x
    // -1/2x^2 + (initial + 0.5)x - (max(box) + min(box)) / 2 = 0
    let middle = (*range.start() + *range.end()) as f64 / 2.;
    let b = initial as f64 + 0.5;
    let hit = solve_quadratic(-0.5, b, -middle)? as i32;

    if hit < 0 {
        // Should not happen because of the shape but for correctness
        None
    } else {
        let min_hit = (0..=hit)
            .rev()
            .take_while(|&n| range.contains(&position(initial, n)))
            .min();

        let max_hit = ((hit + 1)..)
            .take_while(|&n| range.contains(&position(initial, n)))
            .max();

        match (min_hit, max_hit) {
            (Some(min), Some(max)) => Some(min..=max),
            (Some(val), None) | (None, Some(val)) => Some(val..=val),
            _ => None,
        }
    }
}

fn find_speed(x: i32, range: &RangeInclusive<i32>) -> Option<RangeInclusive<i32>> {
    if *range.end() <= position(x, x) {
        // Can and should come to a full stop
        let max = solve_quadratic(0.5, 0.5, -*range.end() as f64)? as i32;

        let min = (0..=max)
            .rev()
            .take_while(|&n| range.contains(&position(n, n)))
            .last()?;

        Some(min..=max)
    } else {
        // Might hit the target at speed
        let max = (x * x + 2 * *range.end() - x) / (2 * x);

        let min = (0..=max)
            .rev()
            .take_while(|&n| range.contains(&position(n, n.min(x))))
            .last()?;

        Some(min..=max)
    }
}

fn parse_range(input: &[u8]) -> IResult<&[u8], RangeInclusive<i32>> {
    use nom::character::complete::i32;

    map(separated_pair(i32, tag(".."), i32), |(start, end)| {
        start..=end
    })(input)
}

fn parse_input(input: &[u8]) -> IResult<&[u8], (RangeInclusive<i32>, RangeInclusive<i32>)> {
    preceded(
        tag("target area: x="),
        separated_pair(parse_range, tag(", y="), parse_range),
    )(input)
}

pub fn part1(input: &mut dyn Read) -> String {
    let (x_range, y_range) = read_input(input, parse_input);

    let check_value = |y_speed| {
        let mut time = find_hit(y_speed, &y_range)?;

        if time.any(|time| find_speed(time, &x_range).is_some()) {
            Some(position(y_speed, y_speed))
        } else {
            None
        }
    };

    debug_assert!(*y_range.start() < 0);
    let y_max = -*y_range.start();

    (0..y_max)
        .filter_map(check_value)
        .max()
        .unwrap()
        .to_string()
}

pub fn part2(input: &mut dyn Read) -> String {
    let (x_range, y_range) = read_input(input, parse_input);

    let num_options = |y_speed| {
        let time = find_hit(y_speed, &y_range)?;
        let range = time
            .filter_map(|time| find_speed(time, &x_range))
            .flat_map(|x| [*x.start(), *x.end()])
            .minmax();

        Some(match range {
            MinMaxResult::NoElements => 0,
            MinMaxResult::OneElement(_) => 1,
            MinMaxResult::MinMax(min, max) => max - min + 1,
        })
    };

    debug_assert!(*y_range.start() < 0);
    let y_max = -*y_range.start();

    (-y_max..y_max)
        .filter_map(num_options)
        .sum::<i32>()
        .to_string()
}

#[cfg(test)]
mod tests {
    use crate::test_implementation;

    use super::*;

    const SAMPLE: &[u8] = &*b"target area: x=20..30, y=-10..-5";

    #[test]
    fn test_find_hit() {
        assert_eq!(find_hit(2, &(-10..=-5)), Some(7..=7));
        assert_eq!(find_hit(3, &(-10..=-5)), Some(9..=9));
        assert_eq!(find_hit(0, &(-10..=-5)), Some(4..=5));
    }

    #[test]
    fn sample_part1() {
        test_implementation(part1, SAMPLE, 45);
    }

    #[test]
    fn sample_part2() {
        test_implementation(part2, SAMPLE, 112);
    }
}
<|endoftext|>


<commit_before>use std::io::Read;

use crate::common::LineIter;

fn read_input(input: &mut dyn Read) -> (i32, i32) {
    let mut reader = LineIter::new(input);

    let a = reader
        .next()
        .unwrap()
        .split(' ')
        .last()
        .unwrap()
        .parse()
        .unwrap();

    let b = reader
        .next()
        .unwrap()
        .split(' ')
        .last()
        .unwrap()
        .parse()
        .unwrap();

    (a, b)
}

#[inline]
fn simulate(die: i32, pos: i32) -> i32 {
    (pos + 3 * die + 3 - 1) % 10 + 1
}

fn find_repetition(mut pos: i32, mut die: i32) -> i32 {
    let mut advance = 0;

    for _ in 0..10 {
        pos = simulate(die, pos);
        advance += pos;
        die = (die + 6) % 10;
    }

    advance
}

pub fn part1(input: &mut dyn Read) -> String {
    const TARGET_SCORE: i32 = 1000;

    let (a, b) = read_input(input);

    let a10 = find_repetition(a, 1);
    let b10 = find_repetition(b, 4);

    let a_win = TARGET_SCORE / a10;
    let b_win = TARGET_SCORE / b10;

    let mut rolls = 3 * 20 * a_win.min(b_win);
    let mut a_score = rolls / 3 / 20 * a10;
    let mut b_score = rolls / 3 / 20 * b10;
    let mut a_pos = a;
    let mut b_pos = b;
    let mut die = 1;

    let (loser_score, rolls) = if a_win < b_win {
        while a_score < TARGET_SCORE {
            a_pos = simulate(die, a_pos);
            a_score += a_pos;
            rolls += 3;

            if a_score < TARGET_SCORE {
                b_pos = simulate(die + 3, b_pos);
                b_score += b_pos;
                rolls += 3;
            }

            die = (die + 6) % 10;
        }

        (b_score, rolls)
    } else {
        while b_score < TARGET_SCORE {
            a_pos = simulate(die, a_pos);
            a_score += a_pos;

            b_pos = simulate(die + 3, b_pos);
            b_score += b_pos;

            rolls += 6;

            die = (die + 6) % 10;
        }

        (a_score, rolls)
    };

    (loser_score * rolls).to_string()
}

const MAX_TURNS: usize = 13;
const ROLLS: [i32; 7] = [3, 4, 5, 6, 7, 8, 9];
const FREQS: [u64; 7] = [1, 3, 6, 7, 6, 3, 1];

fn multiverse(pos: i32) -> ([u64; MAX_TURNS], [u64; MAX_TURNS]) {
    type State = [[u64; 10]; 21];

    // Let's work with pos - 1 as pos for now, indexes nicer;
    let pos = pos as usize - 1;

    let mut alive = [0; MAX_TURNS];
    let mut wins = [0; MAX_TURNS];

    alive[0] = 1;

    let mut current = [[0u64; 10]; 21];
    current[0][pos] = 1;
    let mut next = [[0u64; 10]; 21];

    let mut helper = |turn, current: &State, next: &mut State| {
        next.iter_mut().flatten().for_each(|v| *v = 0);

        for (score, score_row) in current.iter().enumerate() {
            for (pos, &pop) in score_row.iter().enumerate() {
                for (roll, freq) in ROLLS.into_iter().zip(FREQS) {
                    let new_pos = (pos + (roll as usize)) % 10;
                    let new_score = score + new_pos + 1; // +1 because above
                    let new_pop = freq * pop;

                    if new_score >= next.len() {
                        wins[turn] += new_pop;
                    } else {
                        alive[turn] += new_pop;
                        next[new_score][new_pos] += new_pop;
                    }
                }
            }
        }
    };

    for turn in (1..MAX_TURNS).step_by(2) {
        helper(turn, &current, &mut next);
        helper(turn + 1, &next, &mut current);
    }

    (wins, alive)
}

pub fn part2(input: &mut dyn Read) -> String {
    let (a, b) = read_input(input);

    let (a_wins, a_alive) = multiverse(a);
    let (b_wins, b_alive) = multiverse(b);

    let a_winner: u64 = a_wins[1..].iter().zip(b_alive).map(|(&a, b)| a * b).sum();
    let b_winner: u64 = b_wins.into_iter().zip(a_alive).map(|(a, b)| a * b).sum();

    a_winner.max(b_winner).to_string()
}

#[cfg(test)]
mod tests {
    use crate::test_implementation;

    use super::*;

    const SAMPLE: &[u8] = include_bytes!("samples/21.txt");

    #[test]
    fn sample_part1() {
        test_implementation(part1, SAMPLE, 739785);
    }

    #[test]
    fn sample_part2() {
        test_implementation(part2, SAMPLE, 444356092776315u64);
    }
}
<commit_msg>Reduce code duplication<commit_after>use std::io::Read;

use crate::common::LineIter;

fn read_input(input: &mut dyn Read) -> (i32, i32) {
    let mut reader = LineIter::new(input);

    let mut helper = || {
        reader
            .next()
            .unwrap()
            .split(' ')
            .last()
            .unwrap()
            .parse()
            .unwrap()
    };

    let a = helper();
    let b = helper();

    (a, b)
}

#[inline]
fn simulate(die: i32, pos: i32) -> i32 {
    (pos + 3 * die + 3 - 1) % 10 + 1
}

fn find_repetition(mut pos: i32, mut die: i32) -> i32 {
    let mut advance = 0;

    for _ in 0..10 {
        pos = simulate(die, pos);
        advance += pos;
        die = (die + 6) % 10;
    }

    advance
}

pub fn part1(input: &mut dyn Read) -> String {
    const TARGET_SCORE: i32 = 1000;

    let (mut a, mut b) = read_input(input);

    let a10 = find_repetition(a, 1);
    let b10 = find_repetition(b, 4);

    let a_win = TARGET_SCORE / a10;
    let b_win = TARGET_SCORE / b10;

    let win = a_win.min(b_win);
    let mut a_score = win * a10;
    let mut b_score = win * b10;
    let mut die = 1;
    let mut rolls = 3 * 20 * win;

    let (loser_score, rolls) = if a_win < b_win {
        while a_score < TARGET_SCORE {
            a = simulate(die, a);
            a_score += a;
            rolls += 3;

            if a_score < TARGET_SCORE {
                b = simulate(die + 3, b);
                b_score += b;
                rolls += 3;
            }

            die = (die + 6) % 10;
        }

        (b_score, rolls)
    } else {
        while b_score < TARGET_SCORE {
            a = simulate(die, a);
            a_score += a;

            b = simulate(die + 3, b);
            b_score += b;

            rolls += 6;

            die = (die + 6) % 10;
        }

        (a_score, rolls)
    };

    (loser_score * rolls).to_string()
}

const MAX_TURNS: usize = 13;
const ROLLS: [i32; 7] = [3, 4, 5, 6, 7, 8, 9];
const FREQS: [u64; 7] = [1, 3, 6, 7, 6, 3, 1];

fn multiverse(pos: i32) -> ([u64; MAX_TURNS], [u64; MAX_TURNS]) {
    type State = [[u64; 10]; 21];

    // Let's work with pos - 1 as pos for now, indexes nicer;
    let pos = pos as usize - 1;

    let mut alive = [0; MAX_TURNS];
    let mut wins = [0; MAX_TURNS];

    alive[0] = 1;

    let mut current = [[0u64; 10]; 21];
    current[0][pos] = 1;
    let mut next = [[0u64; 10]; 21];

    let mut helper = |turn, current: &State, next: &mut State| {
        next.iter_mut().flatten().for_each(|v| *v = 0);

        for (score, score_row) in current.iter().enumerate() {
            for (pos, &pop) in score_row.iter().enumerate() {
                for (roll, freq) in ROLLS.into_iter().zip(FREQS) {
                    let new_pos = (pos + (roll as usize)) % 10;
                    let new_score = score + new_pos + 1; // +1 because above
                    let new_pop = freq * pop;

                    if new_score >= next.len() {
                        wins[turn] += new_pop;
                    } else {
                        alive[turn] += new_pop;
                        next[new_score][new_pos] += new_pop;
                    }
                }
            }
        }
    };

    for turn in (1..MAX_TURNS).step_by(2) {
        helper(turn, &current, &mut next);
        helper(turn + 1, &next, &mut current);
    }

    (wins, alive)
}

pub fn part2(input: &mut dyn Read) -> String {
    let (a, b) = read_input(input);

    let (a_wins, a_alive) = multiverse(a);
    let (b_wins, b_alive) = multiverse(b);

    let a_winner: u64 = a_wins[1..].iter().zip(b_alive).map(|(&a, b)| a * b).sum();
    let b_winner: u64 = b_wins.into_iter().zip(a_alive).map(|(a, b)| a * b).sum();

    a_winner.max(b_winner).to_string()
}

#[cfg(test)]
mod tests {
    use crate::test_implementation;

    use super::*;

    const SAMPLE: &[u8] = include_bytes!("samples/21.txt");

    #[test]
    fn sample_part1() {
        test_implementation(part1, SAMPLE, 739785);
    }

    #[test]
    fn sample_part2() {
        test_implementation(part2, SAMPLE, 444356092776315u64);
    }
}
<|endoftext|>


<commit_before>use tls::*;

pub enum StateChangeError {
    InvalidTransition,
    ParseError,
}

#[derive(Copy,Clone,Debug,PartialEq)]
pub enum TlsState {
    None,
    ClientHello,
    AskResumeSession,
    ResumeSession,
    ServerHello,
    Certificate,
    ServerKeyExchange,
    ServerHelloDone,
    ClientKeyExchange,
    ClientChangeCipherSpec,

    CRCertRequest,
    CRHelloDone,
    CRCert,
    CRClientKeyExchange,
    CRCertVerify,

    NoCertSKE,
    NoCertHelloDone,
    NoCertCKE,

    SessionEncrypted,

    Alert,

    Invalid,
}

pub fn tls_state_transition_handshake(state: TlsState, msg: &TlsMessageHandshake) -> Result<TlsState,StateChangeError> {
    match (state,msg) {
        (TlsState::None,             &TlsMessageHandshake::ClientHello(ref msg)) => {
            match msg.session_id {
                Some(_) => Ok(TlsState::AskResumeSession),
                _       => Ok(TlsState::ClientHello)
            }
        },
        // Server certificate
        (TlsState::ClientHello,      &TlsMessageHandshake::ServerHello(_))       => Ok(TlsState::ServerHello),
        (TlsState::ServerHello,      &TlsMessageHandshake::Certificate(_))       => Ok(TlsState::Certificate),
        // Server certificate, no client certificate requested
        (TlsState::Certificate,      &TlsMessageHandshake::ServerKeyExchange(_)) => Ok(TlsState::ServerKeyExchange),
        (TlsState::ServerKeyExchange,&TlsMessageHandshake::ServerDone(_))        => Ok(TlsState::ServerHelloDone),
        (TlsState::ServerHelloDone  ,&TlsMessageHandshake::ClientKeyExchange(_)) => Ok(TlsState::ClientKeyExchange),
        // Server certificate, client certificate requested
        (TlsState::Certificate,      &TlsMessageHandshake::CertificateRequest(_))=> Ok(TlsState::CRCertRequest),
        (TlsState::ServerKeyExchange,&TlsMessageHandshake::CertificateRequest(_))=> Ok(TlsState::CRCertRequest),
        (TlsState::CRCertRequest,    &TlsMessageHandshake::ServerDone(_))        => Ok(TlsState::CRHelloDone),
        (TlsState::CRHelloDone,      &TlsMessageHandshake::Certificate(_))       => Ok(TlsState::CRCert),
        (TlsState::CRCert,           &TlsMessageHandshake::ClientKeyExchange(_)) => Ok(TlsState::CRClientKeyExchange),
        (TlsState::CRClientKeyExchange, &TlsMessageHandshake::CertificateVerify(_)) => Ok(TlsState::CRCertVerify),
        // Server has no certificate (but accepts anonymous)
        (TlsState::ServerHello,      &TlsMessageHandshake::ServerKeyExchange(_)) => Ok(TlsState::NoCertSKE),
        (TlsState::NoCertSKE,        &TlsMessageHandshake::ServerDone(_))        => Ok(TlsState::NoCertHelloDone),
        (TlsState::NoCertHelloDone,  &TlsMessageHandshake::ClientKeyExchange(_)) => Ok(TlsState::NoCertCKE),
        // Resuming session
        (TlsState::AskResumeSession, &TlsMessageHandshake::ServerHello(_))       => Ok(TlsState::ResumeSession),
        // All other transitions are considered invalid
        _ => Err(StateChangeError::InvalidTransition),
    }
}

pub fn tls_state_transition(state: TlsState, msg: &TlsMessage) -> Result<TlsState,StateChangeError> {
    match (state,msg) {
        (TlsState::Invalid,_) => Ok(TlsState::Invalid),
        (_,&TlsMessage::Handshake(ref m)) => tls_state_transition_handshake(state,m),
        // Server certificate
        (TlsState::ClientKeyExchange,     &TlsMessage::ChangeCipherSpec) => Ok(TlsState::ClientChangeCipherSpec),
        (TlsState::ClientChangeCipherSpec,&TlsMessage::ChangeCipherSpec) => Ok(TlsState::SessionEncrypted),
        // Server certificate, client certificate requested
        (TlsState::CRClientKeyExchange,   &TlsMessage::ChangeCipherSpec) => Ok(TlsState::ClientChangeCipherSpec),
        (TlsState::CRCertVerify,          &TlsMessage::ChangeCipherSpec) => Ok(TlsState::ClientChangeCipherSpec),
        // No server certificate
        (TlsState::NoCertCKE,             &TlsMessage::ChangeCipherSpec) => Ok(TlsState::ClientChangeCipherSpec),
        // Resume session
        (TlsState::ResumeSession,         &TlsMessage::ChangeCipherSpec) => Ok(TlsState::ClientChangeCipherSpec),
        (_,_) => Err(StateChangeError::InvalidTransition),
    }
}
<commit_msg>Support HelloRequest in state machine<commit_after>use tls::*;

pub enum StateChangeError {
    InvalidTransition,
    ParseError,
}

#[derive(Copy,Clone,Debug,PartialEq)]
pub enum TlsState {
    None,
    ClientHello,
    AskResumeSession,
    ResumeSession,
    ServerHello,
    Certificate,
    ServerKeyExchange,
    ServerHelloDone,
    ClientKeyExchange,
    ClientChangeCipherSpec,

    CRCertRequest,
    CRHelloDone,
    CRCert,
    CRClientKeyExchange,
    CRCertVerify,

    NoCertSKE,
    NoCertHelloDone,
    NoCertCKE,

    SessionEncrypted,

    Alert,

    Invalid,
}

pub fn tls_state_transition_handshake(state: TlsState, msg: &TlsMessageHandshake) -> Result<TlsState,StateChangeError> {
    match (state,msg) {
        (TlsState::None,             &TlsMessageHandshake::ClientHello(ref msg)) => {
            match msg.session_id {
                Some(_) => Ok(TlsState::AskResumeSession),
                _       => Ok(TlsState::ClientHello)
            }
        },
        // Server certificate
        (TlsState::ClientHello,      &TlsMessageHandshake::ServerHello(_))       => Ok(TlsState::ServerHello),
        (TlsState::ServerHello,      &TlsMessageHandshake::Certificate(_))       => Ok(TlsState::Certificate),
        // Server certificate, no client certificate requested
        (TlsState::Certificate,      &TlsMessageHandshake::ServerKeyExchange(_)) => Ok(TlsState::ServerKeyExchange),
        (TlsState::ServerKeyExchange,&TlsMessageHandshake::ServerDone(_))        => Ok(TlsState::ServerHelloDone),
        (TlsState::ServerHelloDone  ,&TlsMessageHandshake::ClientKeyExchange(_)) => Ok(TlsState::ClientKeyExchange),
        // Server certificate, client certificate requested
        (TlsState::Certificate,      &TlsMessageHandshake::CertificateRequest(_))=> Ok(TlsState::CRCertRequest),
        (TlsState::ServerKeyExchange,&TlsMessageHandshake::CertificateRequest(_))=> Ok(TlsState::CRCertRequest),
        (TlsState::CRCertRequest,    &TlsMessageHandshake::ServerDone(_))        => Ok(TlsState::CRHelloDone),
        (TlsState::CRHelloDone,      &TlsMessageHandshake::Certificate(_))       => Ok(TlsState::CRCert),
        (TlsState::CRCert,           &TlsMessageHandshake::ClientKeyExchange(_)) => Ok(TlsState::CRClientKeyExchange),
        (TlsState::CRClientKeyExchange, &TlsMessageHandshake::CertificateVerify(_)) => Ok(TlsState::CRCertVerify),
        // Server has no certificate (but accepts anonymous)
        (TlsState::ServerHello,      &TlsMessageHandshake::ServerKeyExchange(_)) => Ok(TlsState::NoCertSKE),
        (TlsState::NoCertSKE,        &TlsMessageHandshake::ServerDone(_))        => Ok(TlsState::NoCertHelloDone),
        (TlsState::NoCertHelloDone,  &TlsMessageHandshake::ClientKeyExchange(_)) => Ok(TlsState::NoCertCKE),
        // Resuming session
        (TlsState::AskResumeSession, &TlsMessageHandshake::ServerHello(_))       => Ok(TlsState::ResumeSession),
        // Hello requests must be accepted at any time (except start), but ignored [RFC5246] 7.4.1.1
        (TlsState::None,             &TlsMessageHandshake::HelloRequest)         => Err(StateChangeError::InvalidTransition),
        (s,                          &TlsMessageHandshake::HelloRequest)         => Ok(s),
        // All other transitions are considered invalid
        _ => Err(StateChangeError::InvalidTransition),
    }
}

pub fn tls_state_transition(state: TlsState, msg: &TlsMessage) -> Result<TlsState,StateChangeError> {
    match (state,msg) {
        (TlsState::Invalid,_) => Ok(TlsState::Invalid),
        (_,&TlsMessage::Handshake(ref m)) => tls_state_transition_handshake(state,m),
        // Server certificate
        (TlsState::ClientKeyExchange,     &TlsMessage::ChangeCipherSpec) => Ok(TlsState::ClientChangeCipherSpec),
        (TlsState::ClientChangeCipherSpec,&TlsMessage::ChangeCipherSpec) => Ok(TlsState::SessionEncrypted),
        // Server certificate, client certificate requested
        (TlsState::CRClientKeyExchange,   &TlsMessage::ChangeCipherSpec) => Ok(TlsState::ClientChangeCipherSpec),
        (TlsState::CRCertVerify,          &TlsMessage::ChangeCipherSpec) => Ok(TlsState::ClientChangeCipherSpec),
        // No server certificate
        (TlsState::NoCertCKE,             &TlsMessage::ChangeCipherSpec) => Ok(TlsState::ClientChangeCipherSpec),
        // Resume session
        (TlsState::ResumeSession,         &TlsMessage::ChangeCipherSpec) => Ok(TlsState::ClientChangeCipherSpec),
        (_,_) => Err(StateChangeError::InvalidTransition),
    }
}
<|endoftext|>


<commit_before>//! Topic name

use std::convert::Into;
use std::error::Error;
use std::fmt;
use std::io::{Read, Write};
use std::ops::Deref;

use lazy_static::lazy_static;
use regex::Regex;

use crate::encodable::StringEncodeError;
use crate::{Decodable, Encodable};

const TOPIC_NAME_VALIDATE_REGEX: &str = r"^[^#+]+$";

lazy_static! {
    static ref TOPIC_NAME_VALIDATOR: Regex = Regex::new(TOPIC_NAME_VALIDATE_REGEX).unwrap();
}

#[inline]
fn is_invalid_topic_name(topic_name: &str) -> bool {
    topic_name.is_empty()
        || topic_name.as_bytes().len() > 65535
        || !TOPIC_NAME_VALIDATOR.is_match(&topic_name)
}

/// Topic name
///
/// http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718106
#[derive(Debug, Eq, PartialEq, Clone, Hash, Ord, PartialOrd)]
pub struct TopicName(String);

impl TopicName {
    /// Creates a new topic name from string
    /// Return error if the string is not a valid topic name
    pub fn new<S: Into<String>>(topic_name: S) -> Result<TopicName, TopicNameError> {
        let topic_name = topic_name.into();
        if is_invalid_topic_name(&topic_name) {
            Err(TopicNameError::InvalidTopicName(topic_name))
        } else {
            Ok(TopicName(topic_name))
        }
    }

    /// Creates a new topic name from string without validation
    ///
    /// # Safety
    ///
    /// Topic names' syntax is defined in [MQTT specification](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718106).
    /// Creating a name from raw string may cause errors
    pub unsafe fn new_unchecked(topic_name: String) -> TopicName {
        TopicName(topic_name)
    }
}

impl From<TopicName> for String {
    fn into(topic_name: TopicName) -> String {
        topic_name.0
    }
}

impl Deref for TopicName {
    type Target = TopicNameRef;

    fn deref(&self) -> &TopicNameRef {
        unsafe { TopicNameRef::new_unchecked(&self.0) }
    }
}

impl Encodable for TopicName {
    type Err = TopicNameError;

    fn encode<W: Write>(&self, writer: &mut W) -> Result<(), TopicNameError> {
        (&self.0[..])
            .encode(writer)
            .map_err(TopicNameError::StringEncodeError)
    }

    fn encoded_length(&self) -> u32 {
        (&self.0[..]).encoded_length()
    }
}

impl Decodable for TopicName {
    type Err = TopicNameError;
    type Cond = ();

    fn decode_with<R: Read>(
        reader: &mut R,
        _rest: Option<()>,
    ) -> Result<TopicName, TopicNameError> {
        let topic_name: String =
            Decodable::decode(reader).map_err(TopicNameError::StringEncodeError)?;
        TopicName::new(topic_name)
    }
}

/// Errors while parsing topic names
#[derive(Debug)]
pub enum TopicNameError {
    StringEncodeError(StringEncodeError),
    InvalidTopicName(String),
}

impl fmt::Display for TopicNameError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            TopicNameError::StringEncodeError(ref err) => err.fmt(f),
            TopicNameError::InvalidTopicName(ref topic) => {
                write!(f, "Invalid topic filter ({})", topic)
            }
        }
    }
}

impl Error for TopicNameError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        match *self {
            TopicNameError::StringEncodeError(ref err) => Some(err),
            TopicNameError::InvalidTopicName(..) => None,
        }
    }
}

/// Reference to a topic name
#[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct TopicNameRef(str);

impl TopicNameRef {
    /// Creates a new topic name from string
    /// Return error if the string is not a valid topic name
    pub fn new<S: AsRef<str> + ?Sized>(topic_name: &S) -> Result<&TopicNameRef, TopicNameError> {
        let topic_name = topic_name.as_ref();
        if is_invalid_topic_name(&topic_name) {
            Err(TopicNameError::InvalidTopicName(topic_name.to_owned()))
        } else {
            Ok(unsafe { &*(topic_name as *const str as *const TopicNameRef) })
        }
    }

    /// Creates a new topic name from string without validation
    ///
    /// # Safety
    ///
    /// Topic names' syntax is defined in [MQTT specification](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718106).
    /// Creating a name from raw string may cause errors
    pub unsafe fn new_unchecked<S: AsRef<str> + ?Sized>(topic_name: &S) -> &TopicNameRef {
        let topic_name = topic_name.as_ref();
        &*(topic_name as *const str as *const TopicNameRef)
    }

    /// Check if this topic name is only for server.
    ///
    /// Topic names that beginning with a '$' character are reserved for servers
    pub fn is_server_specific(&self) -> bool {
        self.0.starts_with('$')
    }
}

impl Deref for TopicNameRef {
    type Target = str;

    fn deref(&self) -> &str {
        &self.0
    }
}

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

    #[test]
    fn topic_name_sys() {
        let topic_name = "$SYS".to_owned();
        TopicName::new(topic_name).unwrap();

        let topic_name = "$SYS/broker/connection/test.cosm-energy/state".to_owned();
        TopicName::new(topic_name).unwrap();
    }

    #[test]
    fn topic_name_slash() {
        TopicName::new("/").unwrap();
    }

    #[test]
    fn topic_name_basic() {
        TopicName::new("/finance").unwrap();
        TopicName::new("/finance//def").unwrap();
    }
}
<commit_msg>Fix From<> implementation<commit_after>//! Topic name

use std::convert::Into;
use std::error::Error;
use std::fmt;
use std::io::{Read, Write};
use std::ops::Deref;

use lazy_static::lazy_static;
use regex::Regex;

use crate::encodable::StringEncodeError;
use crate::{Decodable, Encodable};

const TOPIC_NAME_VALIDATE_REGEX: &str = r"^[^#+]+$";

lazy_static! {
    static ref TOPIC_NAME_VALIDATOR: Regex = Regex::new(TOPIC_NAME_VALIDATE_REGEX).unwrap();
}

#[inline]
fn is_invalid_topic_name(topic_name: &str) -> bool {
    topic_name.is_empty()
        || topic_name.as_bytes().len() > 65535
        || !TOPIC_NAME_VALIDATOR.is_match(&topic_name)
}

/// Topic name
///
/// http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718106
#[derive(Debug, Eq, PartialEq, Clone, Hash, Ord, PartialOrd)]
pub struct TopicName(String);

impl TopicName {
    /// Creates a new topic name from string
    /// Return error if the string is not a valid topic name
    pub fn new<S: Into<String>>(topic_name: S) -> Result<TopicName, TopicNameError> {
        let topic_name = topic_name.into();
        if is_invalid_topic_name(&topic_name) {
            Err(TopicNameError::InvalidTopicName(topic_name))
        } else {
            Ok(TopicName(topic_name))
        }
    }

    /// Creates a new topic name from string without validation
    ///
    /// # Safety
    ///
    /// Topic names' syntax is defined in [MQTT specification](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718106).
    /// Creating a name from raw string may cause errors
    pub unsafe fn new_unchecked(topic_name: String) -> TopicName {
        TopicName(topic_name)
    }
}

impl From<TopicName> for String {
    fn from(topic_name: TopicName) -> String {
        topic_name.0
    }
}

impl Deref for TopicName {
    type Target = TopicNameRef;

    fn deref(&self) -> &TopicNameRef {
        unsafe { TopicNameRef::new_unchecked(&self.0) }
    }
}

impl Encodable for TopicName {
    type Err = TopicNameError;

    fn encode<W: Write>(&self, writer: &mut W) -> Result<(), TopicNameError> {
        (&self.0[..])
            .encode(writer)
            .map_err(TopicNameError::StringEncodeError)
    }

    fn encoded_length(&self) -> u32 {
        (&self.0[..]).encoded_length()
    }
}

impl Decodable for TopicName {
    type Err = TopicNameError;
    type Cond = ();

    fn decode_with<R: Read>(
        reader: &mut R,
        _rest: Option<()>,
    ) -> Result<TopicName, TopicNameError> {
        let topic_name: String =
            Decodable::decode(reader).map_err(TopicNameError::StringEncodeError)?;
        TopicName::new(topic_name)
    }
}

/// Errors while parsing topic names
#[derive(Debug)]
pub enum TopicNameError {
    StringEncodeError(StringEncodeError),
    InvalidTopicName(String),
}

impl fmt::Display for TopicNameError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            TopicNameError::StringEncodeError(ref err) => err.fmt(f),
            TopicNameError::InvalidTopicName(ref topic) => {
                write!(f, "Invalid topic filter ({})", topic)
            }
        }
    }
}

impl Error for TopicNameError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        match *self {
            TopicNameError::StringEncodeError(ref err) => Some(err),
            TopicNameError::InvalidTopicName(..) => None,
        }
    }
}

/// Reference to a topic name
#[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct TopicNameRef(str);

impl TopicNameRef {
    /// Creates a new topic name from string
    /// Return error if the string is not a valid topic name
    pub fn new<S: AsRef<str> + ?Sized>(topic_name: &S) -> Result<&TopicNameRef, TopicNameError> {
        let topic_name = topic_name.as_ref();
        if is_invalid_topic_name(&topic_name) {
            Err(TopicNameError::InvalidTopicName(topic_name.to_owned()))
        } else {
            Ok(unsafe { &*(topic_name as *const str as *const TopicNameRef) })
        }
    }

    /// Creates a new topic name from string without validation
    ///
    /// # Safety
    ///
    /// Topic names' syntax is defined in [MQTT specification](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718106).
    /// Creating a name from raw string may cause errors
    pub unsafe fn new_unchecked<S: AsRef<str> + ?Sized>(topic_name: &S) -> &TopicNameRef {
        let topic_name = topic_name.as_ref();
        &*(topic_name as *const str as *const TopicNameRef)
    }

    /// Check if this topic name is only for server.
    ///
    /// Topic names that beginning with a '$' character are reserved for servers
    pub fn is_server_specific(&self) -> bool {
        self.0.starts_with('$')
    }
}

impl Deref for TopicNameRef {
    type Target = str;

    fn deref(&self) -> &str {
        &self.0
    }
}

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

    #[test]
    fn topic_name_sys() {
        let topic_name = "$SYS".to_owned();
        TopicName::new(topic_name).unwrap();

        let topic_name = "$SYS/broker/connection/test.cosm-energy/state".to_owned();
        TopicName::new(topic_name).unwrap();
    }

    #[test]
    fn topic_name_slash() {
        TopicName::new("/").unwrap();
    }

    #[test]
    fn topic_name_basic() {
        TopicName::new("/finance").unwrap();
        TopicName::new("/finance//def").unwrap();
    }
}
<|endoftext|>


<commit_before>//! Some iterator that produces tuples

use std::iter::Fuse;
use std::iter::FusedIterator;
use std::iter::Take;
use std::iter::Cycle;
use std::marker::PhantomData;

// `HomogeneousTuple` is a public facade for `TupleCollect`, allowing
// tuple-related methods to be used by clients in generic contexts, while
// hiding the implementation details of `TupleCollect`.
// See https://github.com/rust-itertools/itertools/issues/387

/// Implemented for homogeneous tuples of size up to 4.
pub trait HomogeneousTuple
    : TupleCollect
{}

impl<T: TupleCollect> HomogeneousTuple for T {}

/// An iterator over a incomplete tuple.
///
/// See [`.tuples()`](crate::Itertools::tuples) and
/// [`Tuples::into_buffer()`].
#[derive(Clone, Debug)]
pub struct TupleBuffer<T>
    where T: HomogeneousTuple
{
    cur: usize,
    buf: T::Buffer,
}

impl<T> TupleBuffer<T>
    where T: HomogeneousTuple
{
    fn new(buf: T::Buffer) -> Self {
        TupleBuffer {
            cur: 0,
            buf,
        }
    }
}

impl<T> Iterator for TupleBuffer<T>
    where T: HomogeneousTuple
{
    type Item = T::Item;

    fn next(&mut self) -> Option<Self::Item> {
        let s = self.buf.as_mut();
        if let Some(ref mut item) = s.get_mut(self.cur) {
            self.cur += 1;
            item.take()
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let buffer = &self.buf.as_ref()[self.cur..];
        let len = if buffer.is_empty() {
            0
        } else {
            buffer.iter()
                  .position(|x| x.is_none())
                  .unwrap_or_else(|| buffer.len())
        };
        (len, Some(len))
    }
}

impl<T> ExactSizeIterator for TupleBuffer<T>
    where T: HomogeneousTuple
{
}

/// An iterator that groups the items in tuples of a specific size.
///
/// See [`.tuples()`](crate::Itertools::tuples) for more information.
#[derive(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    iter: Fuse<I>,
    buf: T::Buffer,
}

/// Create a new tuples iterator.
pub fn tuples<I, T>(iter: I) -> Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    Tuples {
        iter: iter.fuse(),
        buf: Default::default(),
    }
}

impl<I, T> Iterator for Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        T::collect_from_iter(&mut self.iter, &mut self.buf)
    }
}

impl<I, T> Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    /// Return a buffer with the produced items that was not enough to be grouped in a tuple.
    ///
    /// ```
    /// use itertools::Itertools;
    ///
    /// let mut iter = (0..5).tuples();
    /// assert_eq!(Some((0, 1, 2)), iter.next());
    /// assert_eq!(None, iter.next());
    /// itertools::assert_equal(vec![3, 4], iter.into_buffer());
    /// ```
    pub fn into_buffer(self) -> TupleBuffer<T> {
        TupleBuffer::new(self.buf)
    }
}

/// An iterator over all contiguous windows that produces tuples of a specific size.
///
/// See [`.tuple_windows()`](crate::Itertools::tuple_windows) for more
/// information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Clone, Debug)]
pub struct TupleWindows<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    iter: I,
    last: Option<T>,
}

/// Create a new tuple windows iterator.
pub fn tuple_windows<I, T>(mut iter: I) -> TupleWindows<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple,
          T::Item: Clone
{
    use std::iter::once;

    let mut last = None;
    if T::num_items() != 1 {
        // put in a duplicate item in front of the tuple; this simplifies
        // .next() function.
        if let Some(item) = iter.next() {
            let iter = once(item.clone()).chain(once(item)).chain(&mut iter);
            last = T::collect_from_iter_no_buf(iter);
        }
    }

    TupleWindows {
        last,
        iter,
    }
}

impl<I, T> Iterator for TupleWindows<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple + Clone,
          T::Item: Clone
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        if T::num_items() == 1 {
            return T::collect_from_iter_no_buf(&mut self.iter)
        }
        if let Some(ref mut last) = self.last {
            if let Some(new) = self.iter.next() {
                last.left_shift_push(new);
                return Some(last.clone());
            }
        }
        None
    }
}

impl<I, T> FusedIterator for TupleWindows<I, T>
    where I: FusedIterator<Item = T::Item>,
          T: HomogeneousTuple + Clone,
          T::Item: Clone
{}

/// An iterator over all windows,wrapping back to the first elements when the
/// window would otherwise exceed the length of the iterator, producing tuples
/// of a specific size.
///
/// See [`.circular_tuple_windows()`](crate::Itertools::circular_tuple_windows) for more
/// information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Debug)]
pub struct CircularTupleWindows<I, T: Clone>
    where I: Iterator<Item = T::Item> + Clone,
          T: TupleCollect + Clone
{
    iter: Take<TupleWindows<Cycle<I>, T>>,
    phantom_data: PhantomData<T>
}

pub fn circular_tuple_windows<I, T>(iter: I) -> CircularTupleWindows<I, T>
    where I: Iterator<Item = T::Item> + Clone + ExactSizeIterator,
          T: TupleCollect + Clone,
          T::Item: Clone
{
    let len = iter.len();
    let iter = tuple_windows(iter.cycle()).take(len);

    CircularTupleWindows {
        iter,
        phantom_data: PhantomData{}
    }
}

impl<I, T> Iterator for CircularTupleWindows<I, T>
    where I: Iterator<Item = T::Item> + Clone,
          T: TupleCollect + Clone,
          T::Item: Clone
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next()
    }
}

pub trait TupleCollect: Sized {
    type Item;
    type Buffer: Default + AsRef<[Option<Self::Item>]> + AsMut<[Option<Self::Item>]>;

    fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
        where I: IntoIterator<Item = Self::Item>;

    fn collect_from_iter_no_buf<I>(iter: I) -> Option<Self>
        where I: IntoIterator<Item = Self::Item>;

    fn num_items() -> usize;

    fn left_shift_push(&mut self, item: Self::Item);
}

macro_rules! count_ident{
    () => {0};
    ($i0:ident, $($i:ident,)*) => {1 + count_ident!($($i,)*)};
}
macro_rules! rev_for_each_ident{
    ($m:ident, ) => {};
    ($m:ident, $i0:ident, $($i:ident,)*) => {
        rev_for_each_ident!($m, $($i,)*);
        $m!($i0);
    };
}

macro_rules! impl_tuple_collect {
    ($dummy:ident,) => {}; // stop
    ($dummy:ident, $($Y:ident,)*) => (
        impl_tuple_collect!($($Y,)*);
        impl<A> TupleCollect for ($(ignore_ident!($Y, A),)*) {
            type Item = A;
            type Buffer = [Option<A>; count_ident!($($Y,)*) - 1];

            #[allow(unused_assignments, unused_mut)]
            fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
                where I: IntoIterator<Item = A>
            {
                let mut iter = iter.into_iter();
                $(
                    let mut $Y = None;
                )*

                loop {
                    $(
                        $Y = iter.next();
                        if $Y.is_none() {
                            break
                        }
                    )*
                    return Some(($($Y.unwrap()),*,))
                }

                let mut i = 0;
                let mut s = buf.as_mut();
                $(
                    if i < s.len() {
                        s[i] = $Y;
                        i += 1;
                    }
                )*
                return None;
            }

            fn collect_from_iter_no_buf<I>(iter: I) -> Option<Self>
                where I: IntoIterator<Item = A>
            {
                let mut iter = iter.into_iter();

                Some(($(
                    { let $Y = iter.next()?; $Y },
                )*))
            }

            fn num_items() -> usize {
                count_ident!($($Y,)*)
            }

            fn left_shift_push(&mut self, mut item: A) {
                use std::mem::replace;

                let &mut ($(ref mut $Y),*,) = self;
                macro_rules! replace_item{($i:ident) => {
                    item = replace($i, item);
                }}
                rev_for_each_ident!(replace_item, $($Y,)*);
                drop(item);
            }
        }
    )
}
impl_tuple_collect!(dummy, a, b, c, d, e, f, g, h, i, j, k, l,);
<commit_msg>Fix documentation of `HomogeneousTuple`<commit_after>//! Some iterator that produces tuples

use std::iter::Fuse;
use std::iter::FusedIterator;
use std::iter::Take;
use std::iter::Cycle;
use std::marker::PhantomData;

// `HomogeneousTuple` is a public facade for `TupleCollect`, allowing
// tuple-related methods to be used by clients in generic contexts, while
// hiding the implementation details of `TupleCollect`.
// See https://github.com/rust-itertools/itertools/issues/387

/// Implemented for homogeneous tuples of size up to 12.
pub trait HomogeneousTuple
    : TupleCollect
{}

impl<T: TupleCollect> HomogeneousTuple for T {}

/// An iterator over a incomplete tuple.
///
/// See [`.tuples()`](crate::Itertools::tuples) and
/// [`Tuples::into_buffer()`].
#[derive(Clone, Debug)]
pub struct TupleBuffer<T>
    where T: HomogeneousTuple
{
    cur: usize,
    buf: T::Buffer,
}

impl<T> TupleBuffer<T>
    where T: HomogeneousTuple
{
    fn new(buf: T::Buffer) -> Self {
        TupleBuffer {
            cur: 0,
            buf,
        }
    }
}

impl<T> Iterator for TupleBuffer<T>
    where T: HomogeneousTuple
{
    type Item = T::Item;

    fn next(&mut self) -> Option<Self::Item> {
        let s = self.buf.as_mut();
        if let Some(ref mut item) = s.get_mut(self.cur) {
            self.cur += 1;
            item.take()
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let buffer = &self.buf.as_ref()[self.cur..];
        let len = if buffer.is_empty() {
            0
        } else {
            buffer.iter()
                  .position(|x| x.is_none())
                  .unwrap_or_else(|| buffer.len())
        };
        (len, Some(len))
    }
}

impl<T> ExactSizeIterator for TupleBuffer<T>
    where T: HomogeneousTuple
{
}

/// An iterator that groups the items in tuples of a specific size.
///
/// See [`.tuples()`](crate::Itertools::tuples) for more information.
#[derive(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    iter: Fuse<I>,
    buf: T::Buffer,
}

/// Create a new tuples iterator.
pub fn tuples<I, T>(iter: I) -> Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    Tuples {
        iter: iter.fuse(),
        buf: Default::default(),
    }
}

impl<I, T> Iterator for Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        T::collect_from_iter(&mut self.iter, &mut self.buf)
    }
}

impl<I, T> Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    /// Return a buffer with the produced items that was not enough to be grouped in a tuple.
    ///
    /// ```
    /// use itertools::Itertools;
    ///
    /// let mut iter = (0..5).tuples();
    /// assert_eq!(Some((0, 1, 2)), iter.next());
    /// assert_eq!(None, iter.next());
    /// itertools::assert_equal(vec![3, 4], iter.into_buffer());
    /// ```
    pub fn into_buffer(self) -> TupleBuffer<T> {
        TupleBuffer::new(self.buf)
    }
}

/// An iterator over all contiguous windows that produces tuples of a specific size.
///
/// See [`.tuple_windows()`](crate::Itertools::tuple_windows) for more
/// information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Clone, Debug)]
pub struct TupleWindows<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    iter: I,
    last: Option<T>,
}

/// Create a new tuple windows iterator.
pub fn tuple_windows<I, T>(mut iter: I) -> TupleWindows<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple,
          T::Item: Clone
{
    use std::iter::once;

    let mut last = None;
    if T::num_items() != 1 {
        // put in a duplicate item in front of the tuple; this simplifies
        // .next() function.
        if let Some(item) = iter.next() {
            let iter = once(item.clone()).chain(once(item)).chain(&mut iter);
            last = T::collect_from_iter_no_buf(iter);
        }
    }

    TupleWindows {
        last,
        iter,
    }
}

impl<I, T> Iterator for TupleWindows<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple + Clone,
          T::Item: Clone
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        if T::num_items() == 1 {
            return T::collect_from_iter_no_buf(&mut self.iter)
        }
        if let Some(ref mut last) = self.last {
            if let Some(new) = self.iter.next() {
                last.left_shift_push(new);
                return Some(last.clone());
            }
        }
        None
    }
}

impl<I, T> FusedIterator for TupleWindows<I, T>
    where I: FusedIterator<Item = T::Item>,
          T: HomogeneousTuple + Clone,
          T::Item: Clone
{}

/// An iterator over all windows,wrapping back to the first elements when the
/// window would otherwise exceed the length of the iterator, producing tuples
/// of a specific size.
///
/// See [`.circular_tuple_windows()`](crate::Itertools::circular_tuple_windows) for more
/// information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Debug)]
pub struct CircularTupleWindows<I, T: Clone>
    where I: Iterator<Item = T::Item> + Clone,
          T: TupleCollect + Clone
{
    iter: Take<TupleWindows<Cycle<I>, T>>,
    phantom_data: PhantomData<T>
}

pub fn circular_tuple_windows<I, T>(iter: I) -> CircularTupleWindows<I, T>
    where I: Iterator<Item = T::Item> + Clone + ExactSizeIterator,
          T: TupleCollect + Clone,
          T::Item: Clone
{
    let len = iter.len();
    let iter = tuple_windows(iter.cycle()).take(len);

    CircularTupleWindows {
        iter,
        phantom_data: PhantomData{}
    }
}

impl<I, T> Iterator for CircularTupleWindows<I, T>
    where I: Iterator<Item = T::Item> + Clone,
          T: TupleCollect + Clone,
          T::Item: Clone
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next()
    }
}

pub trait TupleCollect: Sized {
    type Item;
    type Buffer: Default + AsRef<[Option<Self::Item>]> + AsMut<[Option<Self::Item>]>;

    fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
        where I: IntoIterator<Item = Self::Item>;

    fn collect_from_iter_no_buf<I>(iter: I) -> Option<Self>
        where I: IntoIterator<Item = Self::Item>;

    fn num_items() -> usize;

    fn left_shift_push(&mut self, item: Self::Item);
}

macro_rules! count_ident{
    () => {0};
    ($i0:ident, $($i:ident,)*) => {1 + count_ident!($($i,)*)};
}
macro_rules! rev_for_each_ident{
    ($m:ident, ) => {};
    ($m:ident, $i0:ident, $($i:ident,)*) => {
        rev_for_each_ident!($m, $($i,)*);
        $m!($i0);
    };
}

macro_rules! impl_tuple_collect {
    ($dummy:ident,) => {}; // stop
    ($dummy:ident, $($Y:ident,)*) => (
        impl_tuple_collect!($($Y,)*);
        impl<A> TupleCollect for ($(ignore_ident!($Y, A),)*) {
            type Item = A;
            type Buffer = [Option<A>; count_ident!($($Y,)*) - 1];

            #[allow(unused_assignments, unused_mut)]
            fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
                where I: IntoIterator<Item = A>
            {
                let mut iter = iter.into_iter();
                $(
                    let mut $Y = None;
                )*

                loop {
                    $(
                        $Y = iter.next();
                        if $Y.is_none() {
                            break
                        }
                    )*
                    return Some(($($Y.unwrap()),*,))
                }

                let mut i = 0;
                let mut s = buf.as_mut();
                $(
                    if i < s.len() {
                        s[i] = $Y;
                        i += 1;
                    }
                )*
                return None;
            }

            fn collect_from_iter_no_buf<I>(iter: I) -> Option<Self>
                where I: IntoIterator<Item = A>
            {
                let mut iter = iter.into_iter();

                Some(($(
                    { let $Y = iter.next()?; $Y },
                )*))
            }

            fn num_items() -> usize {
                count_ident!($($Y,)*)
            }

            fn left_shift_push(&mut self, mut item: A) {
                use std::mem::replace;

                let &mut ($(ref mut $Y),*,) = self;
                macro_rules! replace_item{($i:ident) => {
                    item = replace($i, item);
                }}
                rev_for_each_ident!(replace_item, $($Y,)*);
                drop(item);
            }
        }
    )
}
impl_tuple_collect!(dummy, a, b, c, d, e, f, g, h, i, j, k, l,);
<|endoftext|>


<commit_before>extern crate sdl2;

fn main() {
    let sdl_context = sdl2::init().unwrap();
    let game_controller_subsystem = sdl_context.game_controller().unwrap();

    let available =
        match game_controller_subsystem.num_joysticks() {
            Ok(n)  => n,
            Err(e) => panic!("can't enumerate joysticks: {}", e),
        };

    println!("{} joysticks available", available);

    let mut controller = None;

    // Iterate over all available joysticks and look for game
    // controllers.
    for id in 0..available {
        if game_controller_subsystem.is_game_controller(id) {
            println!("Attempting to open controller {}", id);

            match game_controller_subsystem.open(id) {
                Ok(c) => {
                    // We managed to find and open a game controller,
                    // exit the loop
                    println!("Success: opened \"{}\"", c.name());
                    controller = Some(c);
                    break;
                },
                Err(e) => println!("failed: {:?}", e),
            }

        } else {
             println!("{} is not a game controller", id);
        }
    }

    let controller =
        match controller {
            Some(c) => c,
            None     => panic!("Couldn't open any controller"),
        };

    println!("Controller mapping: {}", controller.mapping());

    for event in sdl_context.event_pump().unwrap().wait_iter() {
        use sdl2::event::Event;

        match event {
            Event::ControllerAxisMotion{ axis, value: val, .. } => {
                // Axis motion is an absolute value in the range
                // [-32768, 32767]. Let's simulate a very rough dead
                // zone to ignore spurious events.
                let dead_zone = 10_000;
                if val > dead_zone || val < -dead_zone {
                    println!("Axis {:?} moved to {}", axis, val);
                }
            }
            Event::ControllerButtonDown{ button, .. } =>
                println!("Button {:?} down", button),
            Event::ControllerButtonUp{ button, .. } =>
                println!("Button {:?} up", button),
            Event::Quit{..} => break,
            _ => (),
        }
    }
}
<commit_msg>Modify `game-controller` example to include `set_rumble`<commit_after>extern crate sdl2;

fn main() {
    let sdl_context = sdl2::init().unwrap();
    let game_controller_subsystem = sdl_context.game_controller().unwrap();

    let available =
        match game_controller_subsystem.num_joysticks() {
            Ok(n)  => n,
            Err(e) => panic!("can't enumerate joysticks: {}", e),
        };

    println!("{} joysticks available", available);

    let mut controller = None;

    // Iterate over all available joysticks and look for game
    // controllers.
    for id in 0..available {
        if game_controller_subsystem.is_game_controller(id) {
            println!("Attempting to open controller {}", id);

            match game_controller_subsystem.open(id) {
                Ok(c) => {
                    // We managed to find and open a game controller,
                    // exit the loop
                    println!("Success: opened \"{}\"", c.name());
                    controller = Some(c);
                    break;
                },
                Err(e) => println!("failed: {:?}", e),
            }

        } else {
             println!("{} is not a game controller", id);
        }
    }

    let mut controller =
        match controller {
            Some(c) => c,
            None     => panic!("Couldn't open any controller"),
        };

    println!("Controller mapping: {}", controller.mapping());

    let (mut lo_freq, mut hi_freq) = (0, 0);

    for event in sdl_context.event_pump().unwrap().wait_iter() {
        use sdl2::event::Event;
        use sdl2::controller::Axis;

        match event {
            Event::ControllerAxisMotion{ axis: Axis::TriggerLeft, value: val, .. } => {
                // Trigger axes go from 0 to 32767, so this should be okay
                lo_freq = (val as u16) * 2;
                match controller.set_rumble(lo_freq, hi_freq, 15000) {
                    Ok(()) => println!("Set rumble to ({}, {})", lo_freq, hi_freq),
                    Err(e) => println!("Error setting rumble to ({}, {}): {:?}", lo_freq, hi_freq, e),
                }
            }
            Event::ControllerAxisMotion{ axis: Axis::TriggerRight, value: val, .. } => {
                // Trigger axes go from 0 to 32767, so this should be okay
                hi_freq = (val as u16) * 2;
                match controller.set_rumble(lo_freq, hi_freq, 15000) {
                    Ok(()) => println!("Set rumble to ({}, {})", lo_freq, hi_freq),
                    Err(e) => println!("Error setting rumble to ({}, {}): {:?}", lo_freq, hi_freq, e),
                }
            }
            Event::ControllerAxisMotion{ axis, value: val, .. } => {
                // Axis motion is an absolute value in the range
                // [-32768, 32767]. Let's simulate a very rough dead
                // zone to ignore spurious events.
                let dead_zone = 10_000;
                if val > dead_zone || val < -dead_zone {
                    println!("Axis {:?} moved to {}", axis, val);
                }
            }
            Event::ControllerButtonDown{ button, .. } =>
                println!("Button {:?} down", button),
            Event::ControllerButtonUp{ button, .. } =>
                println!("Button {:?} up", button),
            Event::Quit{..} => break,
            _ => (),
        }
    }
}
<|endoftext|>


<commit_before>//! On Linux we try to use the more accurate `utimensat` syscall but this isn't
//! always available so we also fall back to `utimes` if we couldn't find
//! `utimensat` at runtime.

use std::io;
use std::mem;
use std::path::Path;
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};

use FileTime;
use super::libc::{self, c_int, c_char, timespec};

pub fn set_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> {
    match utimensat() {
        Some(f) => super::utimensat(p, atime, mtime, f, 0),
        None => super::utimes(p, atime, mtime, libc::utimes),
    }
}

pub fn set_symlink_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> {
    match utimensat() {
        Some(f) => super::utimensat(p, atime, mtime, f, libc::AT_SYMLINK_NOFOLLOW),
        None => super::utimes(p, atime, mtime, libc::lutimes),
    }
}

fn utimensat() -> Option<unsafe extern fn(c_int, *const c_char, *const timespec, c_int) -> c_int> {
    static ADDR: AtomicUsize = ATOMIC_USIZE_INIT;
    unsafe {
        match ADDR.load(Ordering::SeqCst) {
            0 => {}
            1 => return None,
            n => return Some(mem::transmute(n)),
        }
        let name = b"utimensat\0";
        let sym = libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr() as *const _);
        let (val, ret) = if sym.is_null() {
            (1, None)
        } else {
            (sym as usize, Some(mem::transmute(sym)))
        };
        ADDR.store(val, Ordering::SeqCst);
        return ret
    }
}
<commit_msg>Add a fallback for utimensat ENOSYS<commit_after>//! On Linux we try to use the more accurate `utimensat` syscall but this isn't
//! always available so we also fall back to `utimes` if we couldn't find
//! `utimensat` at runtime.

use std::io;
use std::mem;
use std::path::Path;
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT};

use FileTime;
use super::libc::{self, c_int, c_char, timespec};

pub fn set_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> {
    set_times(p, atime, mtime, false)
}

pub fn set_symlink_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> {
    set_times(p, atime, mtime, true)
}

fn set_times(p: &Path, atime: FileTime, mtime: FileTime, symlink: bool) -> io::Result<()> {
    let flags = if symlink { libc::AT_SYMLINK_NOFOLLOW } else { 0 };
    let utimes = if symlink { libc::lutimes } else { libc::utimes };

    // Try to use the more-accurate `utimensat` when possible.
    static INVALID: AtomicBool = ATOMIC_BOOL_INIT;
    if !INVALID.load(Ordering::SeqCst) {
        if let Some(f) = utimensat() {
            // Even when libc has `utimensat`, the kernel may return `ENOSYS`,
            // and then we'll need to use the `utimes` fallback instead.
            match super::utimensat(p, atime, mtime, f, flags) {
                Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {
                    INVALID.store(true, Ordering::SeqCst);
                }
                valid => return valid,
            }
        }
    }

    super::utimes(p, atime, mtime, utimes)
}

fn utimensat() -> Option<unsafe extern fn(c_int, *const c_char, *const timespec, c_int) -> c_int> {
    static ADDR: AtomicUsize = ATOMIC_USIZE_INIT;
    unsafe {
        match ADDR.load(Ordering::SeqCst) {
            0 => {}
            1 => return None,
            n => return Some(mem::transmute(n)),
        }
        let name = b"utimensat\0";
        let sym = libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr() as *const _);
        let (val, ret) = if sym.is_null() {
            (1, None)
        } else {
            (sym as usize, Some(mem::transmute(sym)))
        };
        ADDR.store(val, Ordering::SeqCst);
        return ret
    }
}
<|endoftext|>


<commit_before>use math::*;

use component::{TransformManager, StructComponentManager};
use scene::*;
use ecs::*;
use super::{CachedCollider, Collider, ColliderManager};
use debug_draw;

// TODO: Build a custom BVH manager that automatically constructs hierarchy.
pub type BoundingVolumeManager = StructComponentManager<BoundingVolumeHierarchy>;

#[derive(Debug, Clone)]
pub struct BoundingVolumeHierarchy {
    pub entity: Entity,
    pub root: BoundingVolumeNode,
}

impl BoundingVolumeHierarchy {
    /// Traverses the hierarchy and updates the bounding volumes to match any changes
    /// in the root colliders.
    pub fn update(&mut self, _transform_manager: &TransformManager) {
        // self.root.update(transform_manager);
    }

    /// Tests if `other` collides with this BVH.
    pub fn test(&self, _other: &BoundingVolumeHierarchy) -> bool {
        true // TODO: Actually test the collision.
    }

    pub fn debug_draw(&self) {
        self.root.debug_draw();
    }
}

#[derive(Debug, Clone)]
pub enum BoundingVolumeNode {
    Node {
        volume: BoundingVolume,
        left_child: Option<Box<BoundingVolumeNode>>,
        right_child: Option<Box<BoundingVolumeNode>>,
    },
    Leaf(CachedCollider),
}

impl BoundingVolumeNode {
    pub fn update(&mut self, transform_manager: &TransformManager) {
        match self {
            &mut BoundingVolumeNode::Node { volume: _, left_child: _, right_child: _ } => {
                // uhhh
                unimplemented!();
            },
            &mut BoundingVolumeNode::Leaf(ref mut cached_collider) => {
                // Just update cached collider.
                let transform = transform_manager.get(cached_collider.entity);
                cached_collider.position = transform.position_derived();
                cached_collider.orientation = transform.rotation_derived();
                cached_collider.scale = transform.scale_derived();
            },
        }
    }

    pub fn debug_draw(&self) {
        match self {
            &BoundingVolumeNode::Node { ref volume, left_child: _, right_child: _ } => {
                volume.debug_draw();
            },
            &BoundingVolumeNode::Leaf(_) => {
                unimplemented!();
            }
        }
    }
}

#[derive(Debug, Clone)]
pub enum BoundingVolume {
    /// Bounding sphere.
    Sphere {
        center: Point,
        radius: f32,
    },

    /// Axis-aligned bounding box.
    AABB {
        min: Point,
        max: Point,
    },

    /// Oriented boudning box.
    OBB {
        center: Point,
        axes: [Vector3; 3],
        half_widths: Vector3,
    },
}

impl BoundingVolume {
    /// Given a cached collider generate an AABB that bounds it.
    pub fn generate_aabb(cached_collider: &CachedCollider) -> BoundingVolume {
        match cached_collider.collider {
            Collider::Sphere { offset, radius } => {
                let center = cached_collider.position + offset;
                let half_width = Vector3::new(radius, radius, radius);
                let min = center - half_width;
                let max = center + half_width;

                BoundingVolume::AABB {
                    min: min,
                    max: max,
                }
            },
            Collider::Box { offset: _, width: _ } => {
                unimplemented!();
            },
            Collider::Mesh => {
                unimplemented!();
            }
        }
    }

    pub fn debug_draw(&self) {
        match self {
            &BoundingVolume::Sphere { center: _, radius: _ } => {
                unimplemented!();
            },
            &BoundingVolume::AABB { min, max } => {
                debug_draw::box_min_max(min, max);
            },
            &BoundingVolume::OBB { center: _, axes: _, half_widths: _ } => {
                unimplemented!();
            }
        }
    }
}

#[derive(Debug, Clone)]
pub struct BoundingVolumeUpdateSystem;

impl System for BoundingVolumeUpdateSystem {
    fn update(&mut self, scene: &Scene, _delta: f32) {
        let collider_manager = scene.get_manager::<ColliderManager>();
        let transform_manager = scene.get_manager::<TransformManager>();
        let mut bvh_manager = scene.get_manager_mut::<BoundingVolumeManager>();

        for (entity, collider) in collider_manager.iter() {
            let transform = transform_manager.get(entity);

            let cached_collider = CachedCollider {
                position: transform.position_derived(),
                orientation: transform.rotation_derived(),
                scale: transform.scale_derived(),
                collider: *collider,
                entity: entity,
            };

            if let Some(mut bvh) = bvh_manager.get_mut(entity) {
                bvh.update(&*transform_manager);
                bvh.debug_draw();
                continue;
            }

            // This block should be an `else` branch on the previous if block, but the borrow
            // checker isn't smart enough yet to tell that bvh_manager isn't borrowed anymore. We
            // `continue` at the end of the if block so if we get here we know the bvh isn't in
            // the bvh manager yet.
            {
                // Create and insert new bounding volumes.
                let root = BoundingVolumeNode::Node {
                    volume: BoundingVolume::generate_aabb(&cached_collider),
                    left_child: Some(Box::new(BoundingVolumeNode::Leaf(cached_collider))),
                    right_child: None,
                };

                bvh_manager.assign(entity, BoundingVolumeHierarchy {
                    entity: entity,
                    root: root,
                });
            }
        }
    }
}
<commit_msg>AABB Test<commit_after>use math::*;

use component::{TransformManager, StructComponentManager};
use scene::*;
use ecs::*;
use super::{CachedCollider, Collider, ColliderManager};
use debug_draw;

// TODO: Build a custom BVH manager that automatically constructs hierarchy.
pub type BoundingVolumeManager = StructComponentManager<BoundingVolumeHierarchy>;

#[derive(Debug, Clone)]
pub struct BoundingVolumeHierarchy {
    pub entity: Entity,
    pub root: BoundingVolumeNode,
}

impl BoundingVolumeHierarchy {
    /// Traverses the hierarchy and updates the bounding volumes to match any changes
    /// in the root colliders.
    pub fn update(&mut self, _transform_manager: &TransformManager) {
        // TODO: Update the bvh.
        // self.root.update(transform_manager);
    }

    /// Tests if `other` collides with this BVH.
    pub fn test(&self, other: &BoundingVolumeHierarchy) -> bool {
        let our_volume = match &self.root {
            &BoundingVolumeNode::Node { ref volume, left_child: _, right_child: _ } => {
                volume
            },
            &BoundingVolumeNode::Leaf(_) =>
                unimplemented!(),
        };

        let other_volume = match &other.root {
            &BoundingVolumeNode::Node { ref volume, left_child: _, right_child: _ } => {
                volume
            },
            &BoundingVolumeNode::Leaf(_) =>
                unimplemented!(),
        };

        our_volume.test(other_volume)
    }

    pub fn debug_draw(&self) {
        self.root.debug_draw();
    }
}

#[derive(Debug, Clone)]
pub enum BoundingVolumeNode {
    Node {
        volume: BoundingVolume,
        left_child: Option<Box<BoundingVolumeNode>>,
        right_child: Option<Box<BoundingVolumeNode>>,
    },
    Leaf(CachedCollider),
}

impl BoundingVolumeNode {
    pub fn update(&mut self, transform_manager: &TransformManager) {
        match self {
            &mut BoundingVolumeNode::Node { volume: _, left_child: _, right_child: _ } => {
                // uhhh
                unimplemented!();
            },
            &mut BoundingVolumeNode::Leaf(ref mut cached_collider) => {
                // Just update cached collider.
                let transform = transform_manager.get(cached_collider.entity);
                cached_collider.position = transform.position_derived();
                cached_collider.orientation = transform.rotation_derived();
                cached_collider.scale = transform.scale_derived();
            },
        }
    }

    pub fn debug_draw(&self) {
        match self {
            &BoundingVolumeNode::Node { ref volume, left_child: _, right_child: _ } => {
                volume.debug_draw();
            },
            &BoundingVolumeNode::Leaf(_) => {
                unimplemented!();
            }
        }
    }
}

#[derive(Debug, Clone)]
pub enum BoundingVolume {
    /// Bounding sphere.
    Sphere {
        center: Point,
        radius: f32,
    },

    /// Axis-aligned bounding box.
    AABB {
        min: Point,
        max: Point,
    },

    /// Oriented boudning box.
    OBB {
        center: Point,
        axes: [Vector3; 3],
        half_widths: Vector3,
    },
}

impl BoundingVolume {
    /// Given a cached collider generate an AABB that bounds it.
    pub fn generate_aabb(cached_collider: &CachedCollider) -> BoundingVolume {
        match cached_collider.collider {
            Collider::Sphere { offset, radius } => {
                let center = cached_collider.position + offset;
                let half_width = Vector3::new(radius, radius, radius);
                let min = center - half_width;
                let max = center + half_width;

                BoundingVolume::AABB {
                    min: min,
                    max: max,
                }
            },
            Collider::Box { offset: _, width: _ } => {
                unimplemented!();
            },
            Collider::Mesh => {
                unimplemented!();
            }
        }
    }

    pub fn test(&self, other: &BoundingVolume) -> bool {
        let (self_min, self_max) = match self {
            &BoundingVolume::AABB { min, max } => {
                (min, max)
            },
            _ => unimplemented!(),
        };

        let (other_min, other_max) = match other {
            &BoundingVolume::AABB { min, max } => {
                (min, max)
            },
            _ => unimplemented!(),
        };

        test_ranges((self_min.x, self_max.x), (other_min.x, other_max.x))
     && test_ranges((self_min.y, self_max.y), (other_min.y, other_max.y))
     && test_ranges((self_min.z, self_max.z), (other_min.z, other_max.z))
    }

    pub fn debug_draw(&self) {
        match self {
            &BoundingVolume::Sphere { center: _, radius: _ } => {
                unimplemented!();
            },
            &BoundingVolume::AABB { min, max } => {
                debug_draw::box_min_max(min, max);
            },
            &BoundingVolume::OBB { center: _, axes: _, half_widths: _ } => {
                unimplemented!();
            }
        }
    }
}

#[derive(Debug, Clone)]
pub struct BoundingVolumeUpdateSystem;

impl System for BoundingVolumeUpdateSystem {
    fn update(&mut self, scene: &Scene, _delta: f32) {
        let collider_manager = scene.get_manager::<ColliderManager>();
        let transform_manager = scene.get_manager::<TransformManager>();
        let mut bvh_manager = scene.get_manager_mut::<BoundingVolumeManager>();

        for (entity, collider) in collider_manager.iter() {
            let transform = transform_manager.get(entity);

            let cached_collider = CachedCollider {
                position: transform.position_derived(),
                orientation: transform.rotation_derived(),
                scale: transform.scale_derived(),
                collider: *collider,
                entity: entity,
            };

            if let Some(mut bvh) = bvh_manager.get_mut(entity) {
                bvh.update(&*transform_manager);
                bvh.debug_draw();
                continue;
            }

            // This block should be an `else` branch on the previous if block, but the borrow
            // checker isn't smart enough yet to tell that bvh_manager isn't borrowed anymore. We
            // `continue` at the end of the if block so if we get here we know the bvh isn't in
            // the bvh manager yet.
            {
                // Create and insert new bounding volumes.
                let root = BoundingVolumeNode::Node {
                    volume: BoundingVolume::generate_aabb(&cached_collider),
                    left_child: Some(Box::new(BoundingVolumeNode::Leaf(cached_collider))),
                    right_child: None,
                };

                bvh_manager.assign(entity, BoundingVolumeHierarchy {
                    entity: entity,
                    root: root,
                });
            }
        }
    }
}

fn test_ranges(first: (f32, f32), second: (f32, f32)) -> bool {
    let (min_a, max_a) = first;
    let (min_b, max_b) = second;

    !( min_a > max_b
    || min_b > max_a
    || max_a < min_b
    || max_b < min_a)
}
<|endoftext|>


<commit_before>#![cfg(feature = "serde")]

extern crate serde;

use EnumMap;
use Internal;

use self::serde::ser::{Serialize, Serializer, SerializeMap};
use self::serde::de::{self, Deserialize, Deserializer, Error, MapAccess};

use core::fmt;
use core::marker::PhantomData;

/// Requires crate feature `"serde"`
impl<K: Internal<V> + Serialize, V: Serialize> Serialize for EnumMap<K, V> {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        let mut map = serializer.serialize_map(Some(self.len()))?;
        for (key, value) in self {
            map.serialize_entry(&key, value)?;
        }
        map.end()
    }
}

/// Requires crate feature `"serde"`
impl<'de, K, V> Deserialize<'de> for EnumMap<K, V>
where
    K: Internal<V>
        + Internal<Option<V>>
        + Deserialize<'de>,
    V: Deserialize<'de>,
{
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        deserializer.deserialize_map(Visitor(PhantomData))
    }
}

struct Visitor<K, V>(PhantomData<(K, V)>);

impl<'de, K, V> de::Visitor<'de> for Visitor<K, V>
where
    K: Internal<V>
        + Internal<Option<V>>
        + Deserialize<'de>,
    V: Deserialize<'de>,
{
    type Value = EnumMap<K, V>;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "a map")
    }

    fn visit_map<M: MapAccess<'de>>(self, mut access: M) -> Result<Self::Value, M::Error> {
        let mut entries = enum_map! { _ => None };
        while let Some((key, value)) = access.next_entry()? {
            entries[key] = Some(value);
        }
        for value in entries.values() {
            if value.is_none() {
                return Err(M::Error::custom("key not specified"));
            }
        }
        Ok(enum_map! { key => entries[key].take().unwrap() })
    }
}
<commit_msg>Can use EnumMap::new instead of enum_map! macro in visit_map<commit_after>#![cfg(feature = "serde")]

extern crate serde;

use EnumMap;
use Internal;

use self::serde::ser::{Serialize, Serializer, SerializeMap};
use self::serde::de::{self, Deserialize, Deserializer, Error, MapAccess};

use core::fmt;
use core::marker::PhantomData;

/// Requires crate feature `"serde"`
impl<K: Internal<V> + Serialize, V: Serialize> Serialize for EnumMap<K, V> {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        let mut map = serializer.serialize_map(Some(self.len()))?;
        for (key, value) in self {
            map.serialize_entry(&key, value)?;
        }
        map.end()
    }
}

/// Requires crate feature `"serde"`
impl<'de, K, V> Deserialize<'de> for EnumMap<K, V>
where
    K: Internal<V>
        + Internal<Option<V>>
        + Deserialize<'de>,
    V: Deserialize<'de>,
{
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        deserializer.deserialize_map(Visitor(PhantomData))
    }
}

struct Visitor<K, V>(PhantomData<(K, V)>);

impl<'de, K, V> de::Visitor<'de> for Visitor<K, V>
where
    K: Internal<V>
        + Internal<Option<V>>
        + Deserialize<'de>,
    V: Deserialize<'de>,
{
    type Value = EnumMap<K, V>;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "a map")
    }

    fn visit_map<M: MapAccess<'de>>(self, mut access: M) -> Result<Self::Value, M::Error> {
        let mut entries = EnumMap::new();
        while let Some((key, value)) = access.next_entry()? {
            entries[key] = Some(value);
        }
        for value in entries.values() {
            if value.is_none() {
                return Err(M::Error::custom("key not specified"));
            }
        }
        Ok(enum_map! { key => entries[key].take().unwrap() })
    }
}
<|endoftext|>