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

//!
//! # DFA compiler
//!
//! The DFA compiler converts NDFAs into DFAs, using a DFA builder.
//!

use std::marker::PhantomData;
use std::collections::HashSet;
use std::collections::HashMap;
use std::iter::*;
use std::cmp::Ordering;

use super::dfa_builder::*;
use super::state_machine::*;

///
/// Builds a deterministic finite automaton from a NDFA
///
pub struct DfaCompiler<InputSymbol: PartialOrd+Clone, OutputSymbol, DfaType, Ndfa: StateMachine<InputSymbol, OutputSymbol>, Builder: DfaBuilder<InputSymbol, OutputSymbol, DfaType>> {
    /// State machine that is to be compiled
    ndfa: Ndfa,

    /// Builder where the state machine should be generated
    builder: Builder,

    // Phantom data to poke Rust's type system (it's too dumb to see that InputSymbol is used in both Ndfa and Builder there via the type constraint)
    #[allow(dead_code)]
    phantom: (PhantomData<InputSymbol>, PhantomData<OutputSymbol>, PhantomData<DfaType>)
}

/// Represents a state in the DFA (one or more states from the source)
#[derive(Eq, PartialEq, Hash, Clone)]
struct DfaState {
    /// List of the states from the NDFA that make up this DFA state (will be ordered if `dedupe` is called)
    source_states: Vec<StateId>
}

impl DfaState {
    /// Creates a DFA state from a set of source states
    fn create(source_states: Vec<StateId>) -> DfaState {
        let mut set = HashSet::new();
        for state in source_states {
            set.insert(state);
        }

        DfaState { source_states: Vec::from_iter(set.into_iter()) }
    }

    /// Removes any duplicate states from source_states
    fn dedupe(&mut self) {
        self.source_states.sort();
        self.source_states.dedup();
    }
}

/// Represents the transitions for a source state
struct DfaTransitions<InputSymbol, OutputSymbol: Ord> {
    /// ID of this state in the resulting DFA
    state_id: StateId,

    /// Transitions for this state (will be unique if `merge_states` is called)
    transitions: Vec<(InputSymbol, DfaState)>,

    /// The output symbols for this state (empty if this is not an accepting state)
    output: Vec<OutputSymbol>
}

impl<InputSymbol: PartialOrd+Clone, OutputSymbol: Ord> DfaTransitions<InputSymbol, OutputSymbol> {
    /// Goes through the transitions in the object and merges the states of any with the same symbol
    fn merge_states(&mut self) {
        if self.transitions.len() > 0 {
            // Order the transitions so that if two transitions have the same input symbol, they are neighbours
            self.transitions.sort_by(|a, b| {
                let &(ref symbol_a, _) = a;
                let &(ref symbol_b, _) = b;

                if let Some(result) = symbol_a.partial_cmp(symbol_b) {
                    result
                } else {
                    // Unordered input symbols won't work well
                    Ordering::Equal
                }
            });

            // For any transition that has a duplicate state, combine it with the previous state
            let mut new_transitions = vec![];
            new_transitions.push(self.transitions[0].clone());

            for transit_idx in 1..self.transitions.len() {
                let len          = new_transitions.len();
                let this_transit = &mut self.transitions[transit_idx];

                if new_transitions[len-1].0 == this_transit.0 {
                    // Same symbol: expand this state
                    new_transitions[len-1].1.source_states.append(&mut this_transit.1.source_states);
                } else {
                    // Different symbol: add new state
                    new_transitions.push(this_transit.clone());
                }
            }

            // Ensure all of the states are sorted and de-duplicated
            for transit in &mut new_transitions {
                transit.1.dedupe();
            }

            // Update the transitions
            self.transitions = new_transitions;
        }
    }

    ///
    /// Finds the output symbol that corresponds to this state
    ///
    /// Rule is that if there is more than one output symbol then the symbol whose value is ordered lowest is the output for this state
    ///
    fn output_symbol(&mut self) -> Option<&OutputSymbol> {
        if self.output.len() > 0 {
            self.output.sort();
            Some(&self.output[0])
        } else {
            None
        }
    }
}

impl<InputSymbol: PartialOrd+Clone, OutputSymbol: Ord+Clone, DfaType, Ndfa: StateMachine<InputSymbol, OutputSymbol>, Builder: DfaBuilder<InputSymbol, OutputSymbol, DfaType>>
    DfaCompiler<InputSymbol, OutputSymbol, DfaType, Ndfa, Builder> {
    ///
    /// Builds a DFA using an NDFA and a builder
    ///
    pub fn build(ndfa: Ndfa, builder: Builder) -> DfaType {
        let compiler = DfaCompiler::new(ndfa, builder);
        compiler.compile()
    }

    ///
    /// Creates a new DFA compiler using a particular builder and NDFA
    ///
    pub fn new(ndfa: Ndfa, builder: Builder) -> Self {
        DfaCompiler { ndfa: ndfa, builder: builder, phantom: (PhantomData, PhantomData, PhantomData) }
    }

    ///
    /// Compiles the NDFA into a DFA
    ///
    pub fn compile(self) -> DfaType {
        // We assume that input symbols are non-overlapping, which is not automatically the case for symbol ranges

        // Work out the state mapping for each input symbol
        let mut states       = vec![];
        let mut known_states = HashMap::new();
        let mut to_process   = vec![];

        // All state machines have state 0 as their starting state
        let state_zero = DfaState::create(vec![0]);

        known_states.insert(state_zero.clone(), 0);
        to_process.push(state_zero);

        while let Some(state) = to_process.pop() {
            // Create a new transitions object for this state
            let mut transitions = vec![];
            let mut output      = vec![];

            for source_state in &state.source_states {
                let source_transitions = self.ndfa.get_transitions_for_state(*source_state);

                for (symbol, state) in source_transitions {
                    transitions.push((symbol, DfaState::create(vec![state])));
                }

                if let Some(source_output) = self.ndfa.output_symbol_for_state(*source_state) {
                    output.push(source_output.clone());
                }
            }

            // Merge it so that we only have one transition per symbol
            let mut dfa_transitions = DfaTransitions { state_id: states.len() as StateId, transitions: transitions, output: output };
            dfa_transitions.merge_states();

            // Process any generated states that are not already in the DFA
            for &(_, ref maybe_new_state) in &dfa_transitions.transitions {
                if !known_states.contains_key(maybe_new_state) {
                    to_process.push(maybe_new_state.clone());
                }
            }

            // Store the new state
            known_states.insert(state.clone(), dfa_transitions.state_id);
            states.push(dfa_transitions);
        }

        // Build the DFA
        let mut builder = self.builder;

        for mut dfa_state in states {
            builder.start_state();

            if let Some(output_symbol) = dfa_state.output_symbol() {
                builder.accept(output_symbol.clone());
            }

            for (symbol, target_state) in dfa_state.transitions {
                builder.transition(symbol, known_states[&target_state]);
            }
        }

        // Generate the final DFA
        builder.build()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use super::super::regular_pattern::*;
    use super::super::state_machine::*;
    use super::super::symbol_range_dfa::*;
    use super::super::pattern_matcher::*;
    use super::super::symbol_reader::*;

    #[test]
    fn can_create_compiler() {
        let ndfa     = "abc".into_pattern().to_ndfa("success");
        let builder  = SymbolRangeDfaBuilder::new();

        DfaCompiler::new(ndfa, builder);
    }

    #[test]
    fn can_build_dfa() {
        let ndfa     = "abc".into_pattern().to_ndfa("Success");
        let builder  = SymbolRangeDfaBuilder::new();

        let state_machine = DfaCompiler::build(ndfa, builder);

        let mut state = More(state_machine.start());
        let mut input = "abc".read_symbols();

        while let More(this_state) = state {
            let next_state =
                if let Some(next_char) = input.next_symbol() {
                    this_state.next(next_char)
                } else {
                    this_state.finish()
                };

            state = next_state;
        }

        if let Accept(count, output) = state {
            assert!(count == 3);
            assert!(output == &"Success");
        } else {
            assert!(false);
        }
    }
}
<commit_msg>Modify comments<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # DFA compiler
//!
//! The DFA compiler converts NDFAs into DFAs, using a DFA builder.
//!

use std::marker::PhantomData;
use std::collections::HashSet;
use std::collections::HashMap;
use std::iter::*;
use std::cmp::Ordering;

use super::dfa_builder::*;
use super::state_machine::*;

///
/// Builds a deterministic finite automaton from a NDFA
///
pub struct DfaCompiler<InputSymbol: PartialOrd+Clone, OutputSymbol, DfaType, Ndfa: StateMachine<InputSymbol, OutputSymbol>, Builder: DfaBuilder<InputSymbol, OutputSymbol, DfaType>> {
    /// State machine that is to be compiled
    ndfa: Ndfa,

    /// Builder where the state machine should be generated
    builder: Builder,

    // Phantom data to poke Rust's type system (it's too dumb to see that InputSymbol is used in both Ndfa and Builder there via the type constraint)
    #[allow(dead_code)]
    phantom: (PhantomData<InputSymbol>, PhantomData<OutputSymbol>, PhantomData<DfaType>)
}

/// Represents a state in the DFA (one or more states from the source)
#[derive(Eq, PartialEq, Hash, Clone)]
struct DfaState {
    /// List of the states from the NDFA that make up this DFA state (will be ordered if `dedupe` is called)
    source_states: Vec<StateId>
}

impl DfaState {
    /// Creates a DFA state from a set of source states
    fn create(source_states: Vec<StateId>) -> DfaState {
        let mut set = HashSet::new();
        for state in source_states {
            set.insert(state);
        }

        DfaState { source_states: Vec::from_iter(set.into_iter()) }
    }

    /// Removes any duplicate states from source_states
    fn dedupe(&mut self) {
        self.source_states.sort();
        self.source_states.dedup();
    }
}

/// Represents the transitions for a source state
struct DfaTransitions<InputSymbol, OutputSymbol: Ord> {
    /// ID of this state in the resulting DFA
    state_id: StateId,

    /// Transitions for this state (will be unique if `merge_states` is called)
    transitions: Vec<(InputSymbol, DfaState)>,

    /// The output symbols for this state (empty if this is not an accepting state)
    output: Vec<OutputSymbol>
}

impl<InputSymbol: PartialOrd+Clone, OutputSymbol: Ord> DfaTransitions<InputSymbol, OutputSymbol> {
    /// Goes through the transitions in the object and merges the states of any with the same symbol
    fn merge_states(&mut self) {
        if self.transitions.len() > 0 {
            // Order the transitions so that if two transitions have the same input symbol, they are neighbours
            self.transitions.sort_by(|a, b| {
                let &(ref symbol_a, _) = a;
                let &(ref symbol_b, _) = b;

                if let Some(result) = symbol_a.partial_cmp(symbol_b) {
                    result
                } else {
                    // Unordered input symbols won't work well
                    Ordering::Equal
                }
            });

            // For any transition that has a duplicate state, combine it with the previous state
            let mut new_transitions = vec![];
            new_transitions.push(self.transitions[0].clone());

            for transit_idx in 1..self.transitions.len() {
                let len          = new_transitions.len();
                let this_transit = &mut self.transitions[transit_idx];

                if new_transitions[len-1].0 == this_transit.0 {
                    // Same symbol: expand this state
                    new_transitions[len-1].1.source_states.append(&mut this_transit.1.source_states);
                } else {
                    // Different symbol: add new state
                    new_transitions.push(this_transit.clone());
                }
            }

            // Ensure all of the states are sorted and de-duplicated
            for transit in &mut new_transitions {
                transit.1.dedupe();
            }

            // Update the transitions
            self.transitions = new_transitions;
        }
    }

    ///
    /// Finds the output symbol that corresponds to this state
    ///
    /// Rule is that if there is more than one output symbol then the symbol whose value is ordered lowest is the output for this state
    ///
    fn output_symbol(&mut self) -> Option<&OutputSymbol> {
        if self.output.len() > 0 {
            self.output.sort();
            Some(&self.output[0])
        } else {
            None
        }
    }
}

impl<InputSymbol: PartialOrd+Clone, OutputSymbol: Ord+Clone, DfaType, Ndfa: StateMachine<InputSymbol, OutputSymbol>, Builder: DfaBuilder<InputSymbol, OutputSymbol, DfaType>>
    DfaCompiler<InputSymbol, OutputSymbol, DfaType, Ndfa, Builder> {
    ///
    /// Builds a DFA using an NDFA and a builder
    ///
    pub fn build(ndfa: Ndfa, builder: Builder) -> DfaType {
        let compiler = DfaCompiler::new(ndfa, builder);
        compiler.compile()
    }

    ///
    /// Creates a new DFA compiler using a particular builder and NDFA
    ///
    pub fn new(ndfa: Ndfa, builder: Builder) -> Self {
        DfaCompiler { ndfa: ndfa, builder: builder, phantom: (PhantomData, PhantomData, PhantomData) }
    }

    ///
    /// Compiles the NDFA into a DFA
    ///
    pub fn compile(self) -> DfaType {
        // We assume that input symbols are non-overlapping, which is not automatically the case for symbol ranges

        // Work out the state mapping for each input symbol
        let mut states       = vec![];
        let mut known_states = HashMap::new();
        let mut to_process   = vec![];

        // All state machines have state 0 as their starting state
        let state_zero = DfaState::create(vec![0]);

        known_states.insert(state_zero.clone(), 0);
        to_process.push(state_zero);

        while let Some(state) = to_process.pop() {
            // Create a new transitions object for this state
            let mut transitions = vec![];
            let mut output      = vec![];

            for source_state in &state.source_states {
                let source_transitions = self.ndfa.get_transitions_for_state(*source_state);

                for (symbol, state) in source_transitions {
                    transitions.push((symbol, DfaState::create(vec![state])));
                }

                if let Some(source_output) = self.ndfa.output_symbol_for_state(*source_state) {
                    output.push(source_output.clone());
                }
            }

            // Merge it so that we only have one transition per symbol
            let mut dfa_transitions = DfaTransitions { state_id: states.len() as StateId, transitions: transitions, output: output };
            dfa_transitions.merge_states();

            // Process any generated states that are not already in the DFA
            for &(_, ref maybe_new_state) in &dfa_transitions.transitions {
                if !known_states.contains_key(maybe_new_state) {
                    to_process.push(maybe_new_state.clone());
                }
            }

            // Store the new state
            known_states.insert(state.clone(), dfa_transitions.state_id);
            states.push(dfa_transitions);
        }

        // Build the DFA
        let mut builder = self.builder;

        for mut dfa_state in states {
            builder.start_state();

            if let Some(output_symbol) = dfa_state.output_symbol() {
                builder.accept(output_symbol.clone());
            }

            for (symbol, target_state) in dfa_state.transitions {
                builder.transition(symbol, known_states[&target_state]);
            }
        }

        // Generate the final DFA
        builder.build()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use super::super::regular_pattern::*;
    use super::super::state_machine::*;
    use super::super::symbol_range_dfa::*;
    use super::super::pattern_matcher::*;
    use super::super::symbol_reader::*;

    #[test]
    fn can_create_compiler() {
        let ndfa     = "abc".into_pattern().to_ndfa("success");
        let builder  = SymbolRangeDfaBuilder::new();

        DfaCompiler::new(ndfa, builder);
    }

    #[test]
    fn can_build_dfa() {
        // Generate a state machine from the "abc" pattern
        let ndfa     = "abc".into_pattern().to_ndfa("Success");
        let builder  = SymbolRangeDfaBuilder::new();

        let state_machine = DfaCompiler::build(ndfa, builder);

        // Read back 'abc' manually
        let mut state = More(state_machine.start());
        let mut input = "abc".read_symbols();

        while let More(this_state) = state {
            let next_state =
                if let Some(next_char) = input.next_symbol() {
                    this_state.next(next_char)
                } else {
                    this_state.finish()
                };

            state = next_state;
        }

        // Check for acceptance
        if let Accept(count, output) = state {
            assert!(count == 3);
            assert!(output == &"Success");
        } else {
            assert!(false);
        }
    }
}
<|endoftext|>


<commit_before>use dsp::Node;
use dsp::sample::frame::Stereo;
use dsp::sample::signal;
use dsp::sample::{Frame, Signal, slice};

pub type Hz = u64;
pub type PadIdx = usize;
pub type Velocity = u64;
pub type Volume = u64;
pub type AudioOut = Stereo<f64>;

struct PadState {
    /// Is the pad active.
    active: bool,
    /// The velocity this pad was triggered with.
    vel: Velocity,
    /// The current sample rate
    sample_hz: Hz,
}

impl PadState {
    fn new(sample_hz: Hz) -> Self {
        PadState {
            active: false,
            vel: 0,
            sample_hz: sample_hz,
        }
    }

    /// Trigger a sound.
    fn trigger(&mut self, vel: Velocity) {
        self.active = true;
        self.vel = vel;
    }

    /// Deactivate.
    fn silence(&mut self) {
        self.active = false;
        self.vel = 0;
    }

    /// Set the sample rate
    fn set_sample_rate(&mut self, sample_hz: Hz) {
        self.sample_hz = sample_hz;
    }

    /// Get the next audio frame.
    fn next_frame(&mut self) -> Option<AudioOut> {
        Some(AudioOut::equilibrium())
    }
}

impl Iterator for PadState {
    type Item = AudioOut;

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

pub struct Machine {
    /// Amplitude multiplier (volume).
    pub volume: Volume,
    /// Render playback or not.
    pub is_paused: bool,
    /// The current sample rate
    sample_hz: Hz,
    /// The states of the pads that generate sound for the machine.
    pads: Vec<PadState>,
}

impl Machine {
    /// Constructor for a new drum machine.
    pub fn new() -> Self {
        const sample_hz: Hz = 44_100;
        Machine {
            volume: 1,
            is_paused: false,
            pads: vec![PadState::new(sample_hz)],
            sample_hz: sample_hz,
        }
    }

    /// Trigger a pad.
    pub fn trigger(&mut self, pad: PadIdx, vel: Velocity) {
        if pad < self.pads.len() {
            self.pads[pad].trigger(vel);
        }
    }

    /// Deactivate a pad.
    pub fn silence(&mut self, pad: PadIdx) {
        if pad < self.pads.len() {
            self.pads[pad].silence();
        }
    }

    /// Pause playback.
    pub fn pause(&mut self) {
        self.is_paused = true;
    }

    /// Unpause playback.
    pub fn unpause(&mut self) {
        self.is_paused = false;
    }

    /// Stop playback and clear the current pads.
    pub fn stop(&mut self) {
        for pad in &mut self.pads {
            pad.silence();
        }
    }

    /// Set the sample rate
    pub fn set_sample_rate(&mut self, sample_hz: Hz) {
        self.sample_hz = sample_hz;
        for pad in &mut self.pads {
            pad.set_sample_rate(sample_hz);
        }
    }

    /// Get the next audio frame.
    fn next_frame(&mut self) -> Option<AudioOut> {
        Some(self.pads.iter_mut().fold(AudioOut::equilibrium(), |f, pad| {
            f.add_amp(match pad.next() {
                None => AudioOut::equilibrium(),
                Some(output) => output,
            })
        }))
    }
}

impl Iterator for Machine {
    type Item = AudioOut;

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

impl Node<AudioOut> for Machine {
    fn audio_requested(&mut self, buffer: &mut [AudioOut], sample_hz: f64) {
        let sample_hz_rounded = sample_hz.round() as u64;
        if sample_hz_rounded != self.sample_hz {
            self.set_sample_rate(sample_hz_rounded);
        }

        slice::map_in_place(buffer, |_| match self.next() {
            None => AudioOut::equilibrium(),
            Some(output) => output,
        });
    }
}
<commit_msg>Simpler next_frame<commit_after>use dsp::Node;
use dsp::sample::frame::Stereo;
use dsp::sample::signal;
use dsp::sample::{Frame, Signal, slice};

pub type Hz = u64;
pub type PadIdx = usize;
pub type Velocity = u64;
pub type Volume = u64;
pub type AudioOut = Stereo<f64>;

struct PadState {
    /// Is the pad active.
    active: bool,
    /// The velocity this pad was triggered with.
    vel: Velocity,
    /// The current sample rate
    sample_hz: Hz,
}

impl PadState {
    fn new(sample_hz: Hz) -> Self {
        PadState {
            active: false,
            vel: 0,
            sample_hz: sample_hz,
        }
    }

    /// Trigger a sound.
    fn trigger(&mut self, vel: Velocity) {
        self.active = true;
        self.vel = vel;
    }

    /// Deactivate.
    fn silence(&mut self) {
        self.active = false;
        self.vel = 0;
    }

    /// Set the sample rate
    fn set_sample_rate(&mut self, sample_hz: Hz) {
        self.sample_hz = sample_hz;
    }

    /// Get the next audio frame.
    fn next_frame(&mut self) -> AudioOut {
        AudioOut::equilibrium()
    }
}

impl Iterator for PadState {
    type Item = AudioOut;

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

pub struct Machine {
    /// Amplitude multiplier (volume).
    pub volume: Volume,
    /// Render playback or not.
    pub is_paused: bool,
    /// The current sample rate
    sample_hz: Hz,
    /// The states of the pads that generate sound for the machine.
    pads: Vec<PadState>,
}

impl Machine {
    /// Constructor for a new drum machine.
    pub fn new() -> Self {
        const sample_hz: Hz = 44_100;
        Machine {
            volume: 1,
            is_paused: false,
            pads: vec![PadState::new(sample_hz)],
            sample_hz: sample_hz,
        }
    }

    /// Trigger a pad.
    pub fn trigger(&mut self, pad: PadIdx, vel: Velocity) {
        if pad < self.pads.len() {
            self.pads[pad].trigger(vel);
        }
    }

    /// Deactivate a pad.
    pub fn silence(&mut self, pad: PadIdx) {
        if pad < self.pads.len() {
            self.pads[pad].silence();
        }
    }

    /// Pause playback.
    pub fn pause(&mut self) {
        self.is_paused = true;
    }

    /// Unpause playback.
    pub fn unpause(&mut self) {
        self.is_paused = false;
    }

    /// Stop playback and clear the current pads.
    pub fn stop(&mut self) {
        for pad in &mut self.pads {
            pad.silence();
        }
    }

    /// Set the sample rate
    pub fn set_sample_rate(&mut self, sample_hz: Hz) {
        self.sample_hz = sample_hz;
        for pad in &mut self.pads {
            pad.set_sample_rate(sample_hz);
        }
    }

    /// Get the next audio frame.
    fn next_frame(&mut self) -> AudioOut {
        self.pads.iter_mut().fold(AudioOut::equilibrium(),
                                  |f, pad| f.add_amp(pad.next_frame()))
    }
}

impl Iterator for Machine {
    type Item = AudioOut;

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

impl Node<AudioOut> for Machine {
    fn audio_requested(&mut self, buffer: &mut [AudioOut], sample_hz: f64) {
        let sample_hz_rounded = sample_hz.round() as u64;
        if sample_hz_rounded != self.sample_hz {
            self.set_sample_rate(sample_hz_rounded);
        }

        slice::map_in_place(buffer, |_| match self.next() {
            None => AudioOut::equilibrium(),
            Some(output) => output,
        });
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use fmt::{self, FlagV1};

struct PadAdapter<'a, 'b: 'a> {
    fmt: &'a mut fmt::Formatter<'b>,
    on_newline: bool,
}

impl<'a, 'b: 'a> PadAdapter<'a, 'b> {
    fn new(fmt: &'a mut fmt::Formatter<'b>) -> PadAdapter<'a, 'b> {
        PadAdapter {
            fmt: fmt,
            on_newline: false,
        }
    }
}

impl<'a, 'b: 'a> fmt::Write for PadAdapter<'a, 'b> {
    fn write_str(&mut self, mut s: &str) -> fmt::Result {
        while !s.is_empty() {
            if self.on_newline {
                self.fmt.write_str("    ")?;
            }

            let split = match s.find('\n') {
                Some(pos) => {
                    self.on_newline = true;
                    pos + 1
                }
                None => {
                    self.on_newline = false;
                    s.len()
                }
            };
            self.fmt.write_str(&s[..split])?;
            s = &s[split..];
        }

        Ok(())
    }
}

/// A struct to help with `fmt::Debug` implementations.
///
/// Constructed by the `Formatter::debug_struct` method.
#[must_use]
#[allow(missing_debug_implementations)]
#[stable(feature = "debug_builders", since = "1.2.0")]
pub struct DebugStruct<'a, 'b: 'a> {
    fmt: &'a mut fmt::Formatter<'b>,
    result: fmt::Result,
    has_fields: bool,
}

pub fn debug_struct_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>,
                                name: &str)
                                -> DebugStruct<'a, 'b> {
    let result = fmt.write_str(name);
    DebugStruct {
        fmt: fmt,
        result: result,
        has_fields: false,
    }
}

impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
    /// Adds a new field to the generated struct output.
    #[stable(feature = "debug_builders", since = "1.2.0")]
    pub fn field(&mut self, name: &str, value: &fmt::Debug) -> &mut DebugStruct<'a, 'b> {
        self.result = self.result.and_then(|_| {
            let prefix = if self.has_fields {
                ","
            } else {
                " {"
            };

            if self.is_pretty() {
                let mut writer = PadAdapter::new(self.fmt);
                fmt::write(&mut writer,
                           format_args!("{}\n{}: {:#?}", prefix, name, value))
            } else {
                write!(self.fmt, "{} {}: {:?}", prefix, name, value)
            }
        });

        self.has_fields = true;
        self
    }

    /// Finishes output and returns any error encountered.
    #[stable(feature = "debug_builders", since = "1.2.0")]
    pub fn finish(&mut self) -> fmt::Result {
        if self.has_fields {
            self.result = self.result.and_then(|_| {
                if self.is_pretty() {
                    self.fmt.write_str("\n}")
                } else {
                    self.fmt.write_str(" }")
                }
            });
        }
        self.result
    }

    fn is_pretty(&self) -> bool {
        self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
    }
}

/// A struct to help with `fmt::Debug` implementations.
///
/// Constructed by the `Formatter::debug_tuple` method.
#[must_use]
#[allow(missing_debug_implementations)]
#[stable(feature = "debug_builders", since = "1.2.0")]
pub struct DebugTuple<'a, 'b: 'a> {
    fmt: &'a mut fmt::Formatter<'b>,
    result: fmt::Result,
    fields: usize,
    empty_name: bool,
}

pub fn debug_tuple_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> DebugTuple<'a, 'b> {
    let result = fmt.write_str(name);
    DebugTuple {
        fmt: fmt,
        result: result,
        fields: 0,
        empty_name: name.is_empty(),
    }
}

impl<'a, 'b: 'a> DebugTuple<'a, 'b> {
    /// Adds a new field to the generated tuple struct output.
    #[stable(feature = "debug_builders", since = "1.2.0")]
    pub fn field(&mut self, value: &fmt::Debug) -> &mut DebugTuple<'a, 'b> {
        self.result = self.result.and_then(|_| {
            let (prefix, space) = if self.fields > 0 {
                (",", " ")
            } else {
                ("(", "")
            };

            if self.is_pretty() {
                let mut writer = PadAdapter::new(self.fmt);
                fmt::write(&mut writer, format_args!("{}\n{:#?}", prefix, value))
            } else {
                write!(self.fmt, "{}{}{:?}", prefix, space, value)
            }
        });

        self.fields += 1;
        self
    }

    /// Finishes output and returns any error encountered.
    #[stable(feature = "debug_builders", since = "1.2.0")]
    pub fn finish(&mut self) -> fmt::Result {
        if self.fields > 0 {
            self.result = self.result.and_then(|_| {
                if self.is_pretty() {
                    self.fmt.write_str("\n")?;
                }
                if self.fields == 1 && self.empty_name {
                    self.fmt.write_str(",")?;
                }
                self.fmt.write_str(")")
            });
        }
        self.result
    }

    fn is_pretty(&self) -> bool {
        self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
    }
}

struct DebugInner<'a, 'b: 'a> {
    fmt: &'a mut fmt::Formatter<'b>,
    result: fmt::Result,
    has_fields: bool,
}

impl<'a, 'b: 'a> DebugInner<'a, 'b> {
    fn entry(&mut self, entry: &fmt::Debug) {
        self.result = self.result.and_then(|_| {
            if self.is_pretty() {
                let mut writer = PadAdapter::new(self.fmt);
                let prefix = if self.has_fields {
                    ","
                } else {
                    ""
                };
                fmt::write(&mut writer, format_args!("{}\n{:#?}", prefix, entry))
            } else {
                let prefix = if self.has_fields {
                    ", "
                } else {
                    ""
                };
                write!(self.fmt, "{}{:?}", prefix, entry)
            }
        });

        self.has_fields = true;
    }

    pub fn finish(&mut self) {
        let prefix = if self.is_pretty() && self.has_fields {
            "\n"
        } else {
            ""
        };
        self.result = self.result.and_then(|_| self.fmt.write_str(prefix));
    }

    fn is_pretty(&self) -> bool {
        self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
    }
}

/// A struct to help with `fmt::Debug` implementations.
///
/// Constructed by the `Formatter::debug_set` method.
#[must_use]
#[allow(missing_debug_implementations)]
#[stable(feature = "debug_builders", since = "1.2.0")]
pub struct DebugSet<'a, 'b: 'a> {
    inner: DebugInner<'a, 'b>,
}

pub fn debug_set_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugSet<'a, 'b> {
    let result = write!(fmt, "{{");
    DebugSet {
        inner: DebugInner {
            fmt: fmt,
            result: result,
            has_fields: false,
        },
    }
}

impl<'a, 'b: 'a> DebugSet<'a, 'b> {
    /// Adds a new entry to the set output.
    #[stable(feature = "debug_builders", since = "1.2.0")]
    pub fn entry(&mut self, entry: &fmt::Debug) -> &mut DebugSet<'a, 'b> {
        self.inner.entry(entry);
        self
    }

    /// Adds the contents of an iterator of entries to the set output.
    #[stable(feature = "debug_builders", since = "1.2.0")]
    pub fn entries<D, I>(&mut self, entries: I) -> &mut DebugSet<'a, 'b>
        where D: fmt::Debug,
              I: IntoIterator<Item = D>
    {
        for entry in entries {
            self.entry(&entry);
        }
        self
    }

    /// Finishes output and returns any error encountered.
    #[stable(feature = "debug_builders", since = "1.2.0")]
    pub fn finish(&mut self) -> fmt::Result {
        self.inner.finish();
        self.inner.result.and_then(|_| self.inner.fmt.write_str("}"))
    }
}

/// A struct to help with `fmt::Debug` implementations.
///
/// Constructed by the `Formatter::debug_list` method.
#[must_use]
#[allow(missing_debug_implementations)]
#[stable(feature = "debug_builders", since = "1.2.0")]
pub struct DebugList<'a, 'b: 'a> {
    inner: DebugInner<'a, 'b>,
}

pub fn debug_list_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugList<'a, 'b> {
    let result = write!(fmt, "[");
    DebugList {
        inner: DebugInner {
            fmt: fmt,
            result: result,
            has_fields: false,
        },
    }
}

impl<'a, 'b: 'a> DebugList<'a, 'b> {
    /// Adds a new entry to the list output.
    #[stable(feature = "debug_builders", since = "1.2.0")]
    pub fn entry(&mut self, entry: &fmt::Debug) -> &mut DebugList<'a, 'b> {
        self.inner.entry(entry);
        self
    }

    /// Adds the contents of an iterator of entries to the list output.
    #[stable(feature = "debug_builders", since = "1.2.0")]
    pub fn entries<D, I>(&mut self, entries: I) -> &mut DebugList<'a, 'b>
        where D: fmt::Debug,
              I: IntoIterator<Item = D>
    {
        for entry in entries {
            self.entry(&entry);
        }
        self
    }

    /// Finishes output and returns any error encountered.
    #[stable(feature = "debug_builders", since = "1.2.0")]
    pub fn finish(&mut self) -> fmt::Result {
        self.inner.finish();
        self.inner.result.and_then(|_| self.inner.fmt.write_str("]"))
    }
}

/// A struct to help with `fmt::Debug` implementations.
///
/// Constructed by the `Formatter::debug_map` method.
#[must_use]
#[allow(missing_debug_implementations)]
#[stable(feature = "debug_builders", since = "1.2.0")]
pub struct DebugMap<'a, 'b: 'a> {
    fmt: &'a mut fmt::Formatter<'b>,
    result: fmt::Result,
    has_fields: bool,
}

pub fn debug_map_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugMap<'a, 'b> {
    let result = write!(fmt, "{{");
    DebugMap {
        fmt: fmt,
        result: result,
        has_fields: false,
    }
}

impl<'a, 'b: 'a> DebugMap<'a, 'b> {
    /// Adds a new entry to the map output.
    #[stable(feature = "debug_builders", since = "1.2.0")]
    pub fn entry(&mut self, key: &fmt::Debug, value: &fmt::Debug) -> &mut DebugMap<'a, 'b> {
        self.result = self.result.and_then(|_| {
            if self.is_pretty() {
                let mut writer = PadAdapter::new(self.fmt);
                let prefix = if self.has_fields {
                    ","
                } else {
                    ""
                };
                fmt::write(&mut writer,
                           format_args!("{}\n{:#?}: {:#?}", prefix, key, value))
            } else {
                let prefix = if self.has_fields {
                    ", "
                } else {
                    ""
                };
                write!(self.fmt, "{}{:?}: {:?}", prefix, key, value)
            }
        });

        self.has_fields = true;
        self
    }

    /// Adds the contents of an iterator of entries to the map output.
    #[stable(feature = "debug_builders", since = "1.2.0")]
    pub fn entries<K, V, I>(&mut self, entries: I) -> &mut DebugMap<'a, 'b>
        where K: fmt::Debug,
              V: fmt::Debug,
              I: IntoIterator<Item = (K, V)>
    {
        for (k, v) in entries {
            self.entry(&k, &v);
        }
        self
    }

    /// Finishes output and returns any error encountered.
    #[stable(feature = "debug_builders", since = "1.2.0")]
    pub fn finish(&mut self) -> fmt::Result {
        let prefix = if self.is_pretty() && self.has_fields {
            "\n"
        } else {
            ""
        };
        self.result.and_then(|_| write!(self.fmt, "{}}}", prefix))
    }

    fn is_pretty(&self) -> bool {
        self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
    }
}
<commit_msg>Rollup merge of #42836 - rthomas:29355-debug, r=GuillaumeGomez<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use fmt::{self, FlagV1};

struct PadAdapter<'a, 'b: 'a> {
    fmt: &'a mut fmt::Formatter<'b>,
    on_newline: bool,
}

impl<'a, 'b: 'a> PadAdapter<'a, 'b> {
    fn new(fmt: &'a mut fmt::Formatter<'b>) -> PadAdapter<'a, 'b> {
        PadAdapter {
            fmt: fmt,
            on_newline: false,
        }
    }
}

impl<'a, 'b: 'a> fmt::Write for PadAdapter<'a, 'b> {
    fn write_str(&mut self, mut s: &str) -> fmt::Result {
        while !s.is_empty() {
            if self.on_newline {
                self.fmt.write_str("    ")?;
            }

            let split = match s.find('\n') {
                Some(pos) => {
                    self.on_newline = true;
                    pos + 1
                }
                None => {
                    self.on_newline = false;
                    s.len()
                }
            };
            self.fmt.write_str(&s[..split])?;
            s = &s[split..];
        }

        Ok(())
    }
}

/// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations.
///
/// This is useful when you wish to output a formatted struct as a part of your
/// [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation.
///
/// This can be constructed by the
/// [`Formatter::debug_struct`](struct.Formatter.html#method.debug_struct)
/// method.
///
/// # Example
///
/// ```
/// use std::fmt;
///
/// struct Foo {
///     bar: i32,
///     baz: String,
/// }
///
/// impl fmt::Debug for Foo {
///     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
///         fmt.debug_struct("Foo")
///            .field("bar", &self.bar)
///            .field("baz", &self.baz)
///            .finish()
///     }
/// }
///
/// // prints "Foo { bar: 10, baz: "Hello World" }"
/// println!("{:?}", Foo { bar: 10, baz: "Hello World".to_string() });
/// ```
#[must_use]
#[allow(missing_debug_implementations)]
#[stable(feature = "debug_builders", since = "1.2.0")]
pub struct DebugStruct<'a, 'b: 'a> {
    fmt: &'a mut fmt::Formatter<'b>,
    result: fmt::Result,
    has_fields: bool,
}

pub fn debug_struct_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>,
                                name: &str)
                                -> DebugStruct<'a, 'b> {
    let result = fmt.write_str(name);
    DebugStruct {
        fmt: fmt,
        result: result,
        has_fields: false,
    }
}

impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
    /// Adds a new field to the generated struct output.
    #[stable(feature = "debug_builders", since = "1.2.0")]
    pub fn field(&mut self, name: &str, value: &fmt::Debug) -> &mut DebugStruct<'a, 'b> {
        self.result = self.result.and_then(|_| {
            let prefix = if self.has_fields {
                ","
            } else {
                " {"
            };

            if self.is_pretty() {
                let mut writer = PadAdapter::new(self.fmt);
                fmt::write(&mut writer,
                           format_args!("{}\n{}: {:#?}", prefix, name, value))
            } else {
                write!(self.fmt, "{} {}: {:?}", prefix, name, value)
            }
        });

        self.has_fields = true;
        self
    }

    /// Finishes output and returns any error encountered.
    #[stable(feature = "debug_builders", since = "1.2.0")]
    pub fn finish(&mut self) -> fmt::Result {
        if self.has_fields {
            self.result = self.result.and_then(|_| {
                if self.is_pretty() {
                    self.fmt.write_str("\n}")
                } else {
                    self.fmt.write_str(" }")
                }
            });
        }
        self.result
    }

    fn is_pretty(&self) -> bool {
        self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
    }
}

/// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations.
///
/// This is useful when you wish to output a formatted tuple as a part of your
/// [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation.
///
/// This can be constructed by the
/// [`Formatter::debug_tuple`](struct.Formatter.html#method.debug_tuple)
/// method.
///
/// # Example
///
/// ```
/// use std::fmt;
///
/// struct Foo(i32, String);
///
/// impl fmt::Debug for Foo {
///     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
///         fmt.debug_tuple("Foo")
///            .field(&self.0)
///            .field(&self.1)
///            .finish()
///     }
/// }
///
/// // prints "Foo(10, "Hello World")"
/// println!("{:?}", Foo(10, "Hello World".to_string()));
/// ```
#[must_use]
#[allow(missing_debug_implementations)]
#[stable(feature = "debug_builders", since = "1.2.0")]
pub struct DebugTuple<'a, 'b: 'a> {
    fmt: &'a mut fmt::Formatter<'b>,
    result: fmt::Result,
    fields: usize,
    empty_name: bool,
}

pub fn debug_tuple_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> DebugTuple<'a, 'b> {
    let result = fmt.write_str(name);
    DebugTuple {
        fmt: fmt,
        result: result,
        fields: 0,
        empty_name: name.is_empty(),
    }
}

impl<'a, 'b: 'a> DebugTuple<'a, 'b> {
    /// Adds a new field to the generated tuple struct output.
    #[stable(feature = "debug_builders", since = "1.2.0")]
    pub fn field(&mut self, value: &fmt::Debug) -> &mut DebugTuple<'a, 'b> {
        self.result = self.result.and_then(|_| {
            let (prefix, space) = if self.fields > 0 {
                (",", " ")
            } else {
                ("(", "")
            };

            if self.is_pretty() {
                let mut writer = PadAdapter::new(self.fmt);
                fmt::write(&mut writer, format_args!("{}\n{:#?}", prefix, value))
            } else {
                write!(self.fmt, "{}{}{:?}", prefix, space, value)
            }
        });

        self.fields += 1;
        self
    }

    /// Finishes output and returns any error encountered.
    #[stable(feature = "debug_builders", since = "1.2.0")]
    pub fn finish(&mut self) -> fmt::Result {
        if self.fields > 0 {
            self.result = self.result.and_then(|_| {
                if self.is_pretty() {
                    self.fmt.write_str("\n")?;
                }
                if self.fields == 1 && self.empty_name {
                    self.fmt.write_str(",")?;
                }
                self.fmt.write_str(")")
            });
        }
        self.result
    }

    fn is_pretty(&self) -> bool {
        self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
    }
}

struct DebugInner<'a, 'b: 'a> {
    fmt: &'a mut fmt::Formatter<'b>,
    result: fmt::Result,
    has_fields: bool,
}

impl<'a, 'b: 'a> DebugInner<'a, 'b> {
    fn entry(&mut self, entry: &fmt::Debug) {
        self.result = self.result.and_then(|_| {
            if self.is_pretty() {
                let mut writer = PadAdapter::new(self.fmt);
                let prefix = if self.has_fields {
                    ","
                } else {
                    ""
                };
                fmt::write(&mut writer, format_args!("{}\n{:#?}", prefix, entry))
            } else {
                let prefix = if self.has_fields {
                    ", "
                } else {
                    ""
                };
                write!(self.fmt, "{}{:?}", prefix, entry)
            }
        });

        self.has_fields = true;
    }

    pub fn finish(&mut self) {
        let prefix = if self.is_pretty() && self.has_fields {
            "\n"
        } else {
            ""
        };
        self.result = self.result.and_then(|_| self.fmt.write_str(prefix));
    }

    fn is_pretty(&self) -> bool {
        self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
    }
}

/// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations.
///
/// This is useful when you wish to output a formatted set of items as a part
/// of your [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation.
///
/// This can be constructed by the
/// [`Formatter::debug_set`](struct.Formatter.html#method.debug_set)
/// method.
///
/// # Example
///
/// ```
/// use std::fmt;
///
/// struct Foo(Vec<i32>);
///
/// impl fmt::Debug for Foo {
///     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
///         fmt.debug_set().entries(self.0.iter()).finish()
///     }
/// }
///
/// // prints "{10, 11}"
/// println!("{:?}", Foo(vec![10, 11]));
/// ```
#[must_use]
#[allow(missing_debug_implementations)]
#[stable(feature = "debug_builders", since = "1.2.0")]
pub struct DebugSet<'a, 'b: 'a> {
    inner: DebugInner<'a, 'b>,
}

pub fn debug_set_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugSet<'a, 'b> {
    let result = write!(fmt, "{{");
    DebugSet {
        inner: DebugInner {
            fmt: fmt,
            result: result,
            has_fields: false,
        },
    }
}

impl<'a, 'b: 'a> DebugSet<'a, 'b> {
    /// Adds a new entry to the set output.
    #[stable(feature = "debug_builders", since = "1.2.0")]
    pub fn entry(&mut self, entry: &fmt::Debug) -> &mut DebugSet<'a, 'b> {
        self.inner.entry(entry);
        self
    }

    /// Adds the contents of an iterator of entries to the set output.
    #[stable(feature = "debug_builders", since = "1.2.0")]
    pub fn entries<D, I>(&mut self, entries: I) -> &mut DebugSet<'a, 'b>
        where D: fmt::Debug,
              I: IntoIterator<Item = D>
    {
        for entry in entries {
            self.entry(&entry);
        }
        self
    }

    /// Finishes output and returns any error encountered.
    #[stable(feature = "debug_builders", since = "1.2.0")]
    pub fn finish(&mut self) -> fmt::Result {
        self.inner.finish();
        self.inner.result.and_then(|_| self.inner.fmt.write_str("}"))
    }
}

/// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations.
///
/// This is useful when you wish to output a formatted list of items as a part
/// of your [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation.
///
/// This can be constructed by the
/// [`Formatter::debug_list`](struct.Formatter.html#method.debug_list)
/// method.
///
/// # Example
///
/// ```
/// use std::fmt;
///
/// struct Foo(Vec<i32>);
///
/// impl fmt::Debug for Foo {
///     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
///         fmt.debug_list().entries(self.0.iter()).finish()
///     }
/// }
///
/// // prints "[10, 11]"
/// println!("{:?}", Foo(vec![10, 11]));
/// ```
#[must_use]
#[allow(missing_debug_implementations)]
#[stable(feature = "debug_builders", since = "1.2.0")]
pub struct DebugList<'a, 'b: 'a> {
    inner: DebugInner<'a, 'b>,
}

pub fn debug_list_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugList<'a, 'b> {
    let result = write!(fmt, "[");
    DebugList {
        inner: DebugInner {
            fmt: fmt,
            result: result,
            has_fields: false,
        },
    }
}

impl<'a, 'b: 'a> DebugList<'a, 'b> {
    /// Adds a new entry to the list output.
    #[stable(feature = "debug_builders", since = "1.2.0")]
    pub fn entry(&mut self, entry: &fmt::Debug) -> &mut DebugList<'a, 'b> {
        self.inner.entry(entry);
        self
    }

    /// Adds the contents of an iterator of entries to the list output.
    #[stable(feature = "debug_builders", since = "1.2.0")]
    pub fn entries<D, I>(&mut self, entries: I) -> &mut DebugList<'a, 'b>
        where D: fmt::Debug,
              I: IntoIterator<Item = D>
    {
        for entry in entries {
            self.entry(&entry);
        }
        self
    }

    /// Finishes output and returns any error encountered.
    #[stable(feature = "debug_builders", since = "1.2.0")]
    pub fn finish(&mut self) -> fmt::Result {
        self.inner.finish();
        self.inner.result.and_then(|_| self.inner.fmt.write_str("]"))
    }
}

/// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations.
///
/// This is useful when you wish to output a formatted map as a part of your
/// [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation.
///
/// This can be constructed by the
/// [`Formatter::debug_map`](struct.Formatter.html#method.debug_map)
/// method.
///
/// # Example
///
/// ```
/// use std::fmt;
///
/// struct Foo(Vec<(String, i32)>);
///
/// impl fmt::Debug for Foo {
///     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
///         fmt.debug_map().entries(self.0.iter().map(|&(ref k, ref v)| (k, v))).finish()
///     }
/// }
///
/// // prints "{"A": 10, "B": 11}"
/// println!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)]));
/// ```
#[must_use]
#[allow(missing_debug_implementations)]
#[stable(feature = "debug_builders", since = "1.2.0")]
pub struct DebugMap<'a, 'b: 'a> {
    fmt: &'a mut fmt::Formatter<'b>,
    result: fmt::Result,
    has_fields: bool,
}

pub fn debug_map_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugMap<'a, 'b> {
    let result = write!(fmt, "{{");
    DebugMap {
        fmt: fmt,
        result: result,
        has_fields: false,
    }
}

impl<'a, 'b: 'a> DebugMap<'a, 'b> {
    /// Adds a new entry to the map output.
    #[stable(feature = "debug_builders", since = "1.2.0")]
    pub fn entry(&mut self, key: &fmt::Debug, value: &fmt::Debug) -> &mut DebugMap<'a, 'b> {
        self.result = self.result.and_then(|_| {
            if self.is_pretty() {
                let mut writer = PadAdapter::new(self.fmt);
                let prefix = if self.has_fields {
                    ","
                } else {
                    ""
                };
                fmt::write(&mut writer,
                           format_args!("{}\n{:#?}: {:#?}", prefix, key, value))
            } else {
                let prefix = if self.has_fields {
                    ", "
                } else {
                    ""
                };
                write!(self.fmt, "{}{:?}: {:?}", prefix, key, value)
            }
        });

        self.has_fields = true;
        self
    }

    /// Adds the contents of an iterator of entries to the map output.
    #[stable(feature = "debug_builders", since = "1.2.0")]
    pub fn entries<K, V, I>(&mut self, entries: I) -> &mut DebugMap<'a, 'b>
        where K: fmt::Debug,
              V: fmt::Debug,
              I: IntoIterator<Item = (K, V)>
    {
        for (k, v) in entries {
            self.entry(&k, &v);
        }
        self
    }

    /// Finishes output and returns any error encountered.
    #[stable(feature = "debug_builders", since = "1.2.0")]
    pub fn finish(&mut self) -> fmt::Result {
        let prefix = if self.is_pretty() && self.has_fields {
            "\n"
        } else {
            ""
        };
        self.result.and_then(|_| write!(self.fmt, "{}}}", prefix))
    }

    fn is_pretty(&self) -> bool {
        self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
    }
}
<|endoftext|>


<commit_before>#[crate_id = "redis-example#0.1"];
#[crate_type = "app"];

extern mod redis;

fn main() {
    let mut client = redis::Client::open("redis://127.0.0.1/").unwrap();
    client.set("foo", 42);
    client.set("bar", "test");
    println!("foo get: {:?}", client.get("foo"));
    println!("foo as int: {:?}", client.get_as::<int>("foo"));
    println!("ping: {:?}", client.ping());
    println!("keys: {:?}", client.keys("*"));
    println!("foo type: {:?}", client.get_type("foo"));
    println!("foo exists: {:?}", client.exists("foo"));

    let info = client.info();
    println!("info role: {:?}", info.find(&~"role"));
    println!("info version: {:?}", info.find(&~"redis_version"));

    let script = redis::Script::new("
        return tonumber(ARGV[1]);
    ");
    println!("script result: {:?}", client.call_script(
        &script, [], [redis::StrArg("42")]));

    println!("last save: {}", client.lastsave().rfc822());
    println!("server time: {}", client.time().rfc822());
}
<commit_msg>Fixed crate type to bin<commit_after>#[crate_id = "redis-example#0.1"];
#[crate_type = "bin"];

extern mod redis;

fn main() {
    let mut client = redis::Client::open("redis://127.0.0.1/").unwrap();
    client.set("foo", 42);
    client.set("bar", "test");
    println!("foo get: {:?}", client.get("foo"));
    println!("foo as int: {:?}", client.get_as::<int>("foo"));
    println!("ping: {:?}", client.ping());
    println!("keys: {:?}", client.keys("*"));
    println!("foo type: {:?}", client.get_type("foo"));
    println!("foo exists: {:?}", client.exists("foo"));

    let info = client.info();
    println!("info role: {:?}", info.find(&~"role"));
    println!("info version: {:?}", info.find(&~"redis_version"));

    let script = redis::Script::new("
        return tonumber(ARGV[1]);
    ");
    println!("script result: {:?}", client.call_script(
        &script, [], [redis::StrArg("42")]));

    println!("last save: {}", client.lastsave().rfc822());
    println!("server time: {}", client.time().rfc822());
}
<|endoftext|>


<commit_before>//! Generates descriptors structure for unstable feature from Unstable Book
use std::{borrow::Cow, fs, path::Path};

use itertools::Itertools;
use stdx::format_to;
use test_utils::project_root;
use xshell::cmd;

/// This clones rustc repo, and so is not worth to keep up-to-date. We update
/// manually by un-ignoring the test from time to time.
#[test]
#[ignore]
fn sourcegen_lint_completions() {
    let rust_repo = project_root().join("./target/rust");
    if !rust_repo.exists() {
        cmd!("git clone --depth=1 https://github.com/rust-lang/rust {rust_repo}").run().unwrap();
    }

    let mut contents = String::from(
        r"
pub struct Lint {
    pub label: &'static str,
    pub description: &'static str,
}
pub struct LintGroup {
    pub lint: Lint,
    pub children: &'static [&'static str],
}
",
    );

    generate_lint_descriptor(&mut contents);
    contents.push('\n');

    generate_feature_descriptor(&mut contents, &rust_repo.join("src/doc/unstable-book/src"));
    contents.push('\n');

    let lints_json = project_root().join("./target/clippy_lints.json");
    cmd!("curl https://rust-lang.github.io/rust-clippy/master/lints.json --output {lints_json}")
        .run()
        .unwrap();
    generate_descriptor_clippy(&mut contents, &lints_json);

    let contents = sourcegen::add_preamble("sourcegen_lints", sourcegen::reformat(contents));

    let destination = project_root().join("crates/ide_db/src/helpers/generated_lints.rs");
    sourcegen::ensure_file_contents(destination.as_path(), &contents);
}

fn generate_lint_descriptor(buf: &mut String) {
    // FIXME: rustdoc currently requires an input file for -Whelp cc https://github.com/rust-lang/rust/pull/88831
    let file = project_root().join(file!());
    let stdout = cmd!("rustdoc -W help {file}").read().unwrap();
    let start_lints = stdout.find("----  -------  -------").unwrap();
    let start_lint_groups = stdout.find("----  ---------").unwrap();
    let start_lints_rustdoc =
        stdout.find("Lint checks provided by plugins loaded by this crate:").unwrap();
    let start_lint_groups_rustdoc =
        stdout.find("Lint groups provided by plugins loaded by this crate:").unwrap();

    buf.push_str(r#"pub const DEFAULT_LINTS: &[Lint] = &["#);
    buf.push('\n');

    let lints = stdout[start_lints..].lines().skip(1).take_while(|l| !l.is_empty()).map(|line| {
        let (name, rest) = line.trim().split_once(char::is_whitespace).unwrap();
        let (_default_level, description) = rest.trim().split_once(char::is_whitespace).unwrap();
        (name.trim(), Cow::Borrowed(description.trim()), vec![])
    });
    let lint_groups =
        stdout[start_lint_groups..].lines().skip(1).take_while(|l| !l.is_empty()).map(|line| {
            let (name, lints) = line.trim().split_once(char::is_whitespace).unwrap();
            (
                name.trim(),
                format!("lint group for: {}", lints.trim()).into(),
                lints
                    .split_ascii_whitespace()
                    .map(|s| s.trim().trim_matches(',').replace("-", "_"))
                    .collect(),
            )
        });

    let lints = lints
        .chain(lint_groups)
        .sorted_by(|(ident, ..), (ident2, ..)| ident.cmp(ident2))
        .collect::<Vec<_>>();
    for (name, description, ..) in &lints {
        push_lint_completion(buf, &name.replace("-", "_"), &description);
    }
    buf.push_str("];\n");
    buf.push_str(r#"pub const DEFAULT_LINT_GROUPS: &[LintGroup] = &["#);
    for (name, description, children) in &lints {
        if !children.is_empty() {
            // HACK: warnings is emitted with a general description, not with its members
            if name == &"warnings" {
                push_lint_group(buf, &name, &description, &Vec::new());
                continue;
            }
            push_lint_group(buf, &name.replace("-", "_"), &description, children);
        }
    }
    buf.push('\n');
    buf.push_str("];\n");

    // rustdoc

    buf.push('\n');
    buf.push_str(r#"pub const RUSTDOC_LINTS: &[Lint] = &["#);
    buf.push('\n');

    let lints_rustdoc =
        stdout[start_lints_rustdoc..].lines().skip(2).take_while(|l| !l.is_empty()).map(|line| {
            let (name, rest) = line.trim().split_once(char::is_whitespace).unwrap();
            let (_default_level, description) =
                rest.trim().split_once(char::is_whitespace).unwrap();
            (name.trim(), Cow::Borrowed(description.trim()), vec![])
        });
    let lint_groups_rustdoc =
        stdout[start_lint_groups_rustdoc..].lines().skip(2).take_while(|l| !l.is_empty()).map(
            |line| {
                let (name, lints) = line.trim().split_once(char::is_whitespace).unwrap();
                (
                    name.trim(),
                    format!("lint group for: {}", lints.trim()).into(),
                    lints
                        .split_ascii_whitespace()
                        .map(|s| s.trim().trim_matches(',').replace("-", "_"))
                        .collect(),
                )
            },
        );

    let lints_rustdoc = lints_rustdoc
        .chain(lint_groups_rustdoc)
        .sorted_by(|(ident, ..), (ident2, ..)| ident.cmp(ident2))
        .collect::<Vec<_>>();

    for (name, description, ..) in &lints_rustdoc {
        push_lint_completion(buf, &name.replace("-", "_"), &description)
    }
    buf.push_str("];\n");

    buf.push_str(r#"pub const RUSTDOC_LINT_GROUPS: &[LintGroup] = &["#);
    for (name, description, children) in &lints_rustdoc {
        if !children.is_empty() {
            push_lint_group(buf, &name.replace("-", "_"), &description, children);
        }
    }
    buf.push('\n');
    buf.push_str("];\n");
}

fn generate_feature_descriptor(buf: &mut String, src_dir: &Path) {
    let mut features = ["language-features", "library-features"]
        .into_iter()
        .flat_map(|it| sourcegen::list_files(&src_dir.join(it)))
        .filter(|path| {
            // Get all `.md ` files
            path.extension().unwrap_or_default().to_str().unwrap_or_default() == "md"
        })
        .map(|path| {
            let feature_ident = path.file_stem().unwrap().to_str().unwrap().replace("-", "_");
            let doc = fs::read_to_string(path).unwrap();
            (feature_ident, doc)
        })
        .collect::<Vec<_>>();
    features.sort_by(|(feature_ident, _), (feature_ident2, _)| feature_ident.cmp(feature_ident2));

    buf.push_str(r#"pub const FEATURES: &[Lint] = &["#);
    for (feature_ident, doc) in features.into_iter() {
        push_lint_completion(buf, &feature_ident, &doc)
    }
    buf.push('\n');
    buf.push_str("];\n");
}

#[derive(Default)]
struct ClippyLint {
    help: String,
    id: String,
}

fn unescape(s: &str) -> String {
    s.replace(r#"\""#, "").replace(r#"\n"#, "\n").replace(r#"\r"#, "")
}

fn generate_descriptor_clippy(buf: &mut String, path: &Path) {
    let file_content = std::fs::read_to_string(path).unwrap();
    let mut clippy_lints: Vec<ClippyLint> = Vec::new();
    let mut clippy_groups: std::collections::BTreeMap<String, Vec<String>> = Default::default();

    for line in file_content.lines().map(|line| line.trim()) {
        if let Some(line) = line.strip_prefix(r#""id": ""#) {
            let clippy_lint = ClippyLint {
                id: line.strip_suffix(r#"","#).expect("should be suffixed by comma").into(),
                help: String::new(),
            };
            clippy_lints.push(clippy_lint)
        } else if let Some(line) = line.strip_prefix(r#""group": ""#) {
            if let Some(group) = line.strip_suffix("\",") {
                clippy_groups
                    .entry(group.to_owned())
                    .or_default()
                    .push(clippy_lints.last().unwrap().id.clone());
            }
        } else if let Some(line) = line.strip_prefix(r#""docs": ""#) {
            let prefix_to_strip = r#" ### What it does"#;
            let line = match line.strip_prefix(prefix_to_strip) {
                Some(line) => line,
                None => {
                    eprintln!("unexpected clippy prefix for {}", clippy_lints.last().unwrap().id);
                    continue;
                }
            };
            // Only take the description, any more than this is a lot of additional data we would embed into the exe
            // which seems unnecessary
            let up_to = line.find(r#"###"#).expect("no second section found?");
            let line = &line[..up_to];

            let clippy_lint = clippy_lints.last_mut().expect("clippy lint must already exist");
            clippy_lint.help = unescape(line).trim().to_string();
        }
    }
    clippy_lints.sort_by(|lint, lint2| lint.id.cmp(&lint2.id));

    buf.push_str(r#"pub const CLIPPY_LINTS: &[Lint] = &["#);
    buf.push('\n');
    for clippy_lint in clippy_lints.into_iter() {
        let lint_ident = format!("clippy::{}", clippy_lint.id);
        let doc = clippy_lint.help;
        push_lint_completion(buf, &lint_ident, &doc);
    }
    buf.push_str("];\n");

    buf.push_str(r#"pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &["#);
    for (id, children) in clippy_groups {
        let children = children.iter().map(|id| format!("clippy::{}", id)).collect::<Vec<_>>();
        if !children.is_empty() {
            let lint_ident = format!("clippy::{}", id);
            let description = format!("lint group for: {}", children.iter().join(", "));
            push_lint_group(buf, &lint_ident, &description, &children);
        }
    }
    buf.push('\n');
    buf.push_str("];\n");
}

fn push_lint_completion(buf: &mut String, label: &str, description: &str) {
    format_to!(
        buf,
        r###"    Lint {{
        label: "{}",
        description: r##"{}"##,
    }},"###,
        label,
        description,
    );
}

fn push_lint_group<'a>(buf: &mut String, label: &str, description: &str, children: &[String]) {
    buf.push_str(
        r###"    LintGroup {
        lint:
        "###,
    );

    push_lint_completion(buf, label, description);

    let children = format!("&[{}]", children.iter().map(|it| format!("\"{}\"", it)).join(", "));
    format_to!(
        buf,
        r###"
        children: {},
        }},"###,
        children,
    );
}
<commit_msg>List struct to clonable<commit_after>//! Generates descriptors structure for unstable feature from Unstable Book
use std::{borrow::Cow, fs, path::Path};

use itertools::Itertools;
use stdx::format_to;
use test_utils::project_root;
use xshell::cmd;

/// This clones rustc repo, and so is not worth to keep up-to-date. We update
/// manually by un-ignoring the test from time to time.
#[test]
#[ignore]
fn sourcegen_lint_completions() {
    let rust_repo = project_root().join("./target/rust");
    if !rust_repo.exists() {
        cmd!("git clone --depth=1 https://github.com/rust-lang/rust {rust_repo}").run().unwrap();
    }

    let mut contents = String::from(
        r"
#[derive(Clone)]
pub struct Lint {
    pub label: &'static str,
    pub description: &'static str,
}
pub struct LintGroup {
    pub lint: Lint,
    pub children: &'static [&'static str],
}
",
    );

    generate_lint_descriptor(&mut contents);
    contents.push('\n');

    generate_feature_descriptor(&mut contents, &rust_repo.join("src/doc/unstable-book/src"));
    contents.push('\n');

    let lints_json = project_root().join("./target/clippy_lints.json");
    cmd!("curl https://rust-lang.github.io/rust-clippy/master/lints.json --output {lints_json}")
        .run()
        .unwrap();
    generate_descriptor_clippy(&mut contents, &lints_json);

    let contents = sourcegen::add_preamble("sourcegen_lints", sourcegen::reformat(contents));

    let destination = project_root().join("crates/ide_db/src/helpers/generated_lints.rs");
    sourcegen::ensure_file_contents(destination.as_path(), &contents);
}

fn generate_lint_descriptor(buf: &mut String) {
    // FIXME: rustdoc currently requires an input file for -Whelp cc https://github.com/rust-lang/rust/pull/88831
    let file = project_root().join(file!());
    let stdout = cmd!("rustdoc -W help {file}").read().unwrap();
    let start_lints = stdout.find("----  -------  -------").unwrap();
    let start_lint_groups = stdout.find("----  ---------").unwrap();
    let start_lints_rustdoc =
        stdout.find("Lint checks provided by plugins loaded by this crate:").unwrap();
    let start_lint_groups_rustdoc =
        stdout.find("Lint groups provided by plugins loaded by this crate:").unwrap();

    buf.push_str(r#"pub const DEFAULT_LINTS: &[Lint] = &["#);
    buf.push('\n');

    let lints = stdout[start_lints..].lines().skip(1).take_while(|l| !l.is_empty()).map(|line| {
        let (name, rest) = line.trim().split_once(char::is_whitespace).unwrap();
        let (_default_level, description) = rest.trim().split_once(char::is_whitespace).unwrap();
        (name.trim(), Cow::Borrowed(description.trim()), vec![])
    });
    let lint_groups =
        stdout[start_lint_groups..].lines().skip(1).take_while(|l| !l.is_empty()).map(|line| {
            let (name, lints) = line.trim().split_once(char::is_whitespace).unwrap();
            (
                name.trim(),
                format!("lint group for: {}", lints.trim()).into(),
                lints
                    .split_ascii_whitespace()
                    .map(|s| s.trim().trim_matches(',').replace("-", "_"))
                    .collect(),
            )
        });

    let lints = lints
        .chain(lint_groups)
        .sorted_by(|(ident, ..), (ident2, ..)| ident.cmp(ident2))
        .collect::<Vec<_>>();
    for (name, description, ..) in &lints {
        push_lint_completion(buf, &name.replace("-", "_"), &description);
    }
    buf.push_str("];\n");
    buf.push_str(r#"pub const DEFAULT_LINT_GROUPS: &[LintGroup] = &["#);
    for (name, description, children) in &lints {
        if !children.is_empty() {
            // HACK: warnings is emitted with a general description, not with its members
            if name == &"warnings" {
                push_lint_group(buf, &name, &description, &Vec::new());
                continue;
            }
            push_lint_group(buf, &name.replace("-", "_"), &description, children);
        }
    }
    buf.push('\n');
    buf.push_str("];\n");

    // rustdoc

    buf.push('\n');
    buf.push_str(r#"pub const RUSTDOC_LINTS: &[Lint] = &["#);
    buf.push('\n');

    let lints_rustdoc =
        stdout[start_lints_rustdoc..].lines().skip(2).take_while(|l| !l.is_empty()).map(|line| {
            let (name, rest) = line.trim().split_once(char::is_whitespace).unwrap();
            let (_default_level, description) =
                rest.trim().split_once(char::is_whitespace).unwrap();
            (name.trim(), Cow::Borrowed(description.trim()), vec![])
        });
    let lint_groups_rustdoc =
        stdout[start_lint_groups_rustdoc..].lines().skip(2).take_while(|l| !l.is_empty()).map(
            |line| {
                let (name, lints) = line.trim().split_once(char::is_whitespace).unwrap();
                (
                    name.trim(),
                    format!("lint group for: {}", lints.trim()).into(),
                    lints
                        .split_ascii_whitespace()
                        .map(|s| s.trim().trim_matches(',').replace("-", "_"))
                        .collect(),
                )
            },
        );

    let lints_rustdoc = lints_rustdoc
        .chain(lint_groups_rustdoc)
        .sorted_by(|(ident, ..), (ident2, ..)| ident.cmp(ident2))
        .collect::<Vec<_>>();

    for (name, description, ..) in &lints_rustdoc {
        push_lint_completion(buf, &name.replace("-", "_"), &description)
    }
    buf.push_str("];\n");

    buf.push_str(r#"pub const RUSTDOC_LINT_GROUPS: &[LintGroup] = &["#);
    for (name, description, children) in &lints_rustdoc {
        if !children.is_empty() {
            push_lint_group(buf, &name.replace("-", "_"), &description, children);
        }
    }
    buf.push('\n');
    buf.push_str("];\n");
}

fn generate_feature_descriptor(buf: &mut String, src_dir: &Path) {
    let mut features = ["language-features", "library-features"]
        .into_iter()
        .flat_map(|it| sourcegen::list_files(&src_dir.join(it)))
        .filter(|path| {
            // Get all `.md ` files
            path.extension().unwrap_or_default().to_str().unwrap_or_default() == "md"
        })
        .map(|path| {
            let feature_ident = path.file_stem().unwrap().to_str().unwrap().replace("-", "_");
            let doc = fs::read_to_string(path).unwrap();
            (feature_ident, doc)
        })
        .collect::<Vec<_>>();
    features.sort_by(|(feature_ident, _), (feature_ident2, _)| feature_ident.cmp(feature_ident2));

    buf.push_str(r#"pub const FEATURES: &[Lint] = &["#);
    for (feature_ident, doc) in features.into_iter() {
        push_lint_completion(buf, &feature_ident, &doc)
    }
    buf.push('\n');
    buf.push_str("];\n");
}

#[derive(Default)]
struct ClippyLint {
    help: String,
    id: String,
}

fn unescape(s: &str) -> String {
    s.replace(r#"\""#, "").replace(r#"\n"#, "\n").replace(r#"\r"#, "")
}

fn generate_descriptor_clippy(buf: &mut String, path: &Path) {
    let file_content = std::fs::read_to_string(path).unwrap();
    let mut clippy_lints: Vec<ClippyLint> = Vec::new();
    let mut clippy_groups: std::collections::BTreeMap<String, Vec<String>> = Default::default();

    for line in file_content.lines().map(|line| line.trim()) {
        if let Some(line) = line.strip_prefix(r#""id": ""#) {
            let clippy_lint = ClippyLint {
                id: line.strip_suffix(r#"","#).expect("should be suffixed by comma").into(),
                help: String::new(),
            };
            clippy_lints.push(clippy_lint)
        } else if let Some(line) = line.strip_prefix(r#""group": ""#) {
            if let Some(group) = line.strip_suffix("\",") {
                clippy_groups
                    .entry(group.to_owned())
                    .or_default()
                    .push(clippy_lints.last().unwrap().id.clone());
            }
        } else if let Some(line) = line.strip_prefix(r#""docs": ""#) {
            let prefix_to_strip = r#" ### What it does"#;
            let line = match line.strip_prefix(prefix_to_strip) {
                Some(line) => line,
                None => {
                    eprintln!("unexpected clippy prefix for {}", clippy_lints.last().unwrap().id);
                    continue;
                }
            };
            // Only take the description, any more than this is a lot of additional data we would embed into the exe
            // which seems unnecessary
            let up_to = line.find(r#"###"#).expect("no second section found?");
            let line = &line[..up_to];

            let clippy_lint = clippy_lints.last_mut().expect("clippy lint must already exist");
            clippy_lint.help = unescape(line).trim().to_string();
        }
    }
    clippy_lints.sort_by(|lint, lint2| lint.id.cmp(&lint2.id));

    buf.push_str(r#"pub const CLIPPY_LINTS: &[Lint] = &["#);
    buf.push('\n');
    for clippy_lint in clippy_lints.into_iter() {
        let lint_ident = format!("clippy::{}", clippy_lint.id);
        let doc = clippy_lint.help;
        push_lint_completion(buf, &lint_ident, &doc);
    }
    buf.push_str("];\n");

    buf.push_str(r#"pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &["#);
    for (id, children) in clippy_groups {
        let children = children.iter().map(|id| format!("clippy::{}", id)).collect::<Vec<_>>();
        if !children.is_empty() {
            let lint_ident = format!("clippy::{}", id);
            let description = format!("lint group for: {}", children.iter().join(", "));
            push_lint_group(buf, &lint_ident, &description, &children);
        }
    }
    buf.push('\n');
    buf.push_str("];\n");
}

fn push_lint_completion(buf: &mut String, label: &str, description: &str) {
    format_to!(
        buf,
        r###"    Lint {{
        label: "{}",
        description: r##"{}"##,
    }},"###,
        label,
        description,
    );
}

fn push_lint_group<'a>(buf: &mut String, label: &str, description: &str, children: &[String]) {
    buf.push_str(
        r###"    LintGroup {
        lint:
        "###,
    );

    push_lint_completion(buf, label, description);

    let children = format!("&[{}]", children.iter().map(|it| format!("\"{}\"", it)).join(", "));
    format_to!(
        buf,
        r###"
        children: {},
        }},"###,
        children,
    );
}
<|endoftext|>


<commit_before>///! Basic CSS block layout.

use style;
use style::StyledNode;
use css::{Keyword, Length, Px};
use std::default::Default;
use std::iter::AdditiveIterator; // for `sum`

// CSS box model. All sizes are in px.

#[deriving(Default, Show)]
pub struct Dimensions {
    // Position of the content area relative to the document origin:
    pub x: f32,
    pub y: f32,

    // Content area size:
    pub width: f32,
    pub height: f32,

    // Surrounding edges:
    pub padding: EdgeSizes,
    pub border: EdgeSizes,
    pub margin: EdgeSizes,
}

/// A node in the layout tree.
pub struct LayoutBox<'a> {
    pub box_type: BoxType<'a>,
    pub dimensions: Dimensions,
    pub children: Vec<LayoutBox<'a>>,
}

pub enum BoxType<'a> {
    BlockNode(&'a StyledNode<'a>),
    InlineNode(&'a StyledNode<'a>),
    InlineContainer,
}

impl<'a> LayoutBox<'a> {
    fn new(box_type: BoxType) -> LayoutBox {
        LayoutBox {
            box_type: box_type,
            dimensions: Default::default(),
            children: Vec::new(),
        }
    }

    fn style_node(&self) -> &'a StyledNode<'a> {
        match self.box_type {
            BlockNode(style_node) => style_node,
            InlineNode(style_node) => style_node,
            InlineContainer => fail!("Inline container has no style node")
        }
    }
}

#[deriving(Default, Show)]
struct EdgeSizes { left: f32, right: f32, top: f32, bottom: f32 }

/// Transform a style tree into a layout tree.
pub fn layout_tree<'a>(node: &'a StyledNode<'a>, containing_block: Dimensions) -> LayoutBox<'a> {
    let mut root_box = build_layout_tree(node);
    root_box.layout(containing_block);
    return root_box;
}

/// Build the tree of LayoutBoxes, but don't perform any layout calculations yet.
fn build_layout_tree<'a>(style_node: &'a StyledNode<'a>) -> LayoutBox<'a> {
    // Create the root box.
    let mut root = LayoutBox::new(match style_node.display() {
        style::Block => BlockNode(style_node),
        style::Inline => InlineNode(style_node),
        style::None => fail!("Root node has display: none.")
    });

    // Create the descendant boxes.
    for child in style_node.children.iter() {
        match child.display() {
            style::Block => root.children.push(build_layout_tree(child)),
            style::Inline => root.push_inline(build_layout_tree(child)),
            style::None => {} // Don't lay out nodes with `display: none;`
        }
    }
    return root;
}

impl<'a> LayoutBox<'a> {
    /// Lay out a single box and its descendants.
    fn layout(&mut self, containing_block: Dimensions) {
        match self.box_type {
            BlockNode(_) => self.layout_block(containing_block),
            InlineNode(_) => {} // TODO
            InlineContainer => {} // TODO
        }
    }

    /// Lay out a block-level element and its descendants.
    fn layout_block(&mut self, containing_block: Dimensions) {
        // Child width can depend on parent width, so we need to calculate this node's width before
        // laying out its children.
        self.calculate_block_width(containing_block);

        // Recursively lay out the children of this node within its content area.
        let content_height = self.layout_block_content(containing_block);

        // Parent height can depend on child height, so `calculate_height` must be called after the
        // content layout is finished.
        self.calculate_block_height(content_height);
    }

    /// Calculate the width of a block-level non-replaced element in normal flow.
    ///
    /// http://www.w3.org/TR/CSS2/visudet.html#blockwidth
    fn calculate_block_width(&mut self, containing_block: Dimensions) {
        let style = self.style_node();

        // `width` has initial value `auto`.
        let auto = Keyword("auto".to_string());
        let mut width = style.value("width").unwrap_or(auto.clone());

        // margin, border, and padding have initial value 0.
        let zero = Length(0.0, Px);

        let mut margin_left = style.lookup("margin-left", "margin", &zero);
        let mut margin_right = style.lookup("margin-right", "margin", &zero);

        let border_left = style.lookup("border-left-width", "border-width", &zero);
        let border_right = style.lookup("border-right-width", "border-width", &zero);

        let padding_left = style.lookup("padding-left", "padding", &zero);
        let padding_right = style.lookup("padding-right", "padding", &zero);

        let total = [&margin_left, &margin_right, &border_left, &border_right,
                     &padding_left, &padding_right, &width].iter().map(|v| v.to_px()).sum();

        // If width is not auto and the total is wider than the container, treat auto margins as 0.
        if width != auto && total > containing_block.width {
            if margin_left == auto {
                margin_left = Length(0.0, Px);
            }
            if margin_right == auto {
                margin_right = Length(0.0, Px);
            }
        }

        // Adjust used values so that the above sum equals `containing_block.width`.
        // Each arm of the `match` should increase the total width by exactly `underflow`,
        // and afterward all values should be absolute lengths in px.
        let underflow = containing_block.width - total;
        match (width == auto, margin_left == auto, margin_right == auto) {
            // If the values are overconstrained, calculate margin_right.
            (false, false, false) => {
                margin_right = Length(margin_right.to_px() + underflow, Px);
            }
            // If exactly one value is auto, its used value follows from the equality.
            (false, false, true) => {
                margin_right = Length(underflow, Px);
            }
            (false, true, false) => {
                margin_left = Length(underflow, Px);
            }
            // If width is set to auto, any other auto values become 0.
            (true, _, _) => {
                if margin_left == auto {
                    margin_left = Length(0.0, Px);
                }
                if margin_right == auto {
                    margin_right = Length(0.0, Px);
                }
                width = Length(underflow, Px);
            }
            (false, true, true) => {
                // If margin-left and margin-right are both auto, their used values are equal.
                margin_left = Length(underflow / 2.0, Px);
                margin_right = Length(underflow / 2.0, Px);
            }
        }

        let d = &mut self.dimensions;
        d.width = width.to_px();

        d.padding.left = padding_left.to_px();
        d.padding.right = padding_right.to_px();

        d.border.left = border_left.to_px();
        d.border.right = border_right.to_px();

        d.margin.left = margin_left.to_px();
        d.margin.right = margin_right.to_px();

        d.x = containing_block.x + d.margin.left + d.border.left + d.padding.left;
    }

    /// Lay out the node's children within its content area and return the content height.
    ///
    /// http://www.w3.org/TR/CSS2/visudet.html#normal-block
    fn layout_block_content(&mut self, containing_block: Dimensions) -> f32 {
        // First we need to find the position of the content area...
        let style = self.style_node();
        let d = &mut self.dimensions;

        // margin, border, and padding have initial value 0.
        let zero = Length(0.0, Px);

        // If margin-top or margin-bottom is `auto`, the used value is zero.
        d.margin.top = style.lookup("margin-top", "margin", &zero).to_px();
        d.margin.bottom = style.lookup("margin-bottom", "margin", &zero).to_px();

        d.border.top = style.lookup("border-top-width", "border-width", &zero).to_px();
        d.border.bottom = style.lookup("border-bottom-width", "border-width", &zero).to_px();

        d.padding.top = style.lookup("padding-top", "padding", &zero).to_px();
        d.padding.bottom = style.lookup("padding-bottom", "padding", &zero).to_px();

        d.y = containing_block.y + d.margin.top + d.border.top + d.padding.top;

        // Now we can lay out the children within the content area.
        let mut content_height = 0.0;
        for child in self.children.mut_iter() {
            child.layout(*d);

            // Position each child below the previous one. TODO: margin collapsing
            child.dimensions.y = d.y + content_height;
            content_height = content_height + child.dimensions.margin_box_height();
        }
        return content_height;
    }

    /// Height of a block-level non-replaced element in normal flow with overflow visible.
    fn calculate_block_height(&mut self, content_height: f32) {
        let height = self.style_node().value("height");
        self.dimensions.height = match height {
            Some(Length(h, Px)) => h,
            _ => content_height // In the default (`auto`) case, use the content height.
        };
    }

    /// Add an inline-level child.
    fn push_inline(&mut self, child: LayoutBox<'a>) {
        self.container_for_inline().children.push(child);
    }

    /// Where a new inline child should go.
    fn container_for_inline(&mut self) -> &mut LayoutBox<'a> {
        match self.box_type {
            InlineNode(_) | InlineContainer => self,
            BlockNode(_) => {
                // If we're in the middle of a series of inline nodes, keep using the existing
                // container.  Otherwise, create a new inline container.
                match self.children.last() {
                    Some(&LayoutBox { box_type: InlineContainer,..}) => {}
                    _ => self.children.push(LayoutBox::new(InlineContainer))
                }
                self.children.mut_last().unwrap()
            }
        }
    }
}

impl Dimensions {
    /// Total height of a box including its margins, border, and padding.
    fn margin_box_height(&self) -> f32 {
        self.height + self.padding.top + self.padding.bottom
                    + self.border.top + self.border.bottom
                    + self.margin.top + self.margin.bottom
    }
}
<commit_msg>Rename style_node to get_style_node<commit_after>///! Basic CSS block layout.

use style;
use style::StyledNode;
use css::{Keyword, Length, Px};
use std::default::Default;
use std::iter::AdditiveIterator; // for `sum`

// CSS box model. All sizes are in px.

#[deriving(Default, Show)]
pub struct Dimensions {
    // Position of the content area relative to the document origin:
    pub x: f32,
    pub y: f32,

    // Content area size:
    pub width: f32,
    pub height: f32,

    // Surrounding edges:
    pub padding: EdgeSizes,
    pub border: EdgeSizes,
    pub margin: EdgeSizes,
}

/// A node in the layout tree.
pub struct LayoutBox<'a> {
    pub box_type: BoxType<'a>,
    pub dimensions: Dimensions,
    pub children: Vec<LayoutBox<'a>>,
}

pub enum BoxType<'a> {
    BlockNode(&'a StyledNode<'a>),
    InlineNode(&'a StyledNode<'a>),
    InlineContainer,
}

impl<'a> LayoutBox<'a> {
    fn new(box_type: BoxType) -> LayoutBox {
        LayoutBox {
            box_type: box_type,
            dimensions: Default::default(),
            children: Vec::new(),
        }
    }

    fn get_style_node(&self) -> &'a StyledNode<'a> {
        match self.box_type {
            BlockNode(style_node) => style_node,
            InlineNode(style_node) => style_node,
            InlineContainer => fail!("Inline container has no style node")
        }
    }
}

#[deriving(Default, Show)]
struct EdgeSizes { left: f32, right: f32, top: f32, bottom: f32 }

/// Transform a style tree into a layout tree.
pub fn layout_tree<'a>(node: &'a StyledNode<'a>, containing_block: Dimensions) -> LayoutBox<'a> {
    let mut root_box = build_layout_tree(node);
    root_box.layout(containing_block);
    return root_box;
}

/// Build the tree of LayoutBoxes, but don't perform any layout calculations yet.
fn build_layout_tree<'a>(style_node: &'a StyledNode<'a>) -> LayoutBox<'a> {
    // Create the root box.
    let mut root = LayoutBox::new(match style_node.display() {
        style::Block => BlockNode(style_node),
        style::Inline => InlineNode(style_node),
        style::None => fail!("Root node has display: none.")
    });

    // Create the descendant boxes.
    for child in style_node.children.iter() {
        match child.display() {
            style::Block => root.children.push(build_layout_tree(child)),
            style::Inline => root.push_inline(build_layout_tree(child)),
            style::None => {} // Don't lay out nodes with `display: none;`
        }
    }
    return root;
}

impl<'a> LayoutBox<'a> {
    /// Lay out a box and its descendants.
    fn layout(&mut self, containing_block: Dimensions) {
        match self.box_type {
            BlockNode(_) => self.layout_block(containing_block),
            InlineNode(_) => {} // TODO
            InlineContainer => {} // TODO
        }
    }

    /// Lay out a block-level element and its descendants.
    fn layout_block(&mut self, containing_block: Dimensions) {
        // Child width can depend on parent width, so we need to calculate this node's width before
        // laying out its children.
        self.calculate_block_width(containing_block);

        // Recursively lay out the children of this node within its content area.
        let content_height = self.layout_block_content(containing_block);

        // Parent height can depend on child height, so `calculate_height` must be called after the
        // content layout is finished.
        self.calculate_block_height(content_height);
    }

    /// Calculate the width of a block-level non-replaced element in normal flow.
    ///
    /// http://www.w3.org/TR/CSS2/visudet.html#blockwidth
    fn calculate_block_width(&mut self, containing_block: Dimensions) {
        let style = self.get_style_node();

        // `width` has initial value `auto`.
        let auto = Keyword("auto".to_string());
        let mut width = style.value("width").unwrap_or(auto.clone());

        // margin, border, and padding have initial value 0.
        let zero = Length(0.0, Px);

        let mut margin_left = style.lookup("margin-left", "margin", &zero);
        let mut margin_right = style.lookup("margin-right", "margin", &zero);

        let border_left = style.lookup("border-left-width", "border-width", &zero);
        let border_right = style.lookup("border-right-width", "border-width", &zero);

        let padding_left = style.lookup("padding-left", "padding", &zero);
        let padding_right = style.lookup("padding-right", "padding", &zero);

        let total = [&margin_left, &margin_right, &border_left, &border_right,
                     &padding_left, &padding_right, &width].iter().map(|v| v.to_px()).sum();

        // If width is not auto and the total is wider than the container, treat auto margins as 0.
        if width != auto && total > containing_block.width {
            if margin_left == auto {
                margin_left = Length(0.0, Px);
            }
            if margin_right == auto {
                margin_right = Length(0.0, Px);
            }
        }

        // Adjust used values so that the above sum equals `containing_block.width`.
        // Each arm of the `match` should increase the total width by exactly `underflow`,
        // and afterward all values should be absolute lengths in px.
        let underflow = containing_block.width - total;
        match (width == auto, margin_left == auto, margin_right == auto) {
            // If the values are overconstrained, calculate margin_right.
            (false, false, false) => {
                margin_right = Length(margin_right.to_px() + underflow, Px);
            }
            // If exactly one value is auto, its used value follows from the equality.
            (false, false, true) => {
                margin_right = Length(underflow, Px);
            }
            (false, true, false) => {
                margin_left = Length(underflow, Px);
            }
            // If width is set to auto, any other auto values become 0.
            (true, _, _) => {
                if margin_left == auto {
                    margin_left = Length(0.0, Px);
                }
                if margin_right == auto {
                    margin_right = Length(0.0, Px);
                }
                width = Length(underflow, Px);
            }
            (false, true, true) => {
                // If margin-left and margin-right are both auto, their used values are equal.
                margin_left = Length(underflow / 2.0, Px);
                margin_right = Length(underflow / 2.0, Px);
            }
        }

        let d = &mut self.dimensions;
        d.width = width.to_px();

        d.padding.left = padding_left.to_px();
        d.padding.right = padding_right.to_px();

        d.border.left = border_left.to_px();
        d.border.right = border_right.to_px();

        d.margin.left = margin_left.to_px();
        d.margin.right = margin_right.to_px();

        d.x = containing_block.x + d.margin.left + d.border.left + d.padding.left;
    }

    /// Lay out the node's children within its content area and return the content height.
    ///
    /// http://www.w3.org/TR/CSS2/visudet.html#normal-block
    fn layout_block_content(&mut self, containing_block: Dimensions) -> f32 {
        // First we need to find the position of the content area...
        let style = self.get_style_node();
        let d = &mut self.dimensions;

        // margin, border, and padding have initial value 0.
        let zero = Length(0.0, Px);

        // If margin-top or margin-bottom is `auto`, the used value is zero.
        d.margin.top = style.lookup("margin-top", "margin", &zero).to_px();
        d.margin.bottom = style.lookup("margin-bottom", "margin", &zero).to_px();

        d.border.top = style.lookup("border-top-width", "border-width", &zero).to_px();
        d.border.bottom = style.lookup("border-bottom-width", "border-width", &zero).to_px();

        d.padding.top = style.lookup("padding-top", "padding", &zero).to_px();
        d.padding.bottom = style.lookup("padding-bottom", "padding", &zero).to_px();

        d.y = containing_block.y + d.margin.top + d.border.top + d.padding.top;

        // Now we can lay out the children within the content area.
        let mut content_height = 0.0;
        for child in self.children.mut_iter() {
            child.layout(*d);

            // Position each child below the previous one. TODO: margin collapsing
            child.dimensions.y = d.y + content_height;
            content_height = content_height + child.dimensions.margin_box_height();
        }
        return content_height;
    }

    /// Height of a block-level non-replaced element in normal flow with overflow visible.
    fn calculate_block_height(&mut self, content_height: f32) {
        let height = self.get_style_node().value("height");
        self.dimensions.height = match height {
            Some(Length(h, Px)) => h,
            _ => content_height // In the default (`auto`) case, use the content height.
        };
    }

    /// Add an inline-level child.
    fn push_inline(&mut self, child: LayoutBox<'a>) {
        self.container_for_inline().children.push(child);
    }

    /// Where a new inline child should go.
    fn container_for_inline(&mut self) -> &mut LayoutBox<'a> {
        match self.box_type {
            InlineNode(_) | InlineContainer => self,
            BlockNode(_) => {
                // If we're in the middle of a series of inline nodes, keep using the existing
                // container.  Otherwise, create a new inline container.
                match self.children.last() {
                    Some(&LayoutBox { box_type: InlineContainer,..}) => {}
                    _ => self.children.push(LayoutBox::new(InlineContainer))
                }
                self.children.mut_last().unwrap()
            }
        }
    }
}

impl Dimensions {
    /// Total height of a box including its margins, border, and padding.
    fn margin_box_height(&self) -> f32 {
        self.height + self.padding.top + self.padding.bottom
                    + self.border.top + self.border.bottom
                    + self.margin.top + self.margin.bottom
    }
}
<|endoftext|>