<commit_before>use std::cmp::min;

use honey_badger_split::SplitExt;
use types::{ChainConfig, ShardAndCommittee, ValidatorRecord, ValidatorStatus};
use vec_shuffle::{shuffle, ShuffleErr};

type DelegatedCycle = Vec<Vec<ShardAndCommittee>>;

#[derive(Debug, PartialEq)]
pub enum ValidatorAssignmentError {
    TooManyValidators,
    TooFewShards,
}

/// Delegates active validators into slots for a given cycle, given a random seed.
/// Returns a vector or ShardAndComitte vectors representing the shards and committiees for
/// each slot.
/// References get_new_shuffling (ethereum 2.1 specification)
pub fn shard_and_committees_for_cycle(
    seed: &[u8],
    validators: &[ValidatorRecord],
    crosslinking_shard_start: u16,
    config: &ChainConfig,
) -> Result<DelegatedCycle, ValidatorAssignmentError> {
    let shuffled_validator_indices = {
        let mut validator_indices = validators
            .iter()
            .enumerate()
            .filter_map(|(i, validator)| {
                if validator.status_is(ValidatorStatus::Active) {
                    Some(i)
                } else {
                    None
                }
            })
            .collect();
        shuffle(seed, validator_indices)?
    };
    let shard_indices: Vec<usize> = (0_usize..config.shard_count as usize).into_iter().collect();
    let crosslinking_shard_start = crosslinking_shard_start as usize;
    let cycle_length = config.cycle_length as usize;
    let min_committee_size = config.min_committee_size as usize;
    generate_cycle(
        &shuffled_validator_indices,
        &shard_indices,
        crosslinking_shard_start,
        cycle_length,
        min_committee_size,
    )
}

/// Given the validator list, delegates the validators into slots and comittees for a given cycle.
fn generate_cycle(
    validator_indices: &[usize],
    shard_indices: &[usize],
    crosslinking_shard_start: usize,
    cycle_length: usize,
    min_committee_size: usize,
) -> Result<DelegatedCycle, ValidatorAssignmentError> {
    let validator_count = validator_indices.len();
    let shard_count = shard_indices.len();

    if shard_count / cycle_length == 0 {
        return Err(ValidatorAssignmentError::TooFewShards);
    }

    let (committees_per_slot, slots_per_committee) = {
        if validator_count >= cycle_length * min_committee_size {
            let committees_per_slot = min(
                validator_count / cycle_length / (min_committee_size * 2) + 1,
                shard_count / cycle_length,
            );
            let slots_per_committee = 1;
            (committees_per_slot, slots_per_committee)
        } else {
            let committees_per_slot = 1;
            let mut slots_per_committee = 1;
            while (validator_count * slots_per_committee < cycle_length * min_committee_size)
                & (slots_per_committee < cycle_length)
            {
                slots_per_committee *= 2;
            }
            (committees_per_slot, slots_per_committee)
        }
    };

    let cycle = validator_indices
        .honey_badger_split(cycle_length)
        .enumerate()
        .map(|(i, slot_indices)| {
            let shard_start =
                crosslinking_shard_start + i * committees_per_slot / slots_per_committee;
            slot_indices
                .honey_badger_split(committees_per_slot)
                .enumerate()
                .map(|(j, shard_indices)| ShardAndCommittee {
                    shard: ((shard_start + j) % shard_count) as u16,
                    committee: shard_indices.to_vec(),
                }).collect()
        }).collect();
    Ok(cycle)
}

impl From<ShuffleErr> for ValidatorAssignmentError {
    fn from(e: ShuffleErr) -> ValidatorAssignmentError {
        match e {
            ShuffleErr::ExceedsListLength => ValidatorAssignmentError::TooManyValidators,
        }
    }
}

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

    fn generate_cycle_helper(
        validator_count: &usize,
        shard_count: &usize,
        crosslinking_shard_start: usize,
        cycle_length: usize,
        min_committee_size: usize,
    ) -> (
        Vec<usize>,
        Vec<usize>,
        Result<DelegatedCycle, ValidatorAssignmentError>,
    ) {
        let validator_indices: Vec<usize> = (0_usize..*validator_count).into_iter().collect();
        let shard_indices: Vec<usize> = (0_usize..*shard_count).into_iter().collect();
        let result = generate_cycle(
            &validator_indices,
            &shard_indices,
            crosslinking_shard_start,
            cycle_length,
            min_committee_size,
        );
        (validator_indices, shard_indices, result)
    }

    #[allow(dead_code)]
    fn print_cycle(cycle: &DelegatedCycle) {
        cycle.iter().enumerate().for_each(|(i, slot)| {
            println!("slot {:?}", &i);
            slot.iter().enumerate().for_each(|(i, sac)| {
                println!(
                    "#{:?}\tshard={}\tcommittee.len()={}",
                    &i,
                    &sac.shard,
                    &sac.committee.len()
                )
            })
        });
    }

    fn flatten_validators(cycle: &DelegatedCycle) -> Vec<usize> {
        let mut flattened = vec![];
        for slot in cycle.iter() {
            for sac in slot.iter() {
                for validator in sac.committee.iter() {
                    flattened.push(*validator);
                }
            }
        }
        flattened
    }

    fn flatten_and_dedup_shards(cycle: &DelegatedCycle) -> Vec<usize> {
        let mut flattened = vec![];
        for slot in cycle.iter() {
            for sac in slot.iter() {
                flattened.push(sac.shard as usize);
            }
        }
        flattened.dedup();
        flattened
    }

    fn flatten_shards_in_slots(cycle: &DelegatedCycle) -> Vec<Vec<usize>> {
        let mut shards_in_slots: Vec<Vec<usize>> = vec![];
        for slot in cycle.iter() {
            let mut shards: Vec<usize> = vec![];
            for sac in slot.iter() {
                shards.push(sac.shard as usize);
            }
            shards_in_slots.push(shards);
        }
        shards_in_slots
    }

    // TODO: Improve these tests to check committee lengths
    #[test]
    fn test_generate_cycle() {
        let validator_count: usize = 100;
        let shard_count: usize = 20;
        let crosslinking_shard_start: usize = 0;
        let cycle_length: usize = 20;
        let min_committee_size: usize = 10;
        let (validators, shards, result) = generate_cycle_helper(
            &validator_count,
            &shard_count,
            crosslinking_shard_start,
            cycle_length,
            min_committee_size,
        );
        let cycle = result.unwrap();

        let assigned_validators = flatten_validators(&cycle);
        let assigned_shards = flatten_and_dedup_shards(&cycle);
        let shards_in_slots = flatten_shards_in_slots(&cycle);
        let expected_shards = shards.get(0..10).unwrap();
        assert_eq!(
            assigned_validators, validators,
            "Validator assignment incorrect"
        );
        assert_eq!(
            assigned_shards, expected_shards,
            "Shard assignment incorrect"
        );

        let expected_shards_in_slots: Vec<Vec<usize>> = vec![
            vec![0],
            vec![0], // Each line is 2 slots..
            vec![1],
            vec![1],
            vec![2],
            vec![2],
            vec![3],
            vec![3],
            vec![4],
            vec![4],
            vec![5],
            vec![5],
            vec![6],
            vec![6],
            vec![7],
            vec![7],
            vec![8],
            vec![8],
            vec![9],
            vec![9],
        ];
        // assert!(compare_shards_in_slots(&cycle, &expected_shards_in_slots));
        assert_eq!(
            expected_shards_in_slots, shards_in_slots,
            "Shard assignment incorrect."
        )
    }

    #[test]
    // Check that the committees per slot is upper bounded by shard count
    fn test_generate_cycle_committees_bounded() {
        let validator_count: usize = 523;
        let shard_count: usize = 31;
        let crosslinking_shard_start: usize = 0;
        let cycle_length: usize = 11;
        let min_committee_size: usize = 5;
        let (validators, shards, result) = generate_cycle_helper(
            &validator_count,
            &shard_count,
            crosslinking_shard_start,
            cycle_length,
            min_committee_size,
        );
        let cycle = result.unwrap();
        let assigned_validators = flatten_validators(&cycle);
        let assigned_shards = flatten_and_dedup_shards(&cycle);
        let shards_in_slots = flatten_shards_in_slots(&cycle);
        let expected_shards = shards.get(0..22).unwrap();
        let expected_shards_in_slots: Vec<Vec<usize>> = (0_usize..11_usize)
            .map(|x| vec![2 * x, 2 * x + 1])
            .collect();
        assert_eq!(
            assigned_validators, validators,
            "Validator assignment incorrect"
        );
        assert_eq!(
            assigned_shards, expected_shards,
            "Shard assignment incorrect"
        );
        // assert!(compare_shards_in_slots(&cycle, &expected_shards_in_slots));
        assert_eq!(
            expected_shards_in_slots, shards_in_slots,
            "Shard assignment incorrect."
        )
    }
}
<commit_msg>rustfmt changes<commit_after>use std::cmp::min;

use honey_badger_split::SplitExt;
use types::{ChainConfig, ShardAndCommittee, ValidatorRecord, ValidatorStatus};
use vec_shuffle::{shuffle, ShuffleErr};

type DelegatedCycle = Vec<Vec<ShardAndCommittee>>;

#[derive(Debug, PartialEq)]
pub enum ValidatorAssignmentError {
    TooManyValidators,
    TooFewShards,
}

/// Delegates active validators into slots for a given cycle, given a random seed.
/// Returns a vector or ShardAndComitte vectors representing the shards and committiees for
/// each slot.
/// References get_new_shuffling (ethereum 2.1 specification)
pub fn shard_and_committees_for_cycle(
    seed: &[u8],
    validators: &[ValidatorRecord],
    crosslinking_shard_start: u16,
    config: &ChainConfig,
) -> Result<DelegatedCycle, ValidatorAssignmentError> {
    let shuffled_validator_indices = {
        let mut validator_indices = validators
            .iter()
            .enumerate()
            .filter_map(|(i, validator)| {
                if validator.status_is(ValidatorStatus::Active) {
                    Some(i)
                } else {
                    None
                }
            })
            .collect();
        shuffle(seed, validator_indices)?
    };
    let shard_indices: Vec<usize> = (0_usize..config.shard_count as usize).into_iter().collect();
    let crosslinking_shard_start = crosslinking_shard_start as usize;
    let cycle_length = config.cycle_length as usize;
    let min_committee_size = config.min_committee_size as usize;
    generate_cycle(
        &shuffled_validator_indices,
        &shard_indices,
        crosslinking_shard_start,
        cycle_length,
        min_committee_size,
    )
}

/// Given the validator list, delegates the validators into slots and comittees for a given cycle.
fn generate_cycle(
    validator_indices: &[usize],
    shard_indices: &[usize],
    crosslinking_shard_start: usize,
    cycle_length: usize,
    min_committee_size: usize,
) -> Result<DelegatedCycle, ValidatorAssignmentError> {
    let validator_count = validator_indices.len();
    let shard_count = shard_indices.len();

    if shard_count / cycle_length == 0 {
        return Err(ValidatorAssignmentError::TooFewShards);
    }

    let (committees_per_slot, slots_per_committee) = {
        if validator_count >= cycle_length * min_committee_size {
            let committees_per_slot = min(
                validator_count / cycle_length / (min_committee_size * 2) + 1,
                shard_count / cycle_length,
            );
            let slots_per_committee = 1;
            (committees_per_slot, slots_per_committee)
        } else {
            let committees_per_slot = 1;
            let mut slots_per_committee = 1;
            while (validator_count * slots_per_committee < cycle_length * min_committee_size)
                & (slots_per_committee < cycle_length)
            {
                slots_per_committee *= 2;
            }
            (committees_per_slot, slots_per_committee)
        }
    };

    let cycle = validator_indices
        .honey_badger_split(cycle_length)
        .enumerate()
        .map(|(i, slot_indices)| {
            let shard_start =
                crosslinking_shard_start + i * committees_per_slot / slots_per_committee;
            slot_indices
                .honey_badger_split(committees_per_slot)
                .enumerate()
                .map(|(j, shard_indices)| ShardAndCommittee {
                    shard: ((shard_start + j) % shard_count) as u16,
                    committee: shard_indices.to_vec(),
                })
                .collect()
        })
        .collect();
    Ok(cycle)
}

impl From<ShuffleErr> for ValidatorAssignmentError {
    fn from(e: ShuffleErr) -> ValidatorAssignmentError {
        match e {
            ShuffleErr::ExceedsListLength => ValidatorAssignmentError::TooManyValidators,
        }
    }
}

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

    fn generate_cycle_helper(
        validator_count: &usize,
        shard_count: &usize,
        crosslinking_shard_start: usize,
        cycle_length: usize,
        min_committee_size: usize,
    ) -> (
        Vec<usize>,
        Vec<usize>,
        Result<DelegatedCycle, ValidatorAssignmentError>,
    ) {
        let validator_indices: Vec<usize> = (0_usize..*validator_count).into_iter().collect();
        let shard_indices: Vec<usize> = (0_usize..*shard_count).into_iter().collect();
        let result = generate_cycle(
            &validator_indices,
            &shard_indices,
            crosslinking_shard_start,
            cycle_length,
            min_committee_size,
        );
        (validator_indices, shard_indices, result)
    }

    #[allow(dead_code)]
    fn print_cycle(cycle: &DelegatedCycle) {
        cycle.iter().enumerate().for_each(|(i, slot)| {
            println!("slot {:?}", &i);
            slot.iter().enumerate().for_each(|(i, sac)| {
                println!(
                    "#{:?}\tshard={}\tcommittee.len()={}",
                    &i,
                    &sac.shard,
                    &sac.committee.len()
                )
            })
        });
    }

    fn flatten_validators(cycle: &DelegatedCycle) -> Vec<usize> {
        let mut flattened = vec![];
        for slot in cycle.iter() {
            for sac in slot.iter() {
                for validator in sac.committee.iter() {
                    flattened.push(*validator);
                }
            }
        }
        flattened
    }

    fn flatten_and_dedup_shards(cycle: &DelegatedCycle) -> Vec<usize> {
        let mut flattened = vec![];
        for slot in cycle.iter() {
            for sac in slot.iter() {
                flattened.push(sac.shard as usize);
            }
        }
        flattened.dedup();
        flattened
    }

    fn flatten_shards_in_slots(cycle: &DelegatedCycle) -> Vec<Vec<usize>> {
        let mut shards_in_slots: Vec<Vec<usize>> = vec![];
        for slot in cycle.iter() {
            let mut shards: Vec<usize> = vec![];
            for sac in slot.iter() {
                shards.push(sac.shard as usize);
            }
            shards_in_slots.push(shards);
        }
        shards_in_slots
    }

    // TODO: Improve these tests to check committee lengths
    #[test]
    fn test_generate_cycle() {
        let validator_count: usize = 100;
        let shard_count: usize = 20;
        let crosslinking_shard_start: usize = 0;
        let cycle_length: usize = 20;
        let min_committee_size: usize = 10;
        let (validators, shards, result) = generate_cycle_helper(
            &validator_count,
            &shard_count,
            crosslinking_shard_start,
            cycle_length,
            min_committee_size,
        );
        let cycle = result.unwrap();

        let assigned_validators = flatten_validators(&cycle);
        let assigned_shards = flatten_and_dedup_shards(&cycle);
        let shards_in_slots = flatten_shards_in_slots(&cycle);
        let expected_shards = shards.get(0..10).unwrap();
        assert_eq!(
            assigned_validators, validators,
            "Validator assignment incorrect"
        );
        assert_eq!(
            assigned_shards, expected_shards,
            "Shard assignment incorrect"
        );

        let expected_shards_in_slots: Vec<Vec<usize>> = vec![
            vec![0],
            vec![0], // Each line is 2 slots..
            vec![1],
            vec![1],
            vec![2],
            vec![2],
            vec![3],
            vec![3],
            vec![4],
            vec![4],
            vec![5],
            vec![5],
            vec![6],
            vec![6],
            vec![7],
            vec![7],
            vec![8],
            vec![8],
            vec![9],
            vec![9],
        ];
        // assert!(compare_shards_in_slots(&cycle, &expected_shards_in_slots));
        assert_eq!(
            expected_shards_in_slots, shards_in_slots,
            "Shard assignment incorrect."
        )
    }

    #[test]
    // Check that the committees per slot is upper bounded by shard count
    fn test_generate_cycle_committees_bounded() {
        let validator_count: usize = 523;
        let shard_count: usize = 31;
        let crosslinking_shard_start: usize = 0;
        let cycle_length: usize = 11;
        let min_committee_size: usize = 5;
        let (validators, shards, result) = generate_cycle_helper(
            &validator_count,
            &shard_count,
            crosslinking_shard_start,
            cycle_length,
            min_committee_size,
        );
        let cycle = result.unwrap();
        let assigned_validators = flatten_validators(&cycle);
        let assigned_shards = flatten_and_dedup_shards(&cycle);
        let shards_in_slots = flatten_shards_in_slots(&cycle);
        let expected_shards = shards.get(0..22).unwrap();
        let expected_shards_in_slots: Vec<Vec<usize>> = (0_usize..11_usize)
            .map(|x| vec![2 * x, 2 * x + 1])
            .collect();
        assert_eq!(
            assigned_validators, validators,
            "Validator assignment incorrect"
        );
        assert_eq!(
            assigned_shards, expected_shards,
            "Shard assignment incorrect"
        );
        // assert!(compare_shards_in_slots(&cycle, &expected_shards_in_slots));
        assert_eq!(
            expected_shards_in_slots, shards_in_slots,
            "Shard assignment incorrect."
        )
    }
}
<|endoftext|>


<commit_before>use crate::colors::AlphaOptim;
use crate::colors::ColorType;
use crate::evaluate::Evaluator;
use crate::headers::IhdrData;
use crate::png::scan_lines::ScanLine;
use crate::png::PngImage;
#[cfg(not(feature = "parallel"))]
use crate::rayon::prelude::*;
use indexmap::IndexSet;
#[cfg(feature = "parallel")]
use rayon::prelude::*;
use std::sync::Arc;

pub(crate) fn try_alpha_reductions(
    png: Arc<PngImage>,
    alphas: &IndexSet<AlphaOptim>,
    eval: &Evaluator,
) {
    if alphas.is_empty() {
        return;
    }

    alphas
        .par_iter()
        .with_max_len(1)
        .filter_map(|&alpha| filtered_alpha_channel(&png, alpha))
        .for_each(|image| eval.try_image(Arc::new(image)));
}

pub fn filtered_alpha_channel(png: &PngImage, optim: AlphaOptim) -> Option<PngImage> {
    let (bpc, bpp) = match png.ihdr.color_type {
        ColorType::RGBA | ColorType::GrayscaleAlpha => {
            let cpp = png.channels_per_pixel();
            let bpc = png.ihdr.bit_depth.as_u8() / 8;
            (bpc as usize, (bpc * cpp) as usize)
        }
        _ => {
            return None;
        }
    };

    let raw_data = match optim {
        AlphaOptim::NoOp => return None,
        AlphaOptim::Black => reduced_alpha_to_black(png, bpc, bpp),
        AlphaOptim::White => reduced_alpha_to_white(png, bpc, bpp),
        AlphaOptim::Up => reduced_alpha_to_up(png, bpc, bpp),
        AlphaOptim::Down => reduced_alpha_to_down(png, bpc, bpp),
        AlphaOptim::Left => reduced_alpha_to_left(png, bpc, bpp),
        AlphaOptim::Right => reduced_alpha_to_right(png, bpc, bpp),
    };

    Some(PngImage {
        data: raw_data,
        ihdr: png.ihdr,
        palette: png.palette.clone(),
        transparency_pixel: png.transparency_pixel.clone(),
        aux_headers: png.aux_headers.clone(),
    })
}

fn reduced_alpha_to_black(png: &PngImage, bpc: usize, bpp: usize) -> Vec<u8> {
    let mut reduced = Vec::with_capacity(png.data.len());
    for line in png.scan_lines() {
        reduced.push(line.filter);
        for pixel in line.data.chunks(bpp) {
            if pixel.iter().skip(bpp - bpc).fold(0, |sum, i| sum | i) == 0 {
                for _ in 0..bpp {
                    reduced.push(0);
                }
            } else {
                reduced.extend_from_slice(pixel);
            }
        }
    }
    reduced
}

fn reduced_alpha_to_white(png: &PngImage, bpc: usize, bpp: usize) -> Vec<u8> {
    let mut reduced = Vec::with_capacity(png.data.len());
    for line in png.scan_lines() {
        reduced.push(line.filter);
        for pixel in line.data.chunks(bpp) {
            if pixel.iter().skip(bpp - bpc).fold(0, |sum, i| sum | i) == 0 {
                for _ in 0..(bpp - bpc) {
                    reduced.push(255);
                }
                for _ in 0..bpc {
                    reduced.push(0);
                }
            } else {
                reduced.extend_from_slice(pixel);
            }
        }
    }
    reduced
}

fn reduced_alpha_to_up(png: &PngImage, bpc: usize, bpp: usize) -> Vec<u8> {
    let mut scan_lines = png.scan_lines().collect::<Vec<ScanLine<'_>>>();
    scan_lines.reverse();
    let mut lines = Vec::with_capacity(scan_lines.len());
    let mut last_line = Vec::new();
    let mut current_line = Vec::with_capacity(scan_lines[0].data.len() + 1); // filter size + pixels
    for line in scan_lines {
        if line.data.len() != last_line.len() {
            last_line = vec![0; line.data.len()];
        }
        current_line.push(line.filter);
        for (pixel, last_pixel) in line.data.chunks(bpp).zip(last_line.chunks(bpp)) {
            if pixel.iter().skip(bpp - bpc).fold(0, |sum, i| sum | i) == 0 {
                current_line.extend_from_slice(&last_pixel[0..(bpp - bpc)]);
                for _ in 0..bpc {
                    current_line.push(0);
                }
            } else {
                current_line.extend_from_slice(pixel);
            }
        }
        last_line = current_line.clone();
        lines.push(current_line.clone());
        current_line.clear();
    }
    lines.into_iter().rev().flatten().collect()
}

fn reduced_alpha_to_down(png: &PngImage, bpc: usize, bpp: usize) -> Vec<u8> {
    let mut reduced = Vec::with_capacity(png.data.len());
    let mut last_line = Vec::new();
    for line in png.scan_lines() {
        if line.data.len() != last_line.len() {
            last_line = vec![0; line.data.len()];
        }
        reduced.push(line.filter);
        for (pixel, last_pixel) in line.data.chunks(bpp).zip(last_line.chunks(bpp)) {
            if pixel.iter().skip(bpp - bpc).fold(0, |sum, i| sum | i) == 0 {
                reduced.extend_from_slice(&last_pixel[0..(bpp - bpc)]);
                for _ in 0..bpc {
                    reduced.push(0);
                }
            } else {
                reduced.extend_from_slice(pixel);
            }
        }
        last_line = reduced.clone();
    }
    reduced
}

fn reduced_alpha_to_left(png: &PngImage, bpc: usize, bpp: usize) -> Vec<u8> {
    let mut reduced = Vec::with_capacity(png.data.len());
    for line in png.scan_lines() {
        let mut line_bytes = Vec::with_capacity(line.data.len());
        let mut last_pixel = vec![0; bpp];
        for pixel in line.data.chunks(bpp).rev() {
            if pixel.iter().skip(bpp - bpc).fold(0, |sum, i| sum | i) == 0 {
                line_bytes.extend_from_slice(&last_pixel[0..(bpp - bpc)]);
                for _ in 0..bpc {
                    line_bytes.push(0);
                }
            } else {
                line_bytes.extend_from_slice(pixel);
            }
            last_pixel = pixel.to_owned();
        }
        reduced.push(line.filter);
        reduced.extend(line_bytes.chunks(bpp).rev().flatten());
    }
    reduced
}

fn reduced_alpha_to_right(png: &PngImage, bpc: usize, bpp: usize) -> Vec<u8> {
    let mut reduced = Vec::with_capacity(png.data.len());
    for line in png.scan_lines() {
        reduced.push(line.filter);
        let mut last_pixel = vec![0; bpp];
        for pixel in line.data.chunks(bpp) {
            if pixel.iter().skip(bpp - bpc).fold(0, |sum, i| sum | i) == 0 {
                reduced.extend_from_slice(&last_pixel[0..(bpp - bpc)]);
                for _ in 0..bpc {
                    reduced.push(0);
                }
            } else {
                reduced.extend_from_slice(pixel);
            }
            last_pixel = pixel.to_owned();
        }
    }
    reduced
}

#[must_use]
pub fn reduced_alpha_channel(png: &PngImage) -> Option<PngImage> {
    let target_color_type = match png.ihdr.color_type {
        ColorType::GrayscaleAlpha => ColorType::Grayscale,
        ColorType::RGBA => ColorType::RGB,
        _ => return None,
    };
    let byte_depth = png.ihdr.bit_depth.as_u8() >> 3;
    let channels = png.channels_per_pixel();
    let bpp = channels * byte_depth;
    let bpp_mask = bpp - 1;
    assert_eq!(0, bpp & bpp_mask);
    let colored_bytes = bpp - byte_depth;
    for line in png.scan_lines() {
        for (i, &byte) in line.data.iter().enumerate() {
            if i as u8 & bpp_mask >= colored_bytes && byte != 255 {
                return None;
            }
        }
    }

    let mut raw_data = Vec::with_capacity(png.data.len());
    for line in png.scan_lines() {
        raw_data.push(line.filter);
        for (i, &byte) in line.data.iter().enumerate() {
            if i as u8 & bpp_mask >= colored_bytes {
                continue;
            }

            raw_data.push(byte);
        }
    }

    let mut aux_headers = png.aux_headers.clone();
    // sBIT contains information about alpha channel's original depth,
    // and alpha has just been removed
    if let Some(sbit_header) = png.aux_headers.get(b"sBIT") {
        // Some programs save the sBIT header as RGB even if the image is RGBA.
        aux_headers.insert(*b"sBIT", sbit_header.iter().cloned().take(3).collect());
    }

    Some(PngImage {
        data: raw_data,
        ihdr: IhdrData {
            color_type: target_color_type,
            ..png.ihdr
        },
        aux_headers,
        transparency_pixel: None,
        palette: None,
    })
}
<commit_msg>Fix new clippy lints from Rust 1.47<commit_after>use crate::colors::AlphaOptim;
use crate::colors::ColorType;
use crate::evaluate::Evaluator;
use crate::headers::IhdrData;
use crate::png::scan_lines::ScanLine;
use crate::png::PngImage;
#[cfg(not(feature = "parallel"))]
use crate::rayon::prelude::*;
use indexmap::IndexSet;
#[cfg(feature = "parallel")]
use rayon::prelude::*;
use std::sync::Arc;

pub(crate) fn try_alpha_reductions(
    png: Arc<PngImage>,
    alphas: &IndexSet<AlphaOptim>,
    eval: &Evaluator,
) {
    if alphas.is_empty() {
        return;
    }

    alphas
        .par_iter()
        .with_max_len(1)
        .filter_map(|&alpha| filtered_alpha_channel(&png, alpha))
        .for_each(|image| eval.try_image(Arc::new(image)));
}

pub fn filtered_alpha_channel(png: &PngImage, optim: AlphaOptim) -> Option<PngImage> {
    let (bpc, bpp) = match png.ihdr.color_type {
        ColorType::RGBA | ColorType::GrayscaleAlpha => {
            let cpp = png.channels_per_pixel();
            let bpc = png.ihdr.bit_depth.as_u8() / 8;
            (bpc as usize, (bpc * cpp) as usize)
        }
        _ => {
            return None;
        }
    };

    let raw_data = match optim {
        AlphaOptim::NoOp => return None,
        AlphaOptim::Black => reduced_alpha_to_black(png, bpc, bpp),
        AlphaOptim::White => reduced_alpha_to_white(png, bpc, bpp),
        AlphaOptim::Up => reduced_alpha_to_up(png, bpc, bpp),
        AlphaOptim::Down => reduced_alpha_to_down(png, bpc, bpp),
        AlphaOptim::Left => reduced_alpha_to_left(png, bpc, bpp),
        AlphaOptim::Right => reduced_alpha_to_right(png, bpc, bpp),
    };

    Some(PngImage {
        data: raw_data,
        ihdr: png.ihdr,
        palette: png.palette.clone(),
        transparency_pixel: png.transparency_pixel.clone(),
        aux_headers: png.aux_headers.clone(),
    })
}

fn reduced_alpha_to_black(png: &PngImage, bpc: usize, bpp: usize) -> Vec<u8> {
    let mut reduced = Vec::with_capacity(png.data.len());
    for line in png.scan_lines() {
        reduced.push(line.filter);
        for pixel in line.data.chunks(bpp) {
            if pixel.iter().skip(bpp - bpc).fold(0, |sum, i| sum | i) == 0 {
                reduced.resize(reduced.len() + bpp, 0);
            } else {
                reduced.extend_from_slice(pixel);
            }
        }
    }
    reduced
}

fn reduced_alpha_to_white(png: &PngImage, bpc: usize, bpp: usize) -> Vec<u8> {
    let mut reduced = Vec::with_capacity(png.data.len());
    for line in png.scan_lines() {
        reduced.push(line.filter);
        for pixel in line.data.chunks(bpp) {
            if pixel.iter().skip(bpp - bpc).fold(0, |sum, i| sum | i) == 0 {
                reduced.resize(reduced.len() + bpp - bpc, 255);
                reduced.resize(reduced.len() + bpc, 0);
            } else {
                reduced.extend_from_slice(pixel);
            }
        }
    }
    reduced
}

fn reduced_alpha_to_up(png: &PngImage, bpc: usize, bpp: usize) -> Vec<u8> {
    let mut scan_lines = png.scan_lines().collect::<Vec<ScanLine<'_>>>();
    scan_lines.reverse();
    let mut lines = Vec::with_capacity(scan_lines.len());
    let mut last_line = Vec::new();
    let mut current_line = Vec::with_capacity(scan_lines[0].data.len() + 1); // filter size + pixels
    for line in scan_lines {
        if line.data.len() != last_line.len() {
            last_line = vec![0; line.data.len()];
        }
        current_line.push(line.filter);
        for (pixel, last_pixel) in line.data.chunks(bpp).zip(last_line.chunks(bpp)) {
            if pixel.iter().skip(bpp - bpc).fold(0, |sum, i| sum | i) == 0 {
                current_line.extend_from_slice(&last_pixel[0..(bpp - bpc)]);
                current_line.resize(current_line.len() + bpc, 0);
            } else {
                current_line.extend_from_slice(pixel);
            }
        }
        last_line = current_line.clone();
        lines.push(current_line.clone());
        current_line.clear();
    }
    lines.into_iter().rev().flatten().collect()
}

fn reduced_alpha_to_down(png: &PngImage, bpc: usize, bpp: usize) -> Vec<u8> {
    let mut reduced = Vec::with_capacity(png.data.len());
    let mut last_line = Vec::new();
    for line in png.scan_lines() {
        if line.data.len() != last_line.len() {
            last_line = vec![0; line.data.len()];
        }
        reduced.push(line.filter);
        for (pixel, last_pixel) in line.data.chunks(bpp).zip(last_line.chunks(bpp)) {
            if pixel.iter().skip(bpp - bpc).fold(0, |sum, i| sum | i) == 0 {
                reduced.extend_from_slice(&last_pixel[0..(bpp - bpc)]);
                reduced.resize(reduced.len() + bpc, 0);
            } else {
                reduced.extend_from_slice(pixel);
            }
        }
        last_line = reduced.clone();
    }
    reduced
}

fn reduced_alpha_to_left(png: &PngImage, bpc: usize, bpp: usize) -> Vec<u8> {
    let mut reduced = Vec::with_capacity(png.data.len());
    for line in png.scan_lines() {
        let mut line_bytes = Vec::with_capacity(line.data.len());
        let mut last_pixel = vec![0; bpp];
        for pixel in line.data.chunks(bpp).rev() {
            if pixel.iter().skip(bpp - bpc).fold(0, |sum, i| sum | i) == 0 {
                line_bytes.extend_from_slice(&last_pixel[0..(bpp - bpc)]);
                line_bytes.resize(line_bytes.len() + bpc, 0);
            } else {
                line_bytes.extend_from_slice(pixel);
            }
            last_pixel = pixel.to_owned();
        }
        reduced.push(line.filter);
        reduced.extend(line_bytes.chunks(bpp).rev().flatten());
    }
    reduced
}

fn reduced_alpha_to_right(png: &PngImage, bpc: usize, bpp: usize) -> Vec<u8> {
    let mut reduced = Vec::with_capacity(png.data.len());
    for line in png.scan_lines() {
        reduced.push(line.filter);
        let mut last_pixel = vec![0; bpp];
        for pixel in line.data.chunks(bpp) {
            if pixel.iter().skip(bpp - bpc).fold(0, |sum, i| sum | i) == 0 {
                reduced.extend_from_slice(&last_pixel[0..(bpp - bpc)]);
                reduced.resize(reduced.len() + bpc, 0);
            } else {
                reduced.extend_from_slice(pixel);
            }
            last_pixel = pixel.to_owned();
        }
    }
    reduced
}

#[must_use]
pub fn reduced_alpha_channel(png: &PngImage) -> Option<PngImage> {
    let target_color_type = match png.ihdr.color_type {
        ColorType::GrayscaleAlpha => ColorType::Grayscale,
        ColorType::RGBA => ColorType::RGB,
        _ => return None,
    };
    let byte_depth = png.ihdr.bit_depth.as_u8() >> 3;
    let channels = png.channels_per_pixel();
    let bpp = channels * byte_depth;
    let bpp_mask = bpp - 1;
    assert_eq!(0, bpp & bpp_mask);
    let colored_bytes = bpp - byte_depth;
    for line in png.scan_lines() {
        for (i, &byte) in line.data.iter().enumerate() {
            if i as u8 & bpp_mask >= colored_bytes && byte != 255 {
                return None;
            }
        }
    }

    let mut raw_data = Vec::with_capacity(png.data.len());
    for line in png.scan_lines() {
        raw_data.push(line.filter);
        for (i, &byte) in line.data.iter().enumerate() {
            if i as u8 & bpp_mask >= colored_bytes {
                continue;
            }

            raw_data.push(byte);
        }
    }

    let mut aux_headers = png.aux_headers.clone();
    // sBIT contains information about alpha channel's original depth,
    // and alpha has just been removed
    if let Some(sbit_header) = png.aux_headers.get(b"sBIT") {
        // Some programs save the sBIT header as RGB even if the image is RGBA.
        aux_headers.insert(*b"sBIT", sbit_header.iter().cloned().take(3).collect());
    }

    Some(PngImage {
        data: raw_data,
        ihdr: IhdrData {
            color_type: target_color_type,
            ..png.ihdr
        },
        aux_headers,
        transparency_pixel: None,
        palette: None,
    })
}
<|endoftext|>


<commit_before>//! The main rustup commandline application
//!
//! The rustup binary is a chimera, changing its behavior based on the
//! name of the binary. This is used most prominently to enable
//! rustup's tool 'proxies' - that is, rustup itself and the rustup
//! proxies are the same binary; when the binary is called 'rustup' or
//! 'rustup.exe' rustup behaves like the rustup commandline
//! application; when it is called 'rustc' it behaves as a proxy to
//! 'rustc'.
//!
//! This scheme is further used to distingush the rustup installer,
//! called 'rustup-init' which is again just the rustup binary under a
//! different name.

#![recursion_limit = "1024"]

#[macro_use]
extern crate error_chain;
extern crate rustup_dist;
extern crate rustup_utils;

extern crate clap;
extern crate itertools;
extern crate markdown;
extern crate rand;
extern crate regex;
extern crate rustup;
extern crate same_file;
extern crate scopeguard;
extern crate sha2;
extern crate tempdir;
extern crate term;
extern crate time;
extern crate toml;
extern crate wait_timeout;

#[cfg(windows)]
extern crate gcc;
extern crate libc;
#[cfg(windows)]
extern crate winapi;
#[cfg(windows)]
extern crate winreg;

#[macro_use]
mod log;
mod common;
mod download_tracker;
mod proxy_mode;
mod setup_mode;
mod rustup_mode;
mod self_update;
mod job;
mod term2;
mod errors;
mod help;

use std::env;
use std::path::PathBuf;
use errors::*;
use rustup_dist::dist::TargetTriple;
use rustup::env_var::RUST_RECURSION_COUNT_MAX;

fn main() {
    if let Err(ref e) = run_rustup() {
        common::report_error(e);
        std::process::exit(1);
    }
}

fn run_rustup() -> Result<()> {
    // Guard against infinite proxy recursion. This mostly happens due to
    // bugs in rustup.
    do_recursion_guard()?;

    // Do various hacks to clean up past messes
    do_compatibility_hacks();

    // The name of arg0 determines how the program is going to behave
    let arg0 = env::args().next().map(PathBuf::from);
    let name = arg0.as_ref()
        .and_then(|a| a.file_stem())
        .and_then(|a| a.to_str());

    match name {
        Some("rustup") => rustup_mode::main(),
        Some(n)
            if n.starts_with("multirust-setup") || n.starts_with("rustup-setup")
                || n.starts_with("rustup-init") =>
        {
            // NB: The above check is only for the prefix of the file
            // name. Browsers rename duplicates to
            // e.g. rustup-setup(2), and this allows all variations
            // to work.
            setup_mode::main()
        }
        Some(n) if n.starts_with("rustup-gc-") => {
            // This is the final uninstallation stage on windows where
            // rustup deletes its own exe
            self_update::complete_windows_uninstall()
        }
        Some(n) if n.starts_with("multirust-") => {
            // This is for compatibility with previous revisions of
            // multirust-rs self-update, which expect multirust-rs to
            // be available on the server, downloads it to
            // ~/.multirust/tmp/multirust-$random, and execute it with
            // `self install` as the arguments.  FIXME: Verify this
            // works.
            let opts = self_update::InstallOpts {
                default_host_triple: TargetTriple::from_host_or_build().to_string(),
                default_toolchain: "stable".to_string(),
                no_modify_path: false,
            };
            if cfg!(windows) {
                self_update::install(false, false, opts)
            } else {
                self_update::install(true, false, opts)
            }
        }
        Some(_) => proxy_mode::main(),
        None => {
            // Weird case. No arg0, or it's unparsable.
            Err(ErrorKind::NoExeName.into())
        }
    }
}

fn do_recursion_guard() -> Result<()> {
    let recursion_count = env::var("RUST_RECURSION_COUNT")
        .ok()
        .and_then(|s| s.parse().ok())
        .unwrap_or(0);
    if recursion_count > RUST_RECURSION_COUNT_MAX {
        return Err(ErrorKind::InfiniteRecursion.into());
    }

    Ok(())
}

fn do_compatibility_hacks() {
    make_environment_compatible();
    fix_windows_reg_key();
    delete_multirust_bin();
}

// Convert any MULTIRUST_ env vars to RUSTUP_ and warn about them
fn make_environment_compatible() {
    let ref vars = ["HOME", "TOOLCHAIN", "DIST_ROOT", "UPDATE_ROOT", "GPG_KEY"];
    for var in vars {
        let ref mvar = format!("MULTIRUST_{}", var);
        let ref rvar = format!("RUSTUP_{}", var);
        let mval = env::var_os(mvar);
        let rval = env::var_os(rvar);

        match (mval, rval) {
            (Some(mval), None) => {
                env::set_var(rvar, mval);
                warn!("environment variable {} is deprecated. Use {}.", mvar, rvar);
            }
            _ => (),
        }
    }
}

// #261 We previously incorrectly set HKCU/Environment/PATH to a
// REG_SZ type, when it should be REG_EXPAND_SZ. Silently fix it.
#[cfg(windows)]
fn fix_windows_reg_key() {
    use winreg::RegKey;
    use winreg::enums::{RegType, HKEY_CURRENT_USER, KEY_READ, KEY_WRITE};

    let root = RegKey::predef(HKEY_CURRENT_USER);
    let env = root.open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE);

    let env = if let Ok(e) = env { e } else { return };

    let path = env.get_raw_value("PATH");

    let mut path = if let Ok(p) = path { p } else { return };

    if path.vtype == RegType::REG_EXPAND_SZ {
        return;
    }

    path.vtype = RegType::REG_EXPAND_SZ;

    let _ = env.set_raw_value("PATH", &path);
}

#[cfg(not(windows))]
fn fix_windows_reg_key() {}

// rustup used to be called 'multirust'. This deletes the old bin.
fn delete_multirust_bin() {
    use rustup_utils::utils;
    use std::env::consts::EXE_SUFFIX;
    use std::fs;

    if let Ok(home) = utils::cargo_home() {
        let legacy_bin = home.join(format!("bin/multirust{}", EXE_SUFFIX));
        if legacy_bin.exists() {
            let _ = fs::remove_file(legacy_bin);
        }
    }
}
<commit_msg>Switch to system allocator<commit_after>//! The main rustup commandline application
//!
//! The rustup binary is a chimera, changing its behavior based on the
//! name of the binary. This is used most prominently to enable
//! rustup's tool 'proxies' - that is, rustup itself and the rustup
//! proxies are the same binary; when the binary is called 'rustup' or
//! 'rustup.exe' rustup behaves like the rustup commandline
//! application; when it is called 'rustc' it behaves as a proxy to
//! 'rustc'.
//!
//! This scheme is further used to distingush the rustup installer,
//! called 'rustup-init' which is again just the rustup binary under a
//! different name.

#![recursion_limit = "1024"]

use std::alloc::System;

#[global_allocator]
static A: System = System;

#[macro_use]
extern crate error_chain;
extern crate rustup_dist;
extern crate rustup_utils;

extern crate clap;
extern crate itertools;
extern crate markdown;
extern crate rand;
extern crate regex;
extern crate rustup;
extern crate same_file;
extern crate scopeguard;
extern crate sha2;
extern crate tempdir;
extern crate term;
extern crate time;
extern crate toml;
extern crate wait_timeout;

#[cfg(windows)]
extern crate gcc;
extern crate libc;
#[cfg(windows)]
extern crate winapi;
#[cfg(windows)]
extern crate winreg;

#[macro_use]
mod log;
mod common;
mod download_tracker;
mod proxy_mode;
mod setup_mode;
mod rustup_mode;
mod self_update;
mod job;
mod term2;
mod errors;
mod help;

use std::env;
use std::path::PathBuf;
use errors::*;
use rustup_dist::dist::TargetTriple;
use rustup::env_var::RUST_RECURSION_COUNT_MAX;

fn main() {
    if let Err(ref e) = run_rustup() {
        common::report_error(e);
        std::process::exit(1);
    }
}

fn run_rustup() -> Result<()> {
    // Guard against infinite proxy recursion. This mostly happens due to
    // bugs in rustup.
    do_recursion_guard()?;

    // Do various hacks to clean up past messes
    do_compatibility_hacks();

    // The name of arg0 determines how the program is going to behave
    let arg0 = env::args().next().map(PathBuf::from);
    let name = arg0.as_ref()
        .and_then(|a| a.file_stem())
        .and_then(|a| a.to_str());

    match name {
        Some("rustup") => rustup_mode::main(),
        Some(n)
            if n.starts_with("multirust-setup") || n.starts_with("rustup-setup")
                || n.starts_with("rustup-init") =>
        {
            // NB: The above check is only for the prefix of the file
            // name. Browsers rename duplicates to
            // e.g. rustup-setup(2), and this allows all variations
            // to work.
            setup_mode::main()
        }
        Some(n) if n.starts_with("rustup-gc-") => {
            // This is the final uninstallation stage on windows where
            // rustup deletes its own exe
            self_update::complete_windows_uninstall()
        }
        Some(n) if n.starts_with("multirust-") => {
            // This is for compatibility with previous revisions of
            // multirust-rs self-update, which expect multirust-rs to
            // be available on the server, downloads it to
            // ~/.multirust/tmp/multirust-$random, and execute it with
            // `self install` as the arguments.  FIXME: Verify this
            // works.
            let opts = self_update::InstallOpts {
                default_host_triple: TargetTriple::from_host_or_build().to_string(),
                default_toolchain: "stable".to_string(),
                no_modify_path: false,
            };
            if cfg!(windows) {
                self_update::install(false, false, opts)
            } else {
                self_update::install(true, false, opts)
            }
        }
        Some(_) => proxy_mode::main(),
        None => {
            // Weird case. No arg0, or it's unparsable.
            Err(ErrorKind::NoExeName.into())
        }
    }
}

fn do_recursion_guard() -> Result<()> {
    let recursion_count = env::var("RUST_RECURSION_COUNT")
        .ok()
        .and_then(|s| s.parse().ok())
        .unwrap_or(0);
    if recursion_count > RUST_RECURSION_COUNT_MAX {
        return Err(ErrorKind::InfiniteRecursion.into());
    }

    Ok(())
}

fn do_compatibility_hacks() {
    make_environment_compatible();
    fix_windows_reg_key();
    delete_multirust_bin();
}

// Convert any MULTIRUST_ env vars to RUSTUP_ and warn about them
fn make_environment_compatible() {
    let ref vars = ["HOME", "TOOLCHAIN", "DIST_ROOT", "UPDATE_ROOT", "GPG_KEY"];
    for var in vars {
        let ref mvar = format!("MULTIRUST_{}", var);
        let ref rvar = format!("RUSTUP_{}", var);
        let mval = env::var_os(mvar);
        let rval = env::var_os(rvar);

        match (mval, rval) {
            (Some(mval), None) => {
                env::set_var(rvar, mval);
                warn!("environment variable {} is deprecated. Use {}.", mvar, rvar);
            }
            _ => (),
        }
    }
}

// #261 We previously incorrectly set HKCU/Environment/PATH to a
// REG_SZ type, when it should be REG_EXPAND_SZ. Silently fix it.
#[cfg(windows)]
fn fix_windows_reg_key() {
    use winreg::RegKey;
    use winreg::enums::{RegType, HKEY_CURRENT_USER, KEY_READ, KEY_WRITE};

    let root = RegKey::predef(HKEY_CURRENT_USER);
    let env = root.open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE);

    let env = if let Ok(e) = env { e } else { return };

    let path = env.get_raw_value("PATH");

    let mut path = if let Ok(p) = path { p } else { return };

    if path.vtype == RegType::REG_EXPAND_SZ {
        return;
    }

    path.vtype = RegType::REG_EXPAND_SZ;

    let _ = env.set_raw_value("PATH", &path);
}

#[cfg(not(windows))]
fn fix_windows_reg_key() {}

// rustup used to be called 'multirust'. This deletes the old bin.
fn delete_multirust_bin() {
    use rustup_utils::utils;
    use std::env::consts::EXE_SUFFIX;
    use std::fs;

    if let Ok(home) = utils::cargo_home() {
        let legacy_bin = home.join(format!("bin/multirust{}", EXE_SUFFIX));
        if legacy_bin.exists() {
            let _ = fs::remove_file(legacy_bin);
        }
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::cmp::Ordering;
use rand::{ChaChaRng, SeedableRng};
use {DeterministicRandomId, PredictorId, TimeId, RowId, FieldId, SiphashIdGenerator,
     IterationType, Basics, ExtendedTime, GenericExtendedTime};

// https://github.com/rust-lang/rfcs/issues/1485
pub trait Filter<T> {
  fn filter<P: FnOnce(&T) -> bool>(self, predicate: P) -> Self;
}
impl<T> Filter<T> for Option<T> {
  fn filter<P: FnOnce(&T) -> bool>(self, predicate: P) -> Self {
    self.and_then(|x| { if predicate(&x) { Some(x) } else { None } })
  }
}

type EventRng = ChaChaRng;
fn generator_for_event(id: TimeId) -> EventRng {
  EventRng::from_seed(&[(id.data()[0] >> 32) as u32,
                        (id.data()[0] & 0xffffffff) as u32,
                        (id.data()[1] >> 32) as u32,
                        (id.data()[1] & 0xffffffff) as u32])
}

#[macro_export]
macro_rules! time_steward_common_dynamic_callback_structs {

($M: ident, $PA: ident, $DynamicEventFn: ident, $DynamicPredictorFn: ident, $DynamicPredictor: ident, $StandardSettings: ident) => {

mod __time_steward_make_dynamic_callbacks_impl {

use $crate::{Basics, Event, Predictor, RowId, ColumnId, PredictorId, StewardRc, PredictorList, predictor_list};
use std::collections::HashMap;
use std::marker::PhantomData;

pub struct DynamicEventFn <E: Event> (E);
pub struct DynamicPredictorFn <P: Predictor> (PhantomData <P>);

impl<E: Event> DynamicEventFn <E> {
  pub fn new (event: E)->Self {DynamicEventFn (event)}
}
impl<P: Predictor> DynamicPredictorFn <P> {
  pub fn new ()->Self {DynamicPredictorFn (PhantomData)}
}

impl<'a, 'b, E: Event> Fn <(& 'a mut super::$M <'b, E::Basics>,)> for DynamicEventFn <E> {
  extern "rust-call" fn call (&self, arguments: (& 'a mut super::$M <'b, E::Basics>,)) {
    self.0.call (arguments.0)
  }
}
impl<'a, 'b, P: Predictor> Fn <(& 'a mut super::$PA <'b, P::Basics>, RowId)> for DynamicPredictorFn <P> {
  extern "rust-call" fn call (&self, arguments: (& 'a mut super::$PA <'b, P::Basics>, RowId)) {
    P::call (arguments.0, arguments.1)
  }
}

impl<'a, 'b, E: Event> FnMut <(& 'a mut super::$M <'b, E::Basics>,)> for DynamicEventFn <E> {
  extern "rust-call" fn call_mut (&mut self, arguments: (& 'a mut super::$M <'b, E::Basics>,)) {
    self.call (arguments)
  }
}
impl<'a, 'b, E: Event> FnOnce <(& 'a mut super::$M <'b, E::Basics>,)> for DynamicEventFn <E> {
  type Output = ();
  extern "rust-call" fn call_once (self, arguments: (& 'a mut super::$M <'b, E::Basics>,)) {
    self.call (arguments)
  }
}

impl<'a, 'b, P: Predictor> FnMut <(& 'a mut super::$PA <'b, P::Basics>, RowId)> for DynamicPredictorFn <P> {
  extern "rust-call" fn call_mut (&mut self, arguments: (& 'a mut super::$PA <'b, P::Basics>, RowId)) {
    self.call (arguments)
  }
}
impl<'a, 'b, P: Predictor> FnOnce <(& 'a mut super::$PA <'b, P::Basics>, RowId)> for DynamicPredictorFn <P> {
  type Output = ();
  extern "rust-call" fn call_once (self, arguments: (& 'a mut super::$PA <'b, P::Basics>, RowId)) {
    self.call (arguments)
  }
}

//trait DynamicPredictorTrait: for <'a, 'b> Fn(& 'a mut super::$PA <'b, B>, RowId) {
//
//}

// #[derive (Clone)]
pub struct DynamicPredictor <B: Basics> {
  pub predictor_id: PredictorId,
  pub column_id: ColumnId,
  pub function: StewardRc <for <'a, 'b> Fn(& 'a mut super::$PA <'b, B>, RowId)>,
  _marker: PhantomData <B>,
}
// explicitly implement Clone to work around [a compiler weakness](https://github.com/rust-lang/rust/issues/26925).
impl<B: Basics> Clone for DynamicPredictor<B> {
  fn clone(&self) -> Self {
    DynamicPredictor {
      predictor_id: self.predictor_id,
      column_id: self.column_id,
      function: self.function.clone(),
      _marker: PhantomData,
    }
  }
}

#[derive (Clone)]
pub struct StandardSettings <B: Basics> {
  pub predictors_by_column: HashMap<ColumnId, Vec<DynamicPredictor <B>>>,
  pub predictors_by_id: HashMap<PredictorId, DynamicPredictor <B>>,
}
impl<B: Basics> predictor_list::User <B> for StandardSettings <B> {
  fn apply <P: Predictor <Basics = B>> (&mut self) {
    let predictor = DynamicPredictor {
      predictor_id: P::predictor_id(),
      column_id: P::column_id(),
      function: StewardRc::new (DynamicPredictorFn::<P>::new ()),
      _marker: PhantomData,
    };
    self.predictors_by_id.insert(predictor.predictor_id, predictor.clone());
    self.predictors_by_column.entry(predictor.column_id).or_insert(Vec::new()).push(predictor);
  }
}
impl<B: Basics> StandardSettings <B> {
  pub fn new()->Self {
    let mut result = StandardSettings {
      predictors_by_id: HashMap::new(),
      predictors_by_column: HashMap::new(),
    };
    B::IncludedTypes::apply (&mut result);
    result
  }
}

}

#[allow (unused_imports)]
use self::__time_steward_make_dynamic_callbacks_impl::DynamicEventFn as $DynamicEventFn;
#[allow (unused_imports)]
use self::__time_steward_make_dynamic_callbacks_impl::DynamicPredictor as $DynamicPredictor;
#[allow (unused_imports)]
use self::__time_steward_make_dynamic_callbacks_impl::DynamicPredictorFn as $DynamicPredictorFn;
pub use self::__time_steward_make_dynamic_callbacks_impl::StandardSettings as $StandardSettings;

}}

pub struct GenericPredictorAccessor<B: Basics, E> {
  pub soonest_prediction: Option<(B::Time, E)>,
  pub dependencies: RefCell<(Vec<FieldId>, SiphashIdGenerator)>,
}
impl<B: Basics, E> GenericPredictorAccessor<B, E> {
  pub fn new() -> Self {
    GenericPredictorAccessor {
      soonest_prediction: None,
      dependencies: RefCell::new((Vec::new(), SiphashIdGenerator::new())),
    }
  }
}
#[macro_export]
macro_rules! time_steward_common_accessor_methods_for_predictor_accessor {
  ($B: ty, $get: ident) => {
    fn generic_data_and_extended_last_change(&self,
                                             id: FieldId)
                                             -> Option<(&FieldRc, &ExtendedTime<$B>)> {
      let dependencies: &mut (Vec<FieldId>, SiphashIdGenerator) = &mut*self.generic.dependencies.borrow_mut();
      dependencies.0.push(id);
      self.$get(id).map(|p| {
        {
          use bincode;
          use serde::Serialize;
          let mut serializer = bincode::serde::Serializer::new (&mut dependencies.1);
          p.1.id.serialize (&mut serializer).unwrap();
        }
        p
      })
    }
  }
}
#[macro_export]
macro_rules! time_steward_common_predictor_accessor_methods_for_predictor_accessor {
  ($B: ty, $DynamicEventFn: ident) => {
    fn predict_at_time <E: $crate::Event <Basics = $B>> (&mut self, time: <$B as $crate::Basics>::Time, event: E) {
      if time < *self.unsafe_now() {
        return;
      }
      if let Some((ref old_time, _)) = self.generic.soonest_prediction {
        if old_time <= &time {
          return;
        }
      }
      self.generic.soonest_prediction = Some((time, StewardRc::new ($DynamicEventFn ::new (event))));
    }
  }
}

pub struct GenericMutator<B: Basics> {
  pub now: ExtendedTime<B>,
  pub generator: ChaChaRng,
}
impl<B: Basics> GenericMutator<B> {
  pub fn new(now: ExtendedTime<B>) -> Self {
    let generator = generator_for_event(now.id);
    GenericMutator {
      now: now,
      generator: generator,
    }
  }
}
#[macro_export]
macro_rules! time_steward_common_accessor_methods_for_mutator {
  ($B: ty) => {
    fn unsafe_now(& self)->& <$B as $crate::Basics>::Time {& self.generic.now.base}
  }
}
#[macro_export]
macro_rules! time_steward_common_mutator_methods_for_mutator {
  ($B: ty) => {
    fn extended_now(& self)->& ExtendedTime <$B> {& self.generic.now}
    fn gen_id(&mut self) -> RowId {RowId::from_rng (&mut self.generic.generator)}
  }
}
#[macro_export]
macro_rules! time_steward_common_rng_methods_for_mutator {
  ($B: ty) => {
    fn next_u32(&mut self) -> u32 {self.generic.generator.next_u32()}

    fn next_f32(&mut self) -> f32 {
      assert!(<$B as $crate::Basics>::allow_floats_unsafe(), "Using floating point numbers in TimeSteward events is forbidden by default because it is nondeterministic across platforms. If you know you don't need to be consistent between different computers, or you otherwise know EXACTLY what you're doing, you may add fn allow_floats_unsafe() {true} to your Basics.");
      self.generic.generator.next_f32()
    }
    fn next_f64(&mut self) -> f64 {
      assert!(<$B as $crate::Basics>::allow_floats_unsafe(), "Using floating point numbers in TimeSteward events is forbidden by default because it is nondeterministic across platforms. If you know you don't need to be consistent between different computers, or you otherwise know EXACTLY what you're doing, you may add fn allow_floats_unsafe() {true} to your Basics.");
      self.generic.generator.next_f64()
    }
  }
}

pub fn extended_time_of_fiat_event<BaseTime: Ord>(time: BaseTime,
                                                  id: TimeId)
                                                  -> GenericExtendedTime<BaseTime> {
  GenericExtendedTime {
    base: time,
    iteration: 0,
    id: id.for_fiat_event_internal(),
  }
}

pub fn time_id_for_predicted_event(predictor_id: PredictorId,
                                   row_id: RowId,
                                   iteration: IterationType,
                                   dependencies_hash: DeterministicRandomId)
                                   -> TimeId {
  TimeId::new(&(predictor_id, row_id, iteration, dependencies_hash))
}
pub fn next_extended_time_of_predicted_event<BaseTime: Ord>
  (predictor_id: PredictorId,
   row_id: RowId,
   dependencies_hash: DeterministicRandomId,
   event_base_time: BaseTime,
   from: &GenericExtendedTime<BaseTime>)
   -> Option<GenericExtendedTime<BaseTime>> {
  let (iteration, id) = match event_base_time.cmp(&from.base) {
    Ordering::Less => return None, // short-circuit
    Ordering::Greater => {
      (0, time_id_for_predicted_event(predictor_id, row_id, 0, dependencies_hash))
    }
    Ordering::Equal => {
      let id = time_id_for_predicted_event(predictor_id, row_id, from.iteration, dependencies_hash);
      if id > from.id {
        (from.iteration, id)
      } else {
        if from.iteration == IterationType::max_value() {
          panic!("Too many iterations at the same base time; probably an infinite loop")
        }
        (from.iteration + 1,
         time_id_for_predicted_event(predictor_id, row_id, from.iteration + 1, dependencies_hash))
      }
    }
  };
  Some(GenericExtendedTime {
    base: event_base_time,
    iteration: iteration,
    id: id,
  })
}
<commit_msg>Generalized DynamicEventFn etc. – they didn't actually need to be inside a macro<commit_after>use std::cell::RefCell;
use std::cmp::Ordering;
use rand::{ChaChaRng, SeedableRng};
use {DeterministicRandomId, PredictorId, TimeId, RowId, FieldId, SiphashIdGenerator,
     IterationType, Basics, ExtendedTime, GenericExtendedTime, Predictor, Event, PredictorAccessor, Mutator};
use std::marker::PhantomData;

// https://github.com/rust-lang/rfcs/issues/1485
pub trait Filter<T> {
  fn filter<P: FnOnce(&T) -> bool>(self, predicate: P) -> Self;
}
impl<T> Filter<T> for Option<T> {
  fn filter<P: FnOnce(&T) -> bool>(self, predicate: P) -> Self {
    self.and_then(|x| { if predicate(&x) { Some(x) } else { None } })
  }
}

type EventRng = ChaChaRng;
fn generator_for_event(id: TimeId) -> EventRng {
  EventRng::from_seed(&[(id.data()[0] >> 32) as u32,
                        (id.data()[0] & 0xffffffff) as u32,
                        (id.data()[1] >> 32) as u32,
                        (id.data()[1] & 0xffffffff) as u32])
}

pub struct DynamicEventFn <E: Event> (E);
pub struct DynamicPredictorFn <P: Predictor> (PhantomData <P>);

impl<E: Event> DynamicEventFn <E> {
  pub fn new (event: E)->Self {DynamicEventFn (event)}
}
impl<P: Predictor> DynamicPredictorFn <P> {
  pub fn new ()->Self {DynamicPredictorFn (PhantomData)}
}

impl<'a, 'b, E: Event, M: Mutator <E::Basics>> Fn <(& 'a mut M,)> for DynamicEventFn <E> {
  extern "rust-call" fn call (&self, arguments: (& 'a mut M,)) {
    self.0.call (arguments.0)
  }
}
impl<'a, 'b, P: Predictor, PA: PredictorAccessor <P::Basics>> Fn <(& 'a mut PA, RowId)> for DynamicPredictorFn <P> {
  extern "rust-call" fn call (&self, arguments: (& 'a mut PA, RowId)) {
    P::call (arguments.0, arguments.1)
  }
}

impl<'a, 'b, E: Event, M: Mutator <E::Basics>> FnMut <(& 'a mut M,)> for DynamicEventFn <E> {
  extern "rust-call" fn call_mut (&mut self, arguments: (& 'a mut M,)) {
    self.call (arguments)
  }
}
impl<'a, 'b, E: Event, M: Mutator <E::Basics>> FnOnce <(& 'a mut M,)> for DynamicEventFn <E> {
  type Output = ();
  extern "rust-call" fn call_once (self, arguments: (& 'a mut M,)) {
    self.call (arguments)
  }
}

impl<'a, 'b, P: Predictor, PA: PredictorAccessor <P::Basics>> FnMut <(& 'a mut PA,RowId)> for DynamicPredictorFn <P> {
  extern "rust-call" fn call_mut (&mut self, arguments: (& 'a mut PA, RowId)) {
    self.call (arguments)
  }
}
impl<'a, 'b, P: Predictor, PA: PredictorAccessor <P::Basics>> FnOnce <(& 'a mut PA,RowId)> for DynamicPredictorFn <P> {
  type Output = ();
  extern "rust-call" fn call_once (self, arguments: (& 'a mut PA,RowId)) {
    self.call (arguments)
  }
}

//trait DynamicPredictorTrait <PA: PredictorAccessor>: for <'a, 'b> Fn(& 'a mut PA, RowId) {
 //
//}

#[macro_export]
macro_rules! time_steward_common_dynamic_callback_structs {

($M: ident, $PA: ident, $DynamicEventFn: ident, $DynamicPredictorFn: ident, $DynamicPredictor: ident, $StandardSettings: ident) => {

mod __time_steward_make_dynamic_callbacks_impl {

use $crate::{Basics, Event, Predictor, RowId, ColumnId, PredictorId, StewardRc, PredictorList, predictor_list};
use std::collections::HashMap;
use std::marker::PhantomData;

use ::stewards::common::*;

// #[derive (Clone)]
pub struct DynamicPredictor <B: Basics> {
  pub predictor_id: PredictorId,
  pub column_id: ColumnId,
  pub function: StewardRc <for <'a, 'b> Fn(& 'a mut super::$PA <'b, B>, RowId)>,
  _marker: PhantomData <B>,
}
// explicitly implement Clone to work around [a compiler weakness](https://github.com/rust-lang/rust/issues/26925).
impl<B: Basics> Clone for DynamicPredictor<B> {
  fn clone(&self) -> Self {
    DynamicPredictor {
      predictor_id: self.predictor_id,
      column_id: self.column_id,
      function: self.function.clone(),
      _marker: PhantomData,
    }
  }
}

#[derive (Clone)]
pub struct StandardSettings <B: Basics> {
  pub predictors_by_column: HashMap<ColumnId, Vec<DynamicPredictor <B>>>,
  pub predictors_by_id: HashMap<PredictorId, DynamicPredictor <B>>,
}
impl<B: Basics> predictor_list::User <B> for StandardSettings <B> {
  fn apply <P: Predictor <Basics = B>> (&mut self) {
    let predictor = DynamicPredictor {
      predictor_id: P::predictor_id(),
      column_id: P::column_id(),
      function: StewardRc::new (DynamicPredictorFn::<P>::new ()),
      _marker: PhantomData,
    };
    self.predictors_by_id.insert(predictor.predictor_id, predictor.clone());
    self.predictors_by_column.entry(predictor.column_id).or_insert(Vec::new()).push(predictor);
  }
}
impl<B: Basics> StandardSettings <B> {
  pub fn new()->Self {
    let mut result = StandardSettings {
      predictors_by_id: HashMap::new(),
      predictors_by_column: HashMap::new(),
    };
    B::IncludedTypes::apply (&mut result);
    result
  }
}

}

#[allow (unused_imports)]
use ::stewards::common::DynamicEventFn as $DynamicEventFn;
#[allow (unused_imports)]
use self::__time_steward_make_dynamic_callbacks_impl::DynamicPredictor as $DynamicPredictor;
#[allow (unused_imports)]
use ::stewards::common::DynamicPredictorFn as $DynamicPredictorFn;
pub use self::__time_steward_make_dynamic_callbacks_impl::StandardSettings as $StandardSettings;

}}

pub struct GenericPredictorAccessor<B: Basics, E> {
  pub soonest_prediction: Option<(B::Time, E)>,
  pub dependencies: RefCell<(Vec<FieldId>, SiphashIdGenerator)>,
}
impl<B: Basics, E> GenericPredictorAccessor<B, E> {
  pub fn new() -> Self {
    GenericPredictorAccessor {
      soonest_prediction: None,
      dependencies: RefCell::new((Vec::new(), SiphashIdGenerator::new())),
    }
  }
}
#[macro_export]
macro_rules! time_steward_common_accessor_methods_for_predictor_accessor {
  ($B: ty, $get: ident) => {
    fn generic_data_and_extended_last_change(&self,
                                             id: FieldId)
                                             -> Option<(&FieldRc, &ExtendedTime<$B>)> {
      let dependencies: &mut (Vec<FieldId>, SiphashIdGenerator) = &mut*self.generic.dependencies.borrow_mut();
      dependencies.0.push(id);
      self.$get(id).map(|p| {
        {
          use bincode;
          use serde::Serialize;
          let mut serializer = bincode::serde::Serializer::new (&mut dependencies.1);
          p.1.id.serialize (&mut serializer).unwrap();
        }
        p
      })
    }
  }
}
#[macro_export]
macro_rules! time_steward_common_predictor_accessor_methods_for_predictor_accessor {
  ($B: ty, $DynamicEventFn: ident) => {
    fn predict_at_time <E: $crate::Event <Basics = $B>> (&mut self, time: <$B as $crate::Basics>::Time, event: E) {
      if time < *self.unsafe_now() {
        return;
      }
      if let Some((ref old_time, _)) = self.generic.soonest_prediction {
        if old_time <= &time {
          return;
        }
      }
      self.generic.soonest_prediction = Some((time, StewardRc::new ($DynamicEventFn ::new (event))));
    }
  }
}

pub struct GenericMutator<B: Basics> {
  pub now: ExtendedTime<B>,
  pub generator: ChaChaRng,
}
impl<B: Basics> GenericMutator<B> {
  pub fn new(now: ExtendedTime<B>) -> Self {
    let generator = generator_for_event(now.id);
    GenericMutator {
      now: now,
      generator: generator,
    }
  }
}
#[macro_export]
macro_rules! time_steward_common_accessor_methods_for_mutator {
  ($B: ty) => {
    fn unsafe_now(& self)->& <$B as $crate::Basics>::Time {& self.generic.now.base}
  }
}
#[macro_export]
macro_rules! time_steward_common_mutator_methods_for_mutator {
  ($B: ty) => {
    fn extended_now(& self)->& ExtendedTime <$B> {& self.generic.now}
    fn gen_id(&mut self) -> RowId {RowId::from_rng (&mut self.generic.generator)}
  }
}
#[macro_export]
macro_rules! time_steward_common_rng_methods_for_mutator {
  ($B: ty) => {
    fn next_u32(&mut self) -> u32 {self.generic.generator.next_u32()}

    fn next_f32(&mut self) -> f32 {
      assert!(<$B as $crate::Basics>::allow_floats_unsafe(), "Using floating point numbers in TimeSteward events is forbidden by default because it is nondeterministic across platforms. If you know you don't need to be consistent between different computers, or you otherwise know EXACTLY what you're doing, you may add fn allow_floats_unsafe() {true} to your Basics.");
      self.generic.generator.next_f32()
    }
    fn next_f64(&mut self) -> f64 {
      assert!(<$B as $crate::Basics>::allow_floats_unsafe(), "Using floating point numbers in TimeSteward events is forbidden by default because it is nondeterministic across platforms. If you know you don't need to be consistent between different computers, or you otherwise know EXACTLY what you're doing, you may add fn allow_floats_unsafe() {true} to your Basics.");
      self.generic.generator.next_f64()
    }
  }
}

pub fn extended_time_of_fiat_event<BaseTime: Ord>(time: BaseTime,
                                                  id: TimeId)
                                                  -> GenericExtendedTime<BaseTime> {
  GenericExtendedTime {
    base: time,
    iteration: 0,
    id: id.for_fiat_event_internal(),
  }
}

pub fn time_id_for_predicted_event(predictor_id: PredictorId,
                                   row_id: RowId,
                                   iteration: IterationType,
                                   dependencies_hash: DeterministicRandomId)
                                   -> TimeId {
  TimeId::new(&(predictor_id, row_id, iteration, dependencies_hash))
}
pub fn next_extended_time_of_predicted_event<BaseTime: Ord>
  (predictor_id: PredictorId,
   row_id: RowId,
   dependencies_hash: DeterministicRandomId,
   event_base_time: BaseTime,
   from: &GenericExtendedTime<BaseTime>)
   -> Option<GenericExtendedTime<BaseTime>> {
  let (iteration, id) = match event_base_time.cmp(&from.base) {
    Ordering::Less => return None, // short-circuit
    Ordering::Greater => {
      (0, time_id_for_predicted_event(predictor_id, row_id, 0, dependencies_hash))
    }
    Ordering::Equal => {
      let id = time_id_for_predicted_event(predictor_id, row_id, from.iteration, dependencies_hash);
      if id > from.id {
        (from.iteration, id)
      } else {
        if from.iteration == IterationType::max_value() {
          panic!("Too many iterations at the same base time; probably an infinite loop")
        }
        (from.iteration + 1,
         time_id_for_predicted_event(predictor_id, row_id, from.iteration + 1, dependencies_hash))
      }
    }
  };
  Some(GenericExtendedTime {
    base: event_base_time,
    iteration: iteration,
    id: id,
  })
}
<|endoftext|>


<commit_before>
// struct Node <V> {
//     next: Option<Box<Node<V>>>,
//     val: V,
// }

// struct LinkedList <V> {
//     size: u16,
//     head: Option<Node<V>>,

// }

// impl <V> LinkedList <V> {
//     pub fn new() -> Self {
//         LinkedList {
//             size: 0,
//             head: None,
//         }
//     }
//     pub fn push(&mut self, val: V) -> &mut Self {
//         let added_node = Node {
//             val: val,
//             next: self.head.take().map(|x| Box::new(x))
//         };

//         self.head = Some(added_node);
//         self
//     }
//     pub fn pop(&mut self) -> Option<V> {
//         //we need to pull out the 'next' value from the head node
//         self.head.take().map(|node| {
//             self.head = node.next.map(|x| *x);
//             node.val
//         })
//     }
//     pub fn peek(&self) -> Option<&V> {
//         self.head.as_ref().map(|x| &x.val)
//     }
//     pub fn peek_mut(&mut self) -> Option<&mut V> {
//         self.head.as_mut().map(|x| &mut x.val)
//     }

//     // Iterator
//     pub fn into_iter(self) -> IntoIter<V> {
//         IntoIter(self)
//     }
// }

// impl <V> Drop for LinkedList <V> {
//     fn drop(&mut self) {
//         let mut cur_node = self.head.take();
//         while let Some(mut node) = cur_node {
//             cur_node = node.next.take().map(|x| *x);
//         }
//     }
// }

// pub struct IntoIter<T>(LinkedList<T>);

// impl<T> Iterator for IntoIter<T> {
//     type Item = T;
//     fn next(&mut self) -> Option<Self::Item> {
//         self.0.pop()
//     }
// }

// // Break

// pub struct Iter<'a, T: 'a> {
//     next: Option<&'a Node<T>>,
// }

// impl<T> LinkedList<T> {
//     pub fn iter<'a>(&'a self) -> Iter<'a, T> {
//         Iter {
//             next: self.head.as_ref().map(|node| node)
//         }
//     }
// }

// impl<'a, T> Iterator for Iter<'a, T> {
//     type Item = &'a T;
//     fn next(&mut self) -> Option<Self::Item> {
//         self.next.map(|node| {
//             self.next = node.next.as_ref().map(|node| &**node);
//             &node.val
//         })
//     }
// }

// // Iter Mut

// pub struct IterMut<'a, T: 'a> {
//     next: Option<'a mut Node<T>>,
// }

// impl<T> LinkedList<T> {
//     pub fn iter_mut(&self) -> IterMut<T> {
//         IterMut {
//             next: self.head.as_mut().map(|node| &mut *node)
//         }
//     }
// }

// impl<'a, T> Iterator for IterMut<'a, T> {
//     type Item = 'a mut T;
//     fn next(&mut self) -> Option<Self::Item> {
//         self.next.map(|node| {
//             self.next = node.next.map(|node| &mut **node);
//             &mut node.val
//         })
//     }
// }

// mod test {
//     use super::LinkedList;
//     #[test]
//     fn basics() {
//         let mut list = LinkedList::new();

//         // Check empty list behaves right
//         assert_eq!(list.pop(), None);

//         // Populate list
//         list.push(1);
//         list.push(2);
//         list.push(3);

//         // Check normal removal
//         assert_eq!(list.pop(), Some(3));
//         assert_eq!(list.pop(), Some(2));

//         // Push some more just to make sure nothing's corrupted
//         list.push(4);
//         list.push(5);

//         // Check normal removal
//         assert_eq!(list.pop(), Some(5));
//         assert_eq!(list.pop(), Some(4));

//         // Check exhaustion
//         assert_eq!(list.pop(), Some(1));
//         assert_eq!(list.pop(), None);
//     }

//     #[test]
//     fn peek() {
//         let mut list = LinkedList::new();
//         assert_eq!(list.peek(), None);
//         assert_eq!(list.peek_mut(), None);
//         list.push(1); list.push(2); list.push(3);

//         assert_eq!(list.peek(), Some(&3));
//         assert_eq!(list.peek_mut(), Some(&mut 3));
//     }

//     #[test]
//     fn into_iter() {
//         let mut list = LinkedList::new();
//         list.push(1); list.push(2); list.push(3);

//         let mut iter = list.into_iter();
//         assert_eq!(iter.next(), Some(3));
//         assert_eq!(iter.next(), Some(2));
//         assert_eq!(iter.next(), Some(1));
//     }

//     #[test]
//     fn iter() {
//         let mut list = LinkedList::new();
//         list.push(1); list.push(2); list.push(3);

//         let mut iter = list.iter();
//         assert_eq!(iter.next(), Some(&3));
//         assert_eq!(iter.next(), Some(&2));
//         assert_eq!(iter.next(), Some(&1));
//     }
// }
<commit_msg>updates iter_mut for first implementation<commit_after>
struct Node <V> {
    next: Option<Box<Node<V>>>,
    val: V,
}

struct LinkedList <V> {
    size: u16,
    head: Option<Node<V>>,

}

impl <V> LinkedList <V> {
    pub fn new() -> Self {
        LinkedList {
            size: 0,
            head: None,
        }
    }
    pub fn push(&mut self, val: V) -> &mut Self {
        let added_node = Node {
            val: val,
            next: self.head.take().map(|x| Box::new(x))
        };

        self.head = Some(added_node);
        self
    }
    pub fn pop(&mut self) -> Option<V> {
        //we need to pull out the 'next' value from the head node
        self.head.take().map(|node| {
            self.head = node.next.map(|x| *x);
            node.val
        })
    }
    pub fn peek(&self) -> Option<&V> {
        self.head.as_ref().map(|x| &x.val)
    }
    pub fn peek_mut(&mut self) -> Option<&mut V> {
        self.head.as_mut().map(|x| &mut x.val)
    }

    // Iterator
    pub fn into_iter(self) -> IntoIter<V> {
        IntoIter(self)
    }
}

impl <V> Drop for LinkedList <V> {
    fn drop(&mut self) {
        let mut cur_node = self.head.take();
        while let Some(mut node) = cur_node {
            cur_node = node.next.take().map(|x| *x);
        }
    }
}

pub struct IntoIter<T>(LinkedList<T>);

impl<T> Iterator for IntoIter<T> {
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        self.0.pop()
    }
}

// Break

pub struct Iter<'a, T: 'a> {
    next: Option<&'a Node<T>>,
}

impl<T> LinkedList<T> {
    pub fn iter<'a>(&'a self) -> Iter<'a, T> {
        Iter {
            next: self.head.as_ref().map(|node| node)
        }
    }
}

impl<'a, T> Iterator for Iter<'a, T> {
    type Item = &'a T;
    fn next(&mut self) -> Option<Self::Item> {
        self.next.map(|node| {
            self.next = node.next.as_ref().map(|node| &**node);
            &node.val
        })
    }
}

pub struct IterMut<'a, T: 'a> {
    next: Option<&'a mut Node<T>>,
}

impl<T> LinkedList<T> {
    pub fn iter_mut(&mut self) -> IterMut<T> {
        IterMut {
            next: self.head.as_mut().map(|node| &mut *node)
        }
    }
}

impl<'a, T> Iterator for IterMut<'a, T> {
    type Item = &'a mut T;
    fn next(&mut self) -> Option<Self::Item> {
        self.next.take().map(|node| {
            self.next = node.next.as_mut().map(|node| &mut **node);
            &mut node.val
        })
    }
}

mod test {
    use super::LinkedList;
    #[test]
    fn basics() {
        let mut list = LinkedList::new();

        // Check empty list behaves right
        assert_eq!(list.pop(), None);

        // Populate list
        list.push(1);
        list.push(2);
        list.push(3);

        // Check normal removal
        assert_eq!(list.pop(), Some(3));
        assert_eq!(list.pop(), Some(2));

        // Push some more just to make sure nothing's corrupted
        list.push(4);
        list.push(5);

        // Check normal removal
        assert_eq!(list.pop(), Some(5));
        assert_eq!(list.pop(), Some(4));

        // Check exhaustion
        assert_eq!(list.pop(), Some(1));
        assert_eq!(list.pop(), None);
    }

    #[test]
    fn peek() {
        let mut list = LinkedList::new();
        assert_eq!(list.peek(), None);
        assert_eq!(list.peek_mut(), None);
        list.push(1); list.push(2); list.push(3);

        assert_eq!(list.peek(), Some(&3));
        assert_eq!(list.peek_mut(), Some(&mut 3));
    }

    #[test]
    fn into_iter() {
        let mut list = LinkedList::new();
        list.push(1); list.push(2); list.push(3);

        let mut iter = list.into_iter();
        assert_eq!(iter.next(), Some(3));
        assert_eq!(iter.next(), Some(2));
        assert_eq!(iter.next(), Some(1));
    }

    #[test]
    fn iter() {
        let mut list = LinkedList::new();
        list.push(1); list.push(2); list.push(3);

        let mut iter = list.iter();
        assert_eq!(iter.next(), Some(&3));
        assert_eq!(iter.next(), Some(&2));
        assert_eq!(iter.next(), Some(&1));
    }

    #[test]
    fn iter_mut() {
        let mut list = LinkedList::new();
        list.push(1); list.push(2); list.push(3);

        let mut iter = list.iter_mut();
        assert_eq!(iter.next(), Some(&mut 3));
        assert_eq!(iter.next(), Some(&mut 2));
        assert_eq!(iter.next(), Some(&mut 1));
    }
}
<|endoftext|>