<commit_before>extern crate gstreamer as gst;

#[cfg(feature = "profiling-audio-buffer")]
use chrono::Utc;

use byte_slice_cast::AsSliceOf;

use std::i16;

use std::collections::vec_deque::VecDeque;

use super::{DoubleSampleExtractor};

pub const SAMPLES_NORM: f64 = 200f64;
const SAMPLES_OFFSET: f64 = SAMPLES_NORM / 2f64;

pub struct AudioBuffer {
    capacity: usize,
    pub sample_duration: f64,
    channels: usize,
    drain_size: usize,

    pub eos: bool,

    segement_first_sample: usize,
    last_buffer_pts: u64,
    last_buffer_last_sample: usize,
    pub first_sample: usize,
    pub last_sample: usize,
    pub samples: VecDeque<f64>,

    samples_extractor_opt: Option<DoubleSampleExtractor>,
}

impl AudioBuffer {
    pub fn new(
        caps: &gst::Caps,
        buffer_duration: u64,
        samples_extractor: DoubleSampleExtractor,
    ) -> Self
    {
        let structure = caps.get_structure(0)
            .expect("Couldn't get structure from audio caps");
        let rate = structure.get::<i32>("rate")
            .expect("Couldn't get rate from audio caps");

        // assert_eq!(format, S16);
        // assert_eq!(layout, Interleaved);

        let sample_duration = 1_000_000_000f64 / (rate as f64);
        let capacity = (buffer_duration as f64 / sample_duration) as usize;

        let drain_size = (1_000_000_000f64 / sample_duration) as usize; // 1s worth of samples

        AudioBuffer {
            capacity: capacity,
            sample_duration: sample_duration,
            channels: structure.get::<i32>("channels")
                .expect("Couldn't get channels from audio sample")
                as usize,
            drain_size: drain_size,

            eos: false,

            segement_first_sample: 0,
            last_buffer_pts: 0,
            last_buffer_last_sample: 0,
            first_sample: 0,
            last_sample: 0,
            samples: VecDeque::with_capacity(capacity),

            samples_extractor_opt: Some(samples_extractor),
        }
    }

    // Add samples from the GStreamer pipeline to the AudioBuffer
    // This buffer stores the complete set of samples in a time frame
    // in order to be able to represent the audio at any given precision.
    // Samples are stores as f64 suitable for on screen rendering.
    // This implementation also performs a downmix.
    // TODO: make the representation dependent on the actual context
    //       move this as a trait and make the sample normalization
    //       part of a concrete object
    // Incoming samples are merged to the existing buffer when possible
    pub fn push_gst_sample(&mut self, sample: gst::Sample) {
        #[cfg(feature = "profiling-audio-buffer")]
        let start = Utc::now();

        let buffer = sample.get_buffer()
            .expect("Couldn't get buffer from audio sample");

        let map = buffer.map_readable().unwrap();
        let incoming_samples = map.as_slice().as_slice_of::<i16>()
            .expect("Couldn't get audio samples as i16");

        #[cfg(feature = "profiling-audio-buffer")]
        let before_drain = Utc::now();

        self.eos = false;

        let segment_first_sample = (
            sample.get_segment().unwrap().get_start() as f64 / self.sample_duration
        ) as usize;
        let buffer_sample_len = incoming_samples.len() / self.channels;
        let buffer_pts = buffer.get_pts();

        // Identify conditions for this incoming buffer:
        // 1. Incoming buffer fits at the end of current container.
        // 2. Incoming buffer is already contained within stored samples.
        //    Nothing to do.
        // 3. Incoming buffer overlaps with stored samples at the end.
        // 4. Incoming buffer overlaps with stored samples at the begining.
        //    Note: this changes the first sample and requires to extend
        //    the internal container from the begining.
        // 5. Incoming buffer doesn't overlap with current buffer. In order
        //    not to let gaps between samples, the internal container is
        //    cleared first.
        // 6. The internal container is empty, import incoming buffer
        //    completely.
        let (
            first_sample_changed,
            was_seek,
            first_incoming_sample,
            first_sample_to_add_rel,
            last_sample_to_add_rel
        ) =
            if !self.samples.is_empty()
            {   // not initializing
                let (first_incoming_sample, was_seek) =
                    if segment_first_sample == self.segement_first_sample {
                        // receiving next buffer in the same segment
                        if buffer_pts > self.last_buffer_pts {
                            // ... and getting a more recent buffer than previous
                            // => assuming incoming buffer comes just after previous
                            (self.last_buffer_last_sample, false)
                        } else {
                            // ... but incoming buffer is ealier in the stream
                            // => probably a seek back to the begining
                            // of current segment
                            // (e.g. seeking at the begining of current chapter)
                            (segment_first_sample, true)
                        }
                    } else {
                        // different segment (done seeking)
                        self.segement_first_sample = segment_first_sample;
                        self.last_buffer_last_sample = segment_first_sample;
                        (segment_first_sample, true)
                    };
                let last_incoming_sample = first_incoming_sample + buffer_sample_len;

                if first_incoming_sample == self.last_sample {
                    // 1. append incoming buffer to the end of internal storage
                    //println!("AudioBuffer appending full incoming buffer to the end");
                    // self.first_sample unchanged
                    self.last_sample = last_incoming_sample;
                    self.last_buffer_last_sample = last_incoming_sample;

                    (
                        false,                  // first_sample_changed
                        was_seek,               // was_seek
                        first_incoming_sample,  // first_incoming_sample
                        0,                      // first_sample_to_add_rel
                        buffer_sample_len       // last_sample_to_add_rel
                    )
                } else if first_incoming_sample >= self.first_sample
                && last_incoming_sample <= self.last_sample {
                    // 2. incoming buffer included in current container
                    self.last_buffer_last_sample = last_incoming_sample;
                    (
                        false,                  // first_sample_changed
                        was_seek,               // was_seek
                        first_incoming_sample,  // first_incoming_sample
                        0,                      // first_sample_to_add_rel
                        0                       // last_sample_to_add_rel
                    )
                } else if first_incoming_sample > self.first_sample
                && first_incoming_sample < self.last_sample
                {   // 3. can append [self.last_sample, last_sample] to the end
                    // self.first_sample unchanged
                    let previous_last_sample = self.last_sample;
                    self.last_sample = last_incoming_sample;
                    // self.first_pts unchanged
                    self.last_buffer_last_sample = last_incoming_sample;
                    (
                        false,                  // first_sample_changed
                        was_seek,               // was_seek
                        first_incoming_sample,  // first_incoming_sample
                        previous_last_sample - segment_first_sample, // first_sample_to_add_rel
                        buffer_sample_len       // last_sample_to_add_rel
                    )
                }
                else if last_incoming_sample < self.last_sample
                && last_incoming_sample > self.first_sample
                {   // 4. can insert [first_sample, self.first_sample] to the begining
                    let last_sample_to_add = self.first_sample;
                    self.first_sample = first_incoming_sample;
                    // self.last_sample unchanged
                    self.last_buffer_last_sample = last_incoming_sample;
                    (
                        true,                   // first_sample_changed
                        was_seek,               // was_seek
                        first_incoming_sample,  // first_incoming_sample
                        0,                      // first_sample_to_add_rel
                        last_sample_to_add - segment_first_sample // last_sample_to_add_rel
                    )
                } else {
                    // 5. can't merge with previous buffer
                    //println!("AudioBuffer: can't merge");
                    self.samples.clear();
                    self.first_sample = first_incoming_sample;
                    self.last_sample = last_incoming_sample;
                    self.last_buffer_last_sample = last_incoming_sample;
                    (
                        true,                   // first_sample_changed
                        was_seek,               // was_seek
                        first_incoming_sample,  // first_incoming_sample
                        0,                      // first_sample_to_add_rel
                        buffer_sample_len       // last_sample_to_add_rel
                    )
                }
            } else {
                // 6. initializing
                self.segement_first_sample = segment_first_sample;
                self.first_sample = segment_first_sample;
                self.last_sample = segment_first_sample + buffer_sample_len;
                self.last_buffer_last_sample = self.last_sample;
                (
                    true,                   // first_sample_changed
                    false,                  // was_seek
                    segment_first_sample,   // first_incoming_sample
                    0,                      // first_sample_to_add_rel
                    buffer_sample_len       // last_sample_to_add_rel
                )
            };

        self.last_buffer_pts = buffer_pts;

        // drain internal buffer if necessary and possible
        if !first_sample_changed
        && self.samples.len() + buffer_sample_len > self.capacity
        {   // don't drain if samples are to be added at the begining...
            // drain only if we have enough samples in history
            // TODO: it could be worth testing truncate instead
            // (this would require reversing the buffer alimentation
            // and iteration)

            // Don't drain samples if they might be used by the extractor
            let first_extractor_sample =
                self.samples_extractor_opt.as_ref().unwrap()
                    .get_first_sample();
            let drain_limit =
                if !was_seek {
                    // was not seeking, keep all samples after
                    // first sample previously used by the extractor
                    first_extractor_sample
                } else {
                    // was seeking, keep first sample that
                    // might be necessary for next extraction
                    first_extractor_sample.min(first_incoming_sample)
                };

            if drain_limit > self.first_sample + self.drain_size {
                //println!("draining... len before: {}", self.samples.len());
                self.samples.drain(..self.drain_size);
                self.first_sample += self.drain_size;
            }
        }

        #[cfg(feature = "profiling-audio-buffer")]
        let before_storage = Utc::now();

        // normalize samples in range 0f64..SAMPLES_NORM ready to render
        // TODO: this depends on the actual context (Waveform rendering)
        // do this in a concrete implementation

        // FIXME: use gstreamer downmix
        // FIXME: select the channels using the position info
        // if more than 2 channels,
        // Use 75% for first 2 channels (assuming front left and front right)
        // Use 25% for the others
        if last_sample_to_add_rel > 0 {
            let (front_norm_factor, others_norm_factor, front_channels) =
                if self.channels > 2 {
                    (
                        0.75f64 / 2f64 / f64::from(i16::MAX) * SAMPLES_NORM / 2f64,
                        0.25f64 / ((self.channels - 2) as f64) / f64::from(i16::MAX) * SAMPLES_NORM / 2f64,
                        2
                    )
                } else {
                    (
                        1f64 / (self.channels as f64) / f64::from(i16::MAX) * SAMPLES_OFFSET,
                        0f64,
                        self.channels
                    )
                };

            // Update container using the conditions identified above
            if !first_sample_changed || self.samples.is_empty()
            {   // samples can be push back to the container
                let mut norm_sample;
                let mut index = first_sample_to_add_rel * self.channels;
                let last = last_sample_to_add_rel * self.channels;
                while index < last {
                    norm_sample = 0f64;

                    for _ in 0..front_channels {
                        norm_sample += f64::from(incoming_samples[index]) * front_norm_factor;
                        index += 1;
                    }
                    for _ in front_channels..self.channels {
                        norm_sample += f64::from(incoming_samples[index]) * others_norm_factor;
                        index += 1;
                    }
                    self.samples.push_back(SAMPLES_OFFSET - norm_sample);
                };
            } else
            {   // samples must be inserted at the begining
                // => push front in reverse order
                let mut norm_sample;
                let mut index = last_sample_to_add_rel * self.channels - 1;
                let first = first_sample_to_add_rel * self.channels;
                while index >= first {
                    norm_sample = 0f64;

                    for _ in front_channels..self.channels {
                        norm_sample += f64::from(incoming_samples[index]) * others_norm_factor;
                        index -= 1;
                    }
                    for _ in 0..front_channels {
                        norm_sample += f64::from(incoming_samples[index]) * front_norm_factor;
                        index -= 1;
                    }
                    self.samples.push_front(SAMPLES_OFFSET - norm_sample);
                };
            }
        }

        // Trigger specific buffer extraction
        #[cfg(feature = "profiling-audio-buffer")]
        let before_extract = Utc::now();

        if !self.samples.is_empty() {
            let mut samples_extractor = self.samples_extractor_opt.take().unwrap();
            samples_extractor.extract_samples(self);
            self.samples_extractor_opt = Some(samples_extractor);
        }

        #[cfg(feature = "profiling-audio-buffer")]
        let end = Utc::now();

        #[cfg(feature = "profiling-audio-buffer")]
        println!("audio-buffer,{},{},{},{},{}",
            start.time().format("%H:%M:%S%.6f"),
            before_drain.time().format("%H:%M:%S%.6f"),
            before_storage.time().format("%H:%M:%S%.6f"),
            before_extract.time().format("%H:%M:%S%.6f"),
            end.time().format("%H:%M:%S%.6f"),
        );
    }

    pub fn iter(&self, first: usize, last: usize, step: usize) -> Iter {
        /*if first < self.first_sample {
            println!("iter {}, {}", first, self.first_sample);
        }*/
        assert!(first >= self.first_sample);
        let last = if last > first { last } else { first };
        Iter::new(self, first, last, step)
    }

    pub fn handle_eos(&mut self) {
        if !self.samples.is_empty() {
            self.eos = true;

            let mut samples_extractor = self.samples_extractor_opt.take().unwrap();
            samples_extractor.extract_samples(self);
            self.samples_extractor_opt = Some(samples_extractor);
        }
    }
}

pub struct Iter<'a> {
    buffer: &'a AudioBuffer,
    idx: usize,
    last: usize,
    step: usize,
}

impl<'a> Iter<'a> {
    fn new(buffer: &'a AudioBuffer, first: usize, last: usize, step: usize) -> Iter<'a> {
        Iter {
            buffer: buffer,
            idx: first - buffer.first_sample,
            last: buffer.samples.len().min(last - buffer.first_sample),
            step: step,
        }
    }
}

impl<'a> Iterator for Iter<'a> {
    type Item = &'a f64;

    fn next(&mut self) -> Option<Self::Item> {
        if self.idx >= self.last {
            return None;
        }

        let item = self.buffer.samples.get(self.idx);
        self.idx += self.step;

        item
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        if self.idx >= self.last {
            return (0, Some(0));
        }

        let remaining = (self.last - self.idx) / self.step;

        (remaining, Some(remaining))
    }
}
<commit_msg>Buffer drain: slight simplification (#24)<commit_after>extern crate gstreamer as gst;

#[cfg(feature = "profiling-audio-buffer")]
use chrono::Utc;

use byte_slice_cast::AsSliceOf;

use std::i16;

use std::collections::vec_deque::VecDeque;

use super::{DoubleSampleExtractor};

pub const SAMPLES_NORM: f64 = 200f64;
const SAMPLES_OFFSET: f64 = SAMPLES_NORM / 2f64;

pub struct AudioBuffer {
    capacity: usize,
    pub sample_duration: f64,
    channels: usize,
    drain_size: usize,

    pub eos: bool,

    segement_first_sample: usize,
    last_buffer_pts: u64,
    last_buffer_last_sample: usize,
    pub first_sample: usize,
    pub last_sample: usize,
    pub samples: VecDeque<f64>,

    samples_extractor_opt: Option<DoubleSampleExtractor>,
}

impl AudioBuffer {
    pub fn new(
        caps: &gst::Caps,
        buffer_duration: u64,
        samples_extractor: DoubleSampleExtractor,
    ) -> Self
    {
        let structure = caps.get_structure(0)
            .expect("Couldn't get structure from audio caps");
        let rate = structure.get::<i32>("rate")
            .expect("Couldn't get rate from audio caps");

        // assert_eq!(format, S16);
        // assert_eq!(layout, Interleaved);

        let sample_duration = 1_000_000_000f64 / (rate as f64);
        let capacity = (buffer_duration as f64 / sample_duration) as usize;

        let drain_size = (1_000_000_000f64 / sample_duration) as usize; // 1s worth of samples

        AudioBuffer {
            capacity: capacity,
            sample_duration: sample_duration,
            channels: structure.get::<i32>("channels")
                .expect("Couldn't get channels from audio sample")
                as usize,
            drain_size: drain_size,

            eos: false,

            segement_first_sample: 0,
            last_buffer_pts: 0,
            last_buffer_last_sample: 0,
            first_sample: 0,
            last_sample: 0,
            samples: VecDeque::with_capacity(capacity),

            samples_extractor_opt: Some(samples_extractor),
        }
    }

    // Add samples from the GStreamer pipeline to the AudioBuffer
    // This buffer stores the complete set of samples in a time frame
    // in order to be able to represent the audio at any given precision.
    // Samples are stores as f64 suitable for on screen rendering.
    // This implementation also performs a downmix.
    // TODO: make the representation dependent on the actual context
    //       move this as a trait and make the sample normalization
    //       part of a concrete object
    // Incoming samples are merged to the existing buffer when possible
    pub fn push_gst_sample(&mut self, sample: gst::Sample) {
        #[cfg(feature = "profiling-audio-buffer")]
        let start = Utc::now();

        let buffer = sample.get_buffer()
            .expect("Couldn't get buffer from audio sample");

        let map = buffer.map_readable().unwrap();
        let incoming_samples = map.as_slice().as_slice_of::<i16>()
            .expect("Couldn't get audio samples as i16");

        #[cfg(feature = "profiling-audio-buffer")]
        let before_drain = Utc::now();

        self.eos = false;

        let segment_first_sample = (
            sample.get_segment().unwrap().get_start() as f64 / self.sample_duration
        ) as usize;
        let buffer_sample_len = incoming_samples.len() / self.channels;
        let buffer_pts = buffer.get_pts();

        // Identify conditions for this incoming buffer:
        // 1. Incoming buffer fits at the end of current container.
        // 2. Incoming buffer is already contained within stored samples.
        //    Nothing to do.
        // 3. Incoming buffer overlaps with stored samples at the end.
        // 4. Incoming buffer overlaps with stored samples at the begining.
        //    Note: this changes the first sample and requires to extend
        //    the internal container from the begining.
        // 5. Incoming buffer doesn't overlap with current buffer. In order
        //    not to let gaps between samples, the internal container is
        //    cleared first.
        // 6. The internal container is empty, import incoming buffer
        //    completely.
        let (
            first_sample_changed,
            first_incoming_sample,
            first_sample_to_add_rel,
            last_sample_to_add_rel
        ) =
            if !self.samples.is_empty()
            {   // not initializing
                let first_incoming_sample =
                    if segment_first_sample == self.segement_first_sample {
                        // receiving next buffer in the same segment
                        if buffer_pts > self.last_buffer_pts {
                            // ... and getting a more recent buffer than previous
                            // => assuming incoming buffer comes just after previous
                            self.last_buffer_last_sample
                        } else {
                            // ... but incoming buffer is ealier in the stream
                            // => probably a seek back to the begining
                            // of current segment
                            // (e.g. seeking at the begining of current chapter)
                            segment_first_sample
                        }
                    } else {
                        // different segment (done seeking)
                        self.segement_first_sample = segment_first_sample;
                        self.last_buffer_last_sample = segment_first_sample;
                        segment_first_sample
                    };
                let last_incoming_sample = first_incoming_sample + buffer_sample_len;

                if first_incoming_sample == self.last_sample {
                    // 1. append incoming buffer to the end of internal storage
                    //println!("AudioBuffer appending full incoming buffer to the end");
                    // self.first_sample unchanged
                    self.last_sample = last_incoming_sample;
                    self.last_buffer_last_sample = last_incoming_sample;

                    (
                        false,                  // first_sample_changed
                        first_incoming_sample,  // first_incoming_sample
                        0,                      // first_sample_to_add_rel
                        buffer_sample_len       // last_sample_to_add_rel
                    )
                } else if first_incoming_sample >= self.first_sample
                && last_incoming_sample <= self.last_sample {
                    // 2. incoming buffer included in current container
                    self.last_buffer_last_sample = last_incoming_sample;
                    (
                        false,                  // first_sample_changed
                        first_incoming_sample,  // first_incoming_sample
                        0,                      // first_sample_to_add_rel
                        0                       // last_sample_to_add_rel
                    )
                } else if first_incoming_sample > self.first_sample
                && first_incoming_sample < self.last_sample
                {   // 3. can append [self.last_sample, last_sample] to the end
                    // self.first_sample unchanged
                    let previous_last_sample = self.last_sample;
                    self.last_sample = last_incoming_sample;
                    // self.first_pts unchanged
                    self.last_buffer_last_sample = last_incoming_sample;
                    (
                        false,                  // first_sample_changed
                        first_incoming_sample,  // first_incoming_sample
                        previous_last_sample - segment_first_sample, // first_sample_to_add_rel
                        buffer_sample_len       // last_sample_to_add_rel
                    )
                }
                else if last_incoming_sample < self.last_sample
                && last_incoming_sample > self.first_sample
                {   // 4. can insert [first_sample, self.first_sample] to the begining
                    let last_sample_to_add = self.first_sample;
                    self.first_sample = first_incoming_sample;
                    // self.last_sample unchanged
                    self.last_buffer_last_sample = last_incoming_sample;
                    (
                        true,                   // first_sample_changed
                        first_incoming_sample,  // first_incoming_sample
                        0,                      // first_sample_to_add_rel
                        last_sample_to_add - segment_first_sample // last_sample_to_add_rel
                    )
                } else {
                    // 5. can't merge with previous buffer
                    //println!("AudioBuffer: can't merge");
                    self.samples.clear();
                    self.first_sample = first_incoming_sample;
                    self.last_sample = last_incoming_sample;
                    self.last_buffer_last_sample = last_incoming_sample;
                    (
                        true,                   // first_sample_changed
                        first_incoming_sample,  // first_incoming_sample
                        0,                      // first_sample_to_add_rel
                        buffer_sample_len       // last_sample_to_add_rel
                    )
                }
            } else {
                // 6. initializing
                self.segement_first_sample = segment_first_sample;
                self.first_sample = segment_first_sample;
                self.last_sample = segment_first_sample + buffer_sample_len;
                self.last_buffer_last_sample = self.last_sample;
                (
                    true,                   // first_sample_changed
                    segment_first_sample,   // first_incoming_sample
                    0,                      // first_sample_to_add_rel
                    buffer_sample_len       // last_sample_to_add_rel
                )
            };

        self.last_buffer_pts = buffer_pts;

        // drain internal buffer if necessary and possible
        if !first_sample_changed
        && self.samples.len() + buffer_sample_len > self.capacity
        {   // don't drain if samples are to be added at the begining...
            // drain only if we have enough samples in history
            // TODO: it could be worth testing truncate instead
            // (this would require reversing the buffer alimentation
            // and iteration)

            // Don't drain samples if they might be used by the extractor
            let first_extractor_sample =
                self.samples_extractor_opt.as_ref().unwrap()
                    .get_first_sample();

            if first_extractor_sample.min(first_incoming_sample)
                > self.first_sample + self.drain_size
            {
                //println!("draining... len before: {}", self.samples.len());
                self.samples.drain(..self.drain_size);
                self.first_sample += self.drain_size;
            }
        }

        #[cfg(feature = "profiling-audio-buffer")]
        let before_storage = Utc::now();

        // normalize samples in range 0f64..SAMPLES_NORM ready to render
        // TODO: this depends on the actual context (Waveform rendering)
        // do this in a concrete implementation

        // FIXME: use gstreamer downmix
        // FIXME: select the channels using the position info
        // if more than 2 channels,
        // Use 75% for first 2 channels (assuming front left and front right)
        // Use 25% for the others
        if last_sample_to_add_rel > 0 {
            let (front_norm_factor, others_norm_factor, front_channels) =
                if self.channels > 2 {
                    (
                        0.75f64 / 2f64 / f64::from(i16::MAX) * SAMPLES_NORM / 2f64,
                        0.25f64 / ((self.channels - 2) as f64) / f64::from(i16::MAX) * SAMPLES_NORM / 2f64,
                        2
                    )
                } else {
                    (
                        1f64 / (self.channels as f64) / f64::from(i16::MAX) * SAMPLES_OFFSET,
                        0f64,
                        self.channels
                    )
                };

            // Update container using the conditions identified above
            if !first_sample_changed || self.samples.is_empty()
            {   // samples can be push back to the container
                let mut norm_sample;
                let mut index = first_sample_to_add_rel * self.channels;
                let last = last_sample_to_add_rel * self.channels;
                while index < last {
                    norm_sample = 0f64;

                    for _ in 0..front_channels {
                        norm_sample += f64::from(incoming_samples[index]) * front_norm_factor;
                        index += 1;
                    }
                    for _ in front_channels..self.channels {
                        norm_sample += f64::from(incoming_samples[index]) * others_norm_factor;
                        index += 1;
                    }
                    self.samples.push_back(SAMPLES_OFFSET - norm_sample);
                };
            } else
            {   // samples must be inserted at the begining
                // => push front in reverse order
                let mut norm_sample;
                let mut index = last_sample_to_add_rel * self.channels - 1;
                let first = first_sample_to_add_rel * self.channels;
                while index >= first {
                    norm_sample = 0f64;

                    for _ in front_channels..self.channels {
                        norm_sample += f64::from(incoming_samples[index]) * others_norm_factor;
                        index -= 1;
                    }
                    for _ in 0..front_channels {
                        norm_sample += f64::from(incoming_samples[index]) * front_norm_factor;
                        index -= 1;
                    }
                    self.samples.push_front(SAMPLES_OFFSET - norm_sample);
                };
            }
        }

        // Trigger specific buffer extraction
        #[cfg(feature = "profiling-audio-buffer")]
        let before_extract = Utc::now();

        if !self.samples.is_empty() {
            let mut samples_extractor = self.samples_extractor_opt.take().unwrap();
            samples_extractor.extract_samples(self);
            self.samples_extractor_opt = Some(samples_extractor);
        }

        #[cfg(feature = "profiling-audio-buffer")]
        let end = Utc::now();

        #[cfg(feature = "profiling-audio-buffer")]
        println!("audio-buffer,{},{},{},{},{}",
            start.time().format("%H:%M:%S%.6f"),
            before_drain.time().format("%H:%M:%S%.6f"),
            before_storage.time().format("%H:%M:%S%.6f"),
            before_extract.time().format("%H:%M:%S%.6f"),
            end.time().format("%H:%M:%S%.6f"),
        );
    }

    pub fn iter(&self, first: usize, last: usize, step: usize) -> Iter {
        /*if first < self.first_sample {
            println!("iter {}, {}", first, self.first_sample);
        }*/
        assert!(first >= self.first_sample);
        let last = if last > first { last } else { first };
        Iter::new(self, first, last, step)
    }

    pub fn handle_eos(&mut self) {
        if !self.samples.is_empty() {
            self.eos = true;

            let mut samples_extractor = self.samples_extractor_opt.take().unwrap();
            samples_extractor.extract_samples(self);
            self.samples_extractor_opt = Some(samples_extractor);
        }
    }
}

pub struct Iter<'a> {
    buffer: &'a AudioBuffer,
    idx: usize,
    last: usize,
    step: usize,
}

impl<'a> Iter<'a> {
    fn new(buffer: &'a AudioBuffer, first: usize, last: usize, step: usize) -> Iter<'a> {
        Iter {
            buffer: buffer,
            idx: first - buffer.first_sample,
            last: buffer.samples.len().min(last - buffer.first_sample),
            step: step,
        }
    }
}

impl<'a> Iterator for Iter<'a> {
    type Item = &'a f64;

    fn next(&mut self) -> Option<Self::Item> {
        if self.idx >= self.last {
            return None;
        }

        let item = self.buffer.samples.get(self.idx);
        self.idx += self.step;

        item
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        if self.idx >= self.last {
            return (0, Some(0));
        }

        let remaining = (self.last - self.idx) / self.step;

        (remaining, Some(remaining))
    }
}
<|endoftext|>


<commit_before>
#[allow(dead_code)]
pub fn multiples(upper_bound: i64) -> i64 {
    let range = 0..upper_bound;
    let divisible = range.filter(|x| x % 3 == 0 || x % 5 == 0);
    let mut sum = 0;
    for x in divisible {
        sum = sum + x;
    }
    sum
}

#[allow(dead_code)]
pub fn multiples_fun(upper_bound: i64) -> i64 {
    let divisible = (0..upper_bound).filter(|x| x % 3 == 0 || x % 5 == 0);
    divisible.fold(0, |sum, x| sum + x)
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn example() {
        assert_eq!(multiples(10), 23);
    }

    #[test]
    fn solution() {
        assert_eq!(multiples(1000), 233168);
    }

    #[test]
    fn example_fun() {
        assert_eq!(multiples_fun(10), 23);
    }

    #[test]
    fn solution_fun() {
        assert_eq!(multiples_fun(1000), 233168);
    }
}
<commit_msg>style changes<commit_after>
#[allow(dead_code)]
pub fn multiples(upper_bound: i64) -> i64 {
    let range = 0..upper_bound;
    let divisible = range.filter(|n| n % 3 == 0 || n % 5 == 0);
    let mut sum = 0;
    for n in divisible {
        sum = sum + n;
    }
    sum
}

#[allow(dead_code)]
pub fn multiples_fun(upper_bound: i64) -> i64 {
    let divisible = (0..upper_bound).filter(|n| n % 3 == 0 || n % 5 == 0);
    divisible.fold(0, |sum, n| sum + n)
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn example() {
        assert_eq!(multiples(10), 23);
    }

    #[test]
    fn solution() {
        assert_eq!(multiples(1000), 233168);
    }

    #[test]
    fn example_fun() {
        assert_eq!(multiples_fun(10), 23);
    }

    #[test]
    fn solution_fun() {
        assert_eq!(multiples_fun(1000), 233168);
    }
}
<|endoftext|>


<commit_before>use crate::{CompileError, Config, Syntax};

use std::path::{Path, PathBuf};
use std::str::FromStr;

use quote::ToTokens;

pub struct TemplateInput<'a> {
    pub ast: &'a syn::DeriveInput,
    pub config: &'a Config<'a>,
    pub syntax: &'a Syntax<'a>,
    pub source: Source,
    pub print: Print,
    pub escaper: &'a str,
    pub ext: Option<String>,
    pub parent: Option<&'a syn::Type>,
    pub path: PathBuf,
}

impl<'a> TemplateInput<'a> {
    /// Extract the template metadata from the `DeriveInput` structure. This
    /// mostly recovers the data for the `TemplateInput` fields from the
    /// `template()` attribute list fields; it also finds the of the `_parent`
    /// field, if any.
    pub fn new<'n>(
        ast: &'n syn::DeriveInput,
        config: &'n Config,
    ) -> Result<TemplateInput<'n>, CompileError> {
        // Check that an attribute called `template()` exists and that it is
        // the proper type (list).
        let meta = ast
            .attrs
            .iter()
            .find_map(|attr| match attr.parse_meta() {
                Ok(m) => {
                    if m.path().is_ident("template") {
                        Some(Ok(m))
                    } else {
                        None
                    }
                }
                Err(e) => Some(Err(format!("unable to parse attribute: {}", e).into())),
            })
            .unwrap_or(Err(CompileError::Static("no attribute 'template' found")))?;

        let meta_list = match meta {
            syn::Meta::List(inner) => inner,
            _ => return Err("attribute 'template' has incorrect type".into()),
        };

        // Loop over the meta attributes and find everything that we
        // understand. Raise panics if something is not right.
        // `source` contains an enum that can represent `path` or `source`.
        let mut source = None;
        let mut print = Print::None;
        let mut escaping = None;
        let mut ext = None;
        let mut syntax = None;
        for item in meta_list.nested {
            let pair = match item {
                syn::NestedMeta::Meta(syn::Meta::NameValue(ref pair)) => pair,
                _ => {
                    return Err(format!(
                        "unsupported attribute argument {:?}",
                        item.to_token_stream()
                    )
                    .into())
                }
            };

            if pair.path.is_ident("path") {
                if let syn::Lit::Str(ref s) = pair.lit {
                    if source.is_some() {
                        return Err("must specify 'source' or 'path', not both".into());
                    }
                    source = Some(Source::Path(s.value()));
                } else {
                    return Err("template path must be string literal".into());
                }
            } else if pair.path.is_ident("source") {
                if let syn::Lit::Str(ref s) = pair.lit {
                    if source.is_some() {
                        return Err("must specify 'source' or 'path', not both".into());
                    }
                    source = Some(Source::Source(s.value()));
                } else {
                    return Err("template source must be string literal".into());
                }
            } else if pair.path.is_ident("print") {
                if let syn::Lit::Str(ref s) = pair.lit {
                    print = s.value().parse()?;
                } else {
                    return Err("print value must be string literal".into());
                }
            } else if pair.path.is_ident("escape") {
                if let syn::Lit::Str(ref s) = pair.lit {
                    escaping = Some(s.value());
                } else {
                    return Err("escape value must be string literal".into());
                }
            } else if pair.path.is_ident("ext") {
                if let syn::Lit::Str(ref s) = pair.lit {
                    ext = Some(s.value());
                } else {
                    return Err("ext value must be string literal".into());
                }
            } else if pair.path.is_ident("syntax") {
                if let syn::Lit::Str(ref s) = pair.lit {
                    syntax = Some(s.value())
                } else {
                    return Err("syntax value must be string literal".into());
                }
            } else {
                return Err(format!(
                    "unsupported attribute key '{}' found",
                    pair.path.to_token_stream()
                )
                .into());
            }
        }

        // Validate the `source` and `ext` value together, since they are
        // related. In case `source` was used instead of `path`, the value
        // of `ext` is merged into a synthetic `path` value here.
        let source = source.expect("template path or source not found in attributes");
        let path = match (&source, &ext) {
            (&Source::Path(ref path), None) => config.find_template(path, None)?,
            (&Source::Source(_), Some(ext)) => PathBuf::from(format!("{}.{}", ast.ident, ext)),
            (&Source::Path(_), Some(_)) => {
                return Err("'ext' attribute cannot be used with 'path' attribute".into())
            }
            (&Source::Source(_), None) => {
                return Err("must include 'ext' attribute when using 'source' attribute".into())
            }
        };

        // Check to see if a `_parent` field was defined on the context
        // struct, and store the type for it for use in the code generator.
        let parent = match ast.data {
            syn::Data::Struct(syn::DataStruct {
                fields: syn::Fields::Named(ref fields),
                ..
            }) => fields
                .named
                .iter()
                .find(|f| f.ident.as_ref().filter(|name| *name == "_parent").is_some())
                .map(|f| &f.ty),
            _ => None,
        };

        if parent.is_some() {
            eprint!(
                "   --> in struct {}\n   = use of deprecated field '_parent'\n",
                ast.ident
            );
        }

        // Validate syntax
        let syntax = syntax.map_or_else(
            || Ok(config.syntaxes.get(config.default_syntax).unwrap()),
            |s| {
                config.syntaxes.get(&s).ok_or_else(|| {
                    CompileError::String(format!("attribute syntax {} not exist", s))
                })
            },
        )?;

        // Match extension against defined output formats

        let extension = escaping.unwrap_or_else(|| {
            path.extension()
                .map(|s| s.to_str().unwrap())
                .unwrap_or("")
                .to_string()
        });

        let mut escaper = None;
        for (extensions, path) in &config.escapers {
            if extensions.contains(&extension) {
                escaper = Some(path);
                break;
            }
        }

        let escaper = escaper.ok_or_else(|| {
            CompileError::String(format!("no escaper defined for extension '{}'", extension,))
        })?;

        Ok(TemplateInput {
            ast,
            config,
            syntax,
            source,
            print,
            escaper,
            ext,
            parent,
            path,
        })
    }

    pub fn extension(&self) -> Option<&str> {
        extension(&self.path)
    }
}

fn extension(path: &Path) -> Option<&str> {
    path.extension().map(|s| s.to_str().unwrap())
}

pub enum Source {
    Path(String),
    Source(String),
}

#[derive(PartialEq)]
pub enum Print {
    All,
    Ast,
    Code,
    None,
}

impl FromStr for Print {
    type Err = CompileError;

    fn from_str(s: &str) -> Result<Print, Self::Err> {
        use self::Print::*;
        Ok(match s {
            "all" => All,
            "ast" => Ast,
            "code" => Code,
            "none" => None,
            v => return Err(format!("invalid value for print option: {}", v,).into()),
        })
    }
}
<commit_msg>Fixed extension to ignore common jinja extensions (fixes #457)<commit_after>use crate::{CompileError, Config, Syntax};

use std::path::{Path, PathBuf};
use std::str::FromStr;

use quote::ToTokens;

pub struct TemplateInput<'a> {
    pub ast: &'a syn::DeriveInput,
    pub config: &'a Config<'a>,
    pub syntax: &'a Syntax<'a>,
    pub source: Source,
    pub print: Print,
    pub escaper: &'a str,
    pub ext: Option<String>,
    pub parent: Option<&'a syn::Type>,
    pub path: PathBuf,
}

impl<'a> TemplateInput<'a> {
    /// Extract the template metadata from the `DeriveInput` structure. This
    /// mostly recovers the data for the `TemplateInput` fields from the
    /// `template()` attribute list fields; it also finds the of the `_parent`
    /// field, if any.
    pub fn new<'n>(
        ast: &'n syn::DeriveInput,
        config: &'n Config,
    ) -> Result<TemplateInput<'n>, CompileError> {
        // Check that an attribute called `template()` exists and that it is
        // the proper type (list).
        let meta = ast
            .attrs
            .iter()
            .find_map(|attr| match attr.parse_meta() {
                Ok(m) => {
                    if m.path().is_ident("template") {
                        Some(Ok(m))
                    } else {
                        None
                    }
                }
                Err(e) => Some(Err(format!("unable to parse attribute: {}", e).into())),
            })
            .unwrap_or(Err(CompileError::Static("no attribute 'template' found")))?;

        let meta_list = match meta {
            syn::Meta::List(inner) => inner,
            _ => return Err("attribute 'template' has incorrect type".into()),
        };

        // Loop over the meta attributes and find everything that we
        // understand. Raise panics if something is not right.
        // `source` contains an enum that can represent `path` or `source`.
        let mut source = None;
        let mut print = Print::None;
        let mut escaping = None;
        let mut ext = None;
        let mut syntax = None;
        for item in meta_list.nested {
            let pair = match item {
                syn::NestedMeta::Meta(syn::Meta::NameValue(ref pair)) => pair,
                _ => {
                    return Err(format!(
                        "unsupported attribute argument {:?}",
                        item.to_token_stream()
                    )
                    .into())
                }
            };

            if pair.path.is_ident("path") {
                if let syn::Lit::Str(ref s) = pair.lit {
                    if source.is_some() {
                        return Err("must specify 'source' or 'path', not both".into());
                    }
                    source = Some(Source::Path(s.value()));
                } else {
                    return Err("template path must be string literal".into());
                }
            } else if pair.path.is_ident("source") {
                if let syn::Lit::Str(ref s) = pair.lit {
                    if source.is_some() {
                        return Err("must specify 'source' or 'path', not both".into());
                    }
                    source = Some(Source::Source(s.value()));
                } else {
                    return Err("template source must be string literal".into());
                }
            } else if pair.path.is_ident("print") {
                if let syn::Lit::Str(ref s) = pair.lit {
                    print = s.value().parse()?;
                } else {
                    return Err("print value must be string literal".into());
                }
            } else if pair.path.is_ident("escape") {
                if let syn::Lit::Str(ref s) = pair.lit {
                    escaping = Some(s.value());
                } else {
                    return Err("escape value must be string literal".into());
                }
            } else if pair.path.is_ident("ext") {
                if let syn::Lit::Str(ref s) = pair.lit {
                    ext = Some(s.value());
                } else {
                    return Err("ext value must be string literal".into());
                }
            } else if pair.path.is_ident("syntax") {
                if let syn::Lit::Str(ref s) = pair.lit {
                    syntax = Some(s.value())
                } else {
                    return Err("syntax value must be string literal".into());
                }
            } else {
                return Err(format!(
                    "unsupported attribute key '{}' found",
                    pair.path.to_token_stream()
                )
                .into());
            }
        }

        // Validate the `source` and `ext` value together, since they are
        // related. In case `source` was used instead of `path`, the value
        // of `ext` is merged into a synthetic `path` value here.
        let source = source.expect("template path or source not found in attributes");
        let path = match (&source, &ext) {
            (&Source::Path(ref path), None) => config.find_template(path, None)?,
            (&Source::Source(_), Some(ext)) => PathBuf::from(format!("{}.{}", ast.ident, ext)),
            (&Source::Path(_), Some(_)) => {
                return Err("'ext' attribute cannot be used with 'path' attribute".into())
            }
            (&Source::Source(_), None) => {
                return Err("must include 'ext' attribute when using 'source' attribute".into())
            }
        };

        // Check to see if a `_parent` field was defined on the context
        // struct, and store the type for it for use in the code generator.
        let parent = match ast.data {
            syn::Data::Struct(syn::DataStruct {
                fields: syn::Fields::Named(ref fields),
                ..
            }) => fields
                .named
                .iter()
                .find(|f| f.ident.as_ref().filter(|name| *name == "_parent").is_some())
                .map(|f| &f.ty),
            _ => None,
        };

        if parent.is_some() {
            eprint!(
                "   --> in struct {}\n   = use of deprecated field '_parent'\n",
                ast.ident
            );
        }

        // Validate syntax
        let syntax = syntax.map_or_else(
            || Ok(config.syntaxes.get(config.default_syntax).unwrap()),
            |s| {
                config.syntaxes.get(&s).ok_or_else(|| {
                    CompileError::String(format!("attribute syntax {} not exist", s))
                })
            },
        )?;

        // Match extension against defined output formats

        let extension = escaping.unwrap_or_else(|| {
            path.extension()
                .map(|s| s.to_str().unwrap())
                .unwrap_or("")
                .to_string()
        });

        let mut escaper = None;
        for (extensions, path) in &config.escapers {
            if extensions.contains(&extension) {
                escaper = Some(path);
                break;
            }
        }

        let escaper = escaper.ok_or_else(|| {
            CompileError::String(format!("no escaper defined for extension '{}'", extension,))
        })?;

        Ok(TemplateInput {
            ast,
            config,
            syntax,
            source,
            print,
            escaper,
            ext,
            parent,
            path,
        })
    }

    pub fn extension(&self) -> Option<&str> {
        extension(&self.path)
    }
}

fn extension(path: &Path) -> Option<&str> {
    let ext = path.extension().map(|s| s.to_str().unwrap())?;

    const JINJA_EXTENSIONS: [&str; 3] = ["j2", "jinja", "jinja2"];
    if JINJA_EXTENSIONS.contains(&ext) {
        Path::new(path.file_stem().unwrap())
            .extension()
            .map(|s| s.to_str().unwrap())
            .or(Some(ext))
    } else {
        Some(ext)
    }
}

pub enum Source {
    Path(String),
    Source(String),
}

#[derive(PartialEq)]
pub enum Print {
    All,
    Ast,
    Code,
    None,
}

impl FromStr for Print {
    type Err = CompileError;

    fn from_str(s: &str) -> Result<Print, Self::Err> {
        use self::Print::*;
        Ok(match s {
            "all" => All,
            "ast" => Ast,
            "code" => Code,
            "none" => None,
            v => return Err(format!("invalid value for print option: {}", v,).into()),
        })
    }
}
<|endoftext|>


<commit_before>pub mod parameter;
mod mem_size;
mod get_value;
mod set_value;

use std::io::{Read, Write};
use std::convert::TryFrom;
use byteorder::ReadBytesExt;
use self::parameter::*;
use self::mem_size::MemSize;
use self::get_value::GetValue;
use self::set_value::SetValue;
use arena::ArenaIndex;
use machine::Machine;
use process::Context;
use core::IDX_MOD;

const OP_CODE_SIZE:     usize = 1;
const PARAM_CODE_SIZE:  usize = 1;

use self::Instruction::*;

#[derive(Debug, Copy, Clone)]
pub enum Instruction {
    NoOp,
    Live(Direct),
    Load(DirInd, Register),
    Store(Register, IndReg),
    Addition(Register, Register, Register),
    Substraction(Register, Register, Register),
    And(DirIndReg, DirIndReg, Register),
    Or(DirIndReg, DirIndReg, Register),
    Xor(DirIndReg, DirIndReg, Register),
    ZJump(Direct),
    LoadIndex(DirIndReg, DirReg, Register),
    StoreIndex(Register, DirIndReg, DirReg),
    Fork(Direct),
    LongLoad(DirInd, Register),
    LongLoadIndex(DirIndReg, DirReg, Register),
    Longfork(Direct),
    Display(Register),
}

impl Instruction {
    pub fn cycle_cost(&self) -> usize {
        match *self {
            NoOp => 1,
            Live(_) => 10,
            Load(_, _) => 5,
            Store(_, _) => 5,
            Addition(_, _, _) => 10,
            Substraction(_, _, _) => 10,
            And(_, _, _) => 6,
            Or(_, _, _) => 6,
            Xor(_, _, _) => 6,
            ZJump(_) => 20,
            LoadIndex(_, _, _) => 25,
            StoreIndex(_, _, _) => 25,
            Fork(_) => 800,
            LongLoad(_, _) => 10,
            LongLoadIndex(_, _, _) => 50,
            Longfork(_) => 1000,
            Display(_) => 2,
        }
    }

    pub fn execute<W: Write>(&self, vm: &mut Machine, context: &mut Context, output: &mut W) {
        match *self {
            NoOp => context.pc = context.pc.advance_by(self.mem_size()),
            Live(player_id) => {
                context.cycle_since_last_live = 0;
                let player = vm.set_last_living_player(player_id.into());
                context.pc = context.pc.advance_by(self.mem_size());
            },
            Load(dir_ind, reg) => {
                let value = dir_ind.get_value(vm, context);
                context.registers[reg] = value;
                context.carry = { value == 0 };
                context.pc = context.pc.advance_by(self.mem_size());
            },
            Store(reg, ind_reg) => {
                let value = context.registers[reg];
                match ind_reg {
                    IndReg::Indirect(ind) => ind.set_value(value, vm, context),
                    IndReg::Register(reg) => context.registers[reg] = value,
                }
                context.pc = context.pc.advance_by(self.mem_size());
            },
            Addition(reg_a, reg_b, reg_c) => {
                let val_a = context.registers[reg_a];
                let val_b = context.registers[reg_b];
                let result = val_a.wrapping_add(val_b);
                context.registers[reg_c] = result;
                context.carry = { result == 0 };
                context.pc = context.pc.advance_by(self.mem_size());
            },
            Substraction(reg_a, reg_b, reg_c) => {
                let val_a = context.registers[reg_a];
                let val_b = context.registers[reg_b];
                let result = val_a.wrapping_sub(val_b);
                context.registers[reg_c] = result;
                context.carry = { result == 0 };
                context.pc = context.pc.advance_by(self.mem_size());
            },
            And(dir_ind_reg_a, dir_ind_reg_b, reg) => {
                let val_a = dir_ind_reg_a.get_value(vm, context);
                let val_b = dir_ind_reg_b.get_value(vm, context);
                let result = val_a & val_b;
                context.registers[reg] = result;
                context.carry = { result == 0 };
                context.pc = context.pc.advance_by(self.mem_size());
            },
            Or(dir_ind_reg_a, dir_ind_reg_b, reg) => {
                let val_a = dir_ind_reg_a.get_value(vm, context);
                let val_b = dir_ind_reg_b.get_value(vm, context);
                let result = val_a | val_b;
                context.registers[reg] = result;
                context.carry = { result == 0 };
                context.pc = context.pc.advance_by(self.mem_size());
            },
            Xor(dir_ind_reg_a, dir_ind_reg_b, reg) => {
                let val_a = dir_ind_reg_a.get_value(vm, context);
                let val_b = dir_ind_reg_b.get_value(vm, context);
                let result = val_a ^ val_b;
                context.registers[reg] = result;
                context.carry = { result == 0 };
                context.pc = context.pc.advance_by(self.mem_size());
            },
            ZJump(dir) => if context.carry {
                let value: i32 = dir.into();
                context.pc = context.pc.move_by(value as isize % IDX_MOD as isize);
            } else {
                context.pc = context.pc.advance_by(self.mem_size());
            },
            LoadIndex(dir_ind_reg, dir_reg, reg) => {
                let val_a = dir_ind_reg.get_value(vm, context);
                let val_b = dir_reg.get_value(vm, context);
                let addr = Indirect::from(val_a.wrapping_add(val_b) as i16);
                context.registers[reg] = addr.get_value(vm, context);
                context.pc = context.pc.advance_by(self.mem_size());
            },
            StoreIndex(reg, dir_ind_reg, dir_reg) => {
                let value = context.registers[reg];
                let val_a = dir_ind_reg.get_value(vm, context);
                let val_b = dir_reg.get_value(vm, context);
                let addr = Indirect::from(val_a.wrapping_add(val_b) as i16);
                addr.set_value(value, vm, context);
                context.pc = context.pc.advance_by(self.mem_size());
            },
            Fork(dir) => {
                let value: i32 = dir.into();
                let mut fork = context.clean_fork();
                fork.pc = fork.pc.move_by(value as isize % IDX_MOD as isize);
                vm.new_process(fork);
                context.pc = context.pc.advance_by(self.mem_size());
            },
            LongLoad(dir_ind, reg) => {
                let value = dir_ind.get_value_long(vm, context);
                context.registers[reg] = value;
                context.carry = true; // ???
                context.pc = context.pc.advance_by(self.mem_size());
            },
            LongLoadIndex(dir_ind_reg, dir_reg, reg) => {
                let val_a = dir_ind_reg.get_value_long(vm, context);
                let val_b = dir_reg.get_value_long(vm, context);
                let addr = Indirect::from(val_a.wrapping_add(val_b) as i16);
                context.registers[reg] = addr.get_value_long(vm, context);
                context.carry = { context.pc != ArenaIndex::zero() };
                context.pc = context.pc.advance_by(self.mem_size());
            },
            Longfork(dir) => {
                let value: i32 = dir.into();
                let mut fork = context.clean_fork();
                fork.pc = fork.pc.move_by(value as isize);
                vm.new_process(fork);
                context.pc = context.pc.advance_by(self.mem_size());
            },
            Display(reg) => {
                let value = context.registers[reg] as u8;
                let _ = output.write(&[value]);
                context.pc = context.pc.advance_by(self.mem_size());
            },
        }
    }
}

impl MemSize for Instruction {
    fn mem_size(&self) -> usize {
        let size = match *self {
            NoOp => 0,
            Live(a) => a.mem_size(),
            Load(a, b) => PARAM_CODE_SIZE + a.mem_size() + b.mem_size(),
            Store(a, b) => PARAM_CODE_SIZE + a.mem_size() + b.mem_size(),
            Addition(a, b, c) => a.mem_size() + b.mem_size() + c.mem_size(),
            Substraction(a, b, c) => a.mem_size() + b.mem_size() + c.mem_size(),
            And(a, b, c) => PARAM_CODE_SIZE + a.mem_size() + b.mem_size() + c.mem_size(),
            Or(a, b, c) => PARAM_CODE_SIZE + a.mem_size() + b.mem_size() + c.mem_size(),
            Xor(a, b, c) => PARAM_CODE_SIZE + a.mem_size() + b.mem_size() + c.mem_size(),
            ZJump(a) => a.mem_size(),
            LoadIndex(a, b, c) => PARAM_CODE_SIZE + a.mem_size() + b.mem_size() + c.mem_size(),
            StoreIndex(a, b, c) => PARAM_CODE_SIZE + a.mem_size() + b.mem_size() + c.mem_size(),
            Fork(a) => a.mem_size(),
            LongLoad(a, b) => PARAM_CODE_SIZE + a.mem_size() + b.mem_size(),
            LongLoadIndex(a, b, c) => PARAM_CODE_SIZE + a.mem_size() + b.mem_size() + c.mem_size(),
            Longfork(a) => a.mem_size(),
            Display(a) => PARAM_CODE_SIZE + a.mem_size(),
        };
        OP_CODE_SIZE + size
    }
}

macro_rules! try_param_type {
    ($n:expr, $r:expr) => ({
        use self::ParamNumber::*;
        match ParamCode::from(&mut $r).param_type_of($n) {
            Ok(param_code) => param_code,
            Err(_) => return NoOp,
        }
    });
}

macro_rules! try_param {
    ($t:ident, $p:expr) => (match $t::try_from($p) {
        Ok(instr) => instr,
        Err(_) => return NoOp,
    })
}

impl<R: Read> From<R> for Instruction {
    fn from(mut reader: R) -> Self {
        match reader.read_u8().unwrap() {
            1 => Live(Direct::from(&mut reader)),
            2 => {
                let param_code = try_param_type!(First, reader);
                let dir_ind = try_param!(DirInd, (param_code, &mut reader));
                let reg = try_param!(Register, &mut reader);
                Load(dir_ind, reg)
            },
            3 => {
                let param_code = try_param_type!(Second, reader);
                let reg = try_param!(Register, &mut reader);
                let ind_reg = try_param!(IndReg, (param_code, &mut reader));
                Store(reg, ind_reg)
            },
            4 => {
                let reg_a = try_param!(Register, &mut reader);
                let reg_b = try_param!(Register, &mut reader);
                let reg_c = try_param!(Register, &mut reader);
                Addition(reg_a, reg_b, reg_c)
            },
            5 => {
                let reg_a = try_param!(Register, &mut reader);
                let reg_b = try_param!(Register, &mut reader);
                let reg_c = try_param!(Register, &mut reader);
                Substraction(reg_a, reg_b, reg_c)
            },
            6 => {
                let first_type = try_param_type!(First, reader);
                let second_type = try_param_type!(Second, reader);

                let dir_ind_reg_a = try_param!(DirIndReg, (first_type, &mut reader));
                let dir_ind_reg_b = try_param!(DirIndReg, (second_type, &mut reader));
                let reg = try_param!(Register, &mut reader);

                And(dir_ind_reg_a, dir_ind_reg_b, reg)
            },
            7 => {
                let first_type = try_param_type!(First, reader);
                let second_type = try_param_type!(Second, reader);

                let dir_ind_reg_a = try_param!(DirIndReg, (first_type, &mut reader));
                let dir_ind_reg_b = try_param!(DirIndReg, (second_type, &mut reader));
                let reg = try_param!(Register, &mut reader);

                Or(dir_ind_reg_a, dir_ind_reg_b, reg)
            },
            8 => {
                let first_type = try_param_type!(First, reader);
                let second_type = try_param_type!(Second, reader);

                let dir_ind_reg_a = try_param!(DirIndReg, (first_type, &mut reader));
                let dir_ind_reg_b = try_param!(DirIndReg, (second_type, &mut reader));
                let reg = try_param!(Register, &mut reader);

                Xor(dir_ind_reg_a, dir_ind_reg_b, reg)
            },
            9 => ZJump(Direct::from(&mut reader)),
            10 => {
                let first_type = try_param_type!(First, reader);
                let second_type = try_param_type!(Second, reader);

                let dir_ind_reg = try_param!(DirIndReg, (first_type, &mut reader));
                let dir_reg = try_param!(DirReg, (second_type, &mut reader));
                let reg = try_param!(Register, &mut reader);

                LoadIndex(dir_ind_reg, dir_reg, reg)
            },
            11 => {
                let second_type = try_param_type!(Second, reader);
                let third_type = try_param_type!(Third, reader);

                let reg = try_param!(Register, &mut reader);
                let dir_ind_reg = try_param!(DirIndReg, (second_type, &mut reader));
                let dir_reg = try_param!(DirReg, (third_type, &mut reader));

                StoreIndex(reg, dir_ind_reg, dir_reg)
            },
            12 => Fork(Direct::from(&mut reader)),
            13 => {
                let first_type = try_param_type!(First, reader);
                let dir_ind = try_param!(DirInd, (first_type, &mut reader));
                let reg = try_param!(Register, &mut reader);
                LongLoad(dir_ind, reg)
            },
            14 => {
                let first_type = try_param_type!(First, reader);
                let second_type = try_param_type!(Second, reader);

                let dir_ind_reg = try_param!(DirIndReg, (first_type, &mut reader));
                let dir_reg = try_param!(DirReg, (second_type, &mut reader));
                let reg = try_param!(Register, &mut reader);

                LongLoadIndex(dir_ind_reg, dir_reg, reg)
            },
            15 => Longfork(Direct::from(&mut reader)),
            16 => {
                let _useless = try_param_type!(First, reader);
                let reg = try_param!(Register, &mut reader);
                Display(reg)
            },
            _ => NoOp,
        }
    }
}
<commit_msg>instruction: Fix bad useless param code of Display<commit_after>pub mod parameter;
mod mem_size;
mod get_value;
mod set_value;

use std::io::{Read, Write};
use std::convert::TryFrom;
use byteorder::ReadBytesExt;
use self::parameter::*;
use self::mem_size::MemSize;
use self::get_value::GetValue;
use self::set_value::SetValue;
use arena::ArenaIndex;
use machine::Machine;
use process::Context;
use core::IDX_MOD;

const OP_CODE_SIZE:     usize = 1;
const PARAM_CODE_SIZE:  usize = 1;

use self::Instruction::*;

#[derive(Debug, Copy, Clone)]
pub enum Instruction {
    NoOp,
    Live(Direct),
    Load(DirInd, Register),
    Store(Register, IndReg),
    Addition(Register, Register, Register),
    Substraction(Register, Register, Register),
    And(DirIndReg, DirIndReg, Register),
    Or(DirIndReg, DirIndReg, Register),
    Xor(DirIndReg, DirIndReg, Register),
    ZJump(Direct),
    LoadIndex(DirIndReg, DirReg, Register),
    StoreIndex(Register, DirIndReg, DirReg),
    Fork(Direct),
    LongLoad(DirInd, Register),
    LongLoadIndex(DirIndReg, DirReg, Register),
    Longfork(Direct),
    Display(Register),
}

impl Instruction {
    pub fn cycle_cost(&self) -> usize {
        match *self {
            NoOp => 1,
            Live(_) => 10,
            Load(_, _) => 5,
            Store(_, _) => 5,
            Addition(_, _, _) => 10,
            Substraction(_, _, _) => 10,
            And(_, _, _) => 6,
            Or(_, _, _) => 6,
            Xor(_, _, _) => 6,
            ZJump(_) => 20,
            LoadIndex(_, _, _) => 25,
            StoreIndex(_, _, _) => 25,
            Fork(_) => 800,
            LongLoad(_, _) => 10,
            LongLoadIndex(_, _, _) => 50,
            Longfork(_) => 1000,
            Display(_) => 2,
        }
    }

    pub fn execute<W: Write>(&self, vm: &mut Machine, context: &mut Context, output: &mut W) {
        match *self {
            NoOp => context.pc = context.pc.advance_by(self.mem_size()),
            Live(player_id) => {
                context.cycle_since_last_live = 0;
                let player = vm.set_last_living_player(player_id.into());
                context.pc = context.pc.advance_by(self.mem_size());
            },
            Load(dir_ind, reg) => {
                let value = dir_ind.get_value(vm, context);
                context.registers[reg] = value;
                context.carry = { value == 0 };
                context.pc = context.pc.advance_by(self.mem_size());
            },
            Store(reg, ind_reg) => {
                let value = context.registers[reg];
                match ind_reg {
                    IndReg::Indirect(ind) => ind.set_value(value, vm, context),
                    IndReg::Register(reg) => context.registers[reg] = value,
                }
                context.pc = context.pc.advance_by(self.mem_size());
            },
            Addition(reg_a, reg_b, reg_c) => {
                let val_a = context.registers[reg_a];
                let val_b = context.registers[reg_b];
                let result = val_a.wrapping_add(val_b);
                context.registers[reg_c] = result;
                context.carry = { result == 0 };
                context.pc = context.pc.advance_by(self.mem_size());
            },
            Substraction(reg_a, reg_b, reg_c) => {
                let val_a = context.registers[reg_a];
                let val_b = context.registers[reg_b];
                let result = val_a.wrapping_sub(val_b);
                context.registers[reg_c] = result;
                context.carry = { result == 0 };
                context.pc = context.pc.advance_by(self.mem_size());
            },
            And(dir_ind_reg_a, dir_ind_reg_b, reg) => {
                let val_a = dir_ind_reg_a.get_value(vm, context);
                let val_b = dir_ind_reg_b.get_value(vm, context);
                let result = val_a & val_b;
                context.registers[reg] = result;
                context.carry = { result == 0 };
                context.pc = context.pc.advance_by(self.mem_size());
            },
            Or(dir_ind_reg_a, dir_ind_reg_b, reg) => {
                let val_a = dir_ind_reg_a.get_value(vm, context);
                let val_b = dir_ind_reg_b.get_value(vm, context);
                let result = val_a | val_b;
                context.registers[reg] = result;
                context.carry = { result == 0 };
                context.pc = context.pc.advance_by(self.mem_size());
            },
            Xor(dir_ind_reg_a, dir_ind_reg_b, reg) => {
                let val_a = dir_ind_reg_a.get_value(vm, context);
                let val_b = dir_ind_reg_b.get_value(vm, context);
                let result = val_a ^ val_b;
                context.registers[reg] = result;
                context.carry = { result == 0 };
                context.pc = context.pc.advance_by(self.mem_size());
            },
            ZJump(dir) => if context.carry {
                let value: i32 = dir.into();
                context.pc = context.pc.move_by(value as isize % IDX_MOD as isize);
            } else {
                context.pc = context.pc.advance_by(self.mem_size());
            },
            LoadIndex(dir_ind_reg, dir_reg, reg) => {
                let val_a = dir_ind_reg.get_value(vm, context);
                let val_b = dir_reg.get_value(vm, context);
                let addr = Indirect::from(val_a.wrapping_add(val_b) as i16);
                context.registers[reg] = addr.get_value(vm, context);
                context.pc = context.pc.advance_by(self.mem_size());
            },
            StoreIndex(reg, dir_ind_reg, dir_reg) => {
                let value = context.registers[reg];
                let val_a = dir_ind_reg.get_value(vm, context);
                let val_b = dir_reg.get_value(vm, context);
                let addr = Indirect::from(val_a.wrapping_add(val_b) as i16);
                addr.set_value(value, vm, context);
                context.pc = context.pc.advance_by(self.mem_size());
            },
            Fork(dir) => {
                let value: i32 = dir.into();
                let mut fork = context.clean_fork();
                fork.pc = fork.pc.move_by(value as isize % IDX_MOD as isize);
                vm.new_process(fork);
                context.pc = context.pc.advance_by(self.mem_size());
            },
            LongLoad(dir_ind, reg) => {
                let value = dir_ind.get_value_long(vm, context);
                context.registers[reg] = value;
                context.carry = true; // ???
                context.pc = context.pc.advance_by(self.mem_size());
            },
            LongLoadIndex(dir_ind_reg, dir_reg, reg) => {
                let val_a = dir_ind_reg.get_value_long(vm, context);
                let val_b = dir_reg.get_value_long(vm, context);
                let addr = Indirect::from(val_a.wrapping_add(val_b) as i16);
                context.registers[reg] = addr.get_value_long(vm, context);
                context.carry = { context.pc != ArenaIndex::zero() };
                context.pc = context.pc.advance_by(self.mem_size());
            },
            Longfork(dir) => {
                let value: i32 = dir.into();
                let mut fork = context.clean_fork();
                fork.pc = fork.pc.move_by(value as isize);
                vm.new_process(fork);
                context.pc = context.pc.advance_by(self.mem_size());
            },
            Display(reg) => {
                let value = context.registers[reg] as u8;
                let _ = output.write(&[value]);
                context.pc = context.pc.advance_by(self.mem_size());
            },
        }
    }
}

impl MemSize for Instruction {
    fn mem_size(&self) -> usize {
        let size = match *self {
            NoOp => 0,
            Live(a) => a.mem_size(),
            Load(a, b) => PARAM_CODE_SIZE + a.mem_size() + b.mem_size(),
            Store(a, b) => PARAM_CODE_SIZE + a.mem_size() + b.mem_size(),
            Addition(a, b, c) => a.mem_size() + b.mem_size() + c.mem_size(),
            Substraction(a, b, c) => a.mem_size() + b.mem_size() + c.mem_size(),
            And(a, b, c) => PARAM_CODE_SIZE + a.mem_size() + b.mem_size() + c.mem_size(),
            Or(a, b, c) => PARAM_CODE_SIZE + a.mem_size() + b.mem_size() + c.mem_size(),
            Xor(a, b, c) => PARAM_CODE_SIZE + a.mem_size() + b.mem_size() + c.mem_size(),
            ZJump(a) => a.mem_size(),
            LoadIndex(a, b, c) => PARAM_CODE_SIZE + a.mem_size() + b.mem_size() + c.mem_size(),
            StoreIndex(a, b, c) => PARAM_CODE_SIZE + a.mem_size() + b.mem_size() + c.mem_size(),
            Fork(a) => a.mem_size(),
            LongLoad(a, b) => PARAM_CODE_SIZE + a.mem_size() + b.mem_size(),
            LongLoadIndex(a, b, c) => PARAM_CODE_SIZE + a.mem_size() + b.mem_size() + c.mem_size(),
            Longfork(a) => a.mem_size(),
            Display(a) => PARAM_CODE_SIZE + a.mem_size(),
        };
        OP_CODE_SIZE + size
    }
}

macro_rules! try_param_type {
    ($n:expr, $r:expr) => ({
        use self::ParamNumber::*;
        match ParamCode::from(&mut $r).param_type_of($n) {
            Ok(param_code) => param_code,
            Err(_) => return NoOp,
        }
    });
}

macro_rules! try_param {
    ($t:ident, $p:expr) => (match $t::try_from($p) {
        Ok(instr) => instr,
        Err(_) => return NoOp,
    })
}

impl<R: Read> From<R> for Instruction {
    fn from(mut reader: R) -> Self {
        match reader.read_u8().unwrap() {
            1 => Live(Direct::from(&mut reader)),
            2 => {
                let param_type = try_param_type!(First, reader);
                let dir_ind = try_param!(DirInd, (param_type, &mut reader));
                let reg = try_param!(Register, &mut reader);
                Load(dir_ind, reg)
            },
            3 => {
                let param_type = try_param_type!(Second, reader);
                let reg = try_param!(Register, &mut reader);
                let ind_reg = try_param!(IndReg, (param_type, &mut reader));
                Store(reg, ind_reg)
            },
            4 => {
                let reg_a = try_param!(Register, &mut reader);
                let reg_b = try_param!(Register, &mut reader);
                let reg_c = try_param!(Register, &mut reader);
                Addition(reg_a, reg_b, reg_c)
            },
            5 => {
                let reg_a = try_param!(Register, &mut reader);
                let reg_b = try_param!(Register, &mut reader);
                let reg_c = try_param!(Register, &mut reader);
                Substraction(reg_a, reg_b, reg_c)
            },
            6 => {
                let first_type = try_param_type!(First, reader);
                let second_type = try_param_type!(Second, reader);

                let dir_ind_reg_a = try_param!(DirIndReg, (first_type, &mut reader));
                let dir_ind_reg_b = try_param!(DirIndReg, (second_type, &mut reader));
                let reg = try_param!(Register, &mut reader);

                And(dir_ind_reg_a, dir_ind_reg_b, reg)
            },
            7 => {
                let first_type = try_param_type!(First, reader);
                let second_type = try_param_type!(Second, reader);

                let dir_ind_reg_a = try_param!(DirIndReg, (first_type, &mut reader));
                let dir_ind_reg_b = try_param!(DirIndReg, (second_type, &mut reader));
                let reg = try_param!(Register, &mut reader);

                Or(dir_ind_reg_a, dir_ind_reg_b, reg)
            },
            8 => {
                let first_type = try_param_type!(First, reader);
                let second_type = try_param_type!(Second, reader);

                let dir_ind_reg_a = try_param!(DirIndReg, (first_type, &mut reader));
                let dir_ind_reg_b = try_param!(DirIndReg, (second_type, &mut reader));
                let reg = try_param!(Register, &mut reader);

                Xor(dir_ind_reg_a, dir_ind_reg_b, reg)
            },
            9 => ZJump(Direct::from(&mut reader)),
            10 => {
                let first_type = try_param_type!(First, reader);
                let second_type = try_param_type!(Second, reader);

                let dir_ind_reg = try_param!(DirIndReg, (first_type, &mut reader));
                let dir_reg = try_param!(DirReg, (second_type, &mut reader));
                let reg = try_param!(Register, &mut reader);

                LoadIndex(dir_ind_reg, dir_reg, reg)
            },
            11 => {
                let second_type = try_param_type!(Second, reader);
                let third_type = try_param_type!(Third, reader);

                let reg = try_param!(Register, &mut reader);
                let dir_ind_reg = try_param!(DirIndReg, (second_type, &mut reader));
                let dir_reg = try_param!(DirReg, (third_type, &mut reader));

                StoreIndex(reg, dir_ind_reg, dir_reg)
            },
            12 => Fork(Direct::from(&mut reader)),
            13 => {
                let first_type = try_param_type!(First, reader);
                let dir_ind = try_param!(DirInd, (first_type, &mut reader));
                let reg = try_param!(Register, &mut reader);
                LongLoad(dir_ind, reg)
            },
            14 => {
                let first_type = try_param_type!(First, reader);
                let second_type = try_param_type!(Second, reader);

                let dir_ind_reg = try_param!(DirIndReg, (first_type, &mut reader));
                let dir_reg = try_param!(DirReg, (second_type, &mut reader));
                let reg = try_param!(Register, &mut reader);

                LongLoadIndex(dir_ind_reg, dir_reg, reg)
            },
            15 => Longfork(Direct::from(&mut reader)),
            16 => {
                let _useless_param_code = ParamCode::from(&mut reader);
                let reg = try_param!(Register, &mut reader);
                Display(reg)
            },
            _ => NoOp,
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::env;
use git2;
use errors::*;

pub trait Config {
  fn get(&self, name: &str) -> Result<String>;
  fn get_all(&self, glob: &str) -> Result<HashMap<String, String>>;
  fn set(&mut self, name: &str, value: &str) -> Result<()>;
}

pub struct GitConfig {
  namespace: String,
  repo: git2::Repository,
  config: git2::Config,
}

impl GitConfig {
  pub fn new(namespace: &str) -> Result<GitConfig> {
    let path = try!(env::current_dir()
      .chain_err(|| "error getting current directory"));
    let repo = try!(git2::Repository::discover(path)
      .chain_err(|| "error discovering git repo"));
    let config = try!(repo.config().chain_err(|| "error getting git config"));

    Ok(GitConfig {
      namespace: namespace.into(),
      repo: repo,
      config: config,
    })
  }

  pub fn auto_include(&mut self) {
    let filename = format!(".{}", self.namespace);
    let include_path = format!("../{}", filename);
    let file_exists = self.repo.workdir().map(|path| {
      let mut path_buf = path.to_path_buf();
      path_buf.push(&filename);
      path_buf.exists()
    });

    // Make sure .git-together exists
    if !file_exists.unwrap_or(false) {
      return;
    }

    if self.already_included(&include_path).unwrap_or(true) {
      return;
    }

    let _ = self.config.set_multivar("include.path", "^$", &include_path);
  }

  fn already_included(&self, include_path: &str) -> Result<bool> {
    let local_config = try!(self.config
      .open_level(git2::ConfigLevel::Local)
      .chain_err(|| "error opening local git config"));
    let entries = try!(local_config.entries(None)
      .chain_err(|| "error getting git config entries"));
    Ok(IntoIterator::into_iter(&entries).any(|entry| {
      entry.map(|entry| entry.value() == Some(include_path)).unwrap_or(true)
    }))
  }
}

impl Config for GitConfig {
  fn get(&self, name: &str) -> Result<String> {
    let name = format!("{}.{}", self.namespace, name);
    self.config.get_string(&name).chain_err(|| "error getting git config")
  }

  fn get_all(&self, glob: &str) -> Result<HashMap<String, String>> {
    let mut result = HashMap::new();
    let entries = try!(self.config
      .entries(Some(glob))
      .chain_err(|| "error getting git config entries"));
    for entry in &entries {
      let entry = try!(entry.chain_err(|| "error getting git config entry"));
      if let (Some(name), Some(value)) = (entry.name(), entry.value()) {
        result.insert(name.into(), value.into());
      }
    }
    Ok(result)
  }

  fn set(&mut self, name: &str, value: &str) -> Result<()> {
    let name = format!("{}.{}", self.namespace, name);
    self.config.set_str(&name, value).chain_err(|| "error setting git config")
  }
}
<commit_msg>clarify git config get/set errors<commit_after>use std::collections::HashMap;
use std::env;
use git2;
use errors::*;

pub trait Config {
  fn get(&self, name: &str) -> Result<String>;
  fn get_all(&self, glob: &str) -> Result<HashMap<String, String>>;
  fn set(&mut self, name: &str, value: &str) -> Result<()>;
}

pub struct GitConfig {
  namespace: String,
  repo: git2::Repository,
  config: git2::Config,
}

impl GitConfig {
  pub fn new(namespace: &str) -> Result<GitConfig> {
    let path = try!(env::current_dir()
      .chain_err(|| "error getting current directory"));
    let repo = try!(git2::Repository::discover(path)
      .chain_err(|| "error discovering git repo"));
    let config = try!(repo.config().chain_err(|| "error getting git config"));

    Ok(GitConfig {
      namespace: namespace.into(),
      repo: repo,
      config: config,
    })
  }

  pub fn auto_include(&mut self) {
    let filename = format!(".{}", self.namespace);
    let include_path = format!("../{}", filename);
    let file_exists = self.repo.workdir().map(|path| {
      let mut path_buf = path.to_path_buf();
      path_buf.push(&filename);
      path_buf.exists()
    });

    // Make sure .git-together exists
    if !file_exists.unwrap_or(false) {
      return;
    }

    if self.already_included(&include_path).unwrap_or(true) {
      return;
    }

    let _ = self.config.set_multivar("include.path", "^$", &include_path);
  }

  fn already_included(&self, include_path: &str) -> Result<bool> {
    let local_config = try!(self.config
      .open_level(git2::ConfigLevel::Local)
      .chain_err(|| "error opening local git config"));
    let entries = try!(local_config.entries(None)
      .chain_err(|| "error getting git config entries"));
    Ok(IntoIterator::into_iter(&entries).any(|entry| {
      entry.map(|entry| entry.value() == Some(include_path)).unwrap_or(true)
    }))
  }
}

impl Config for GitConfig {
  fn get(&self, name: &str) -> Result<String> {
    let name = format!("{}.{}", self.namespace, name);
    self.config
      .get_string(&name)
      .chain_err(|| format!("error getting git config for '{}'", name))
  }

  fn get_all(&self, glob: &str) -> Result<HashMap<String, String>> {
    let mut result = HashMap::new();
    let entries = try!(self.config
      .entries(Some(glob))
      .chain_err(|| "error getting git config entries"));
    for entry in &entries {
      let entry = try!(entry.chain_err(|| "error getting git config entry"));
      if let (Some(name), Some(value)) = (entry.name(), entry.value()) {
        result.insert(name.into(), value.into());
      }
    }
    Ok(result)
  }

  fn set(&mut self, name: &str, value: &str) -> Result<()> {
    let name = format!("{}.{}", self.namespace, name);
    self.config
      .set_str(&name, value)
      .chain_err(|| "error setting git config '{}': '{}'", name, value)
  }
}
<|endoftext|>