<commit_before>use Result;
use point::Error;
use std::fmt;

const TIME_FORMATS: &'static [u8] = &[1, 3, 4, 5, 6, 7, 8, 9, 10];
const COLOR_FORMATS: &'static [u8] = &[2, 3, 5, 7, 8, 10];
const WAVEFORM_FORMATS: &'static [u8] = &[4, 5, 9, 10];
const NIR_FORMATS: &'static [u8] = &[8, 10];

/// Point formats are defined by the las spec.
///
/// As of las 1.4, there are eleven point formats (0-10). A new `Format` can be created from its
/// code and converted back into it:
///
/// ```
/// use las::point::Format;
///
/// let format_1 = Format::new(1).unwrap();
/// assert!(format_1.has_gps_time);
/// assert_eq!(1, format_1.to_u8().unwrap());
///
/// assert!(Format::new(11).is_err());
/// ```
///
/// Point formats can have extra bytes, which are user-defined attributes. Extra bytes were
/// introduced in las 1.4.
///
/// ```
/// use las::point::Format;
/// let mut format = Format::new(0).unwrap();
/// format.extra_bytes = 1;
/// assert_eq!(21, format.len());
/// ```
///
/// Certain combinations of attributes in a point format are illegal, e.g. gps time is required for
/// all formats >= 6:
///
/// ```
/// use las::point::Format;
/// let mut format = Format::new(6).unwrap();
/// format.has_gps_time = false;
/// assert!(format.to_u8().is_err());
/// ```
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Format {
    /// Does this point format include gps time?
    pub has_gps_time: bool,
    /// Does this point format include red, green, and blue colors?
    pub has_color: bool,
    /// Does this point format use two bytes for its flags and scaled scan angles?
    pub is_extended: bool,
    /// Does this point format have waveforms?
    pub has_waveform: bool,
    /// Does this point format have near infrared data?
    pub has_nir: bool,
    /// The number of extra bytes on each point.
    pub extra_bytes: u16,
}

impl Format {
    /// Creates a new point format from a u8.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::point::Format;
    /// let format = Format::new(0).unwrap();
    /// assert!(!format.has_gps_time);
    /// assert!(!format.has_color);
    ///
    /// let format = Format::new(3).unwrap();
    /// assert!(format.has_gps_time);
    /// assert!(format.has_color);
    ///
    /// assert!(Format::new(11).is_err());
    /// ```
    pub fn new(n: u8) -> Result<Format> {
        if n > 10 {
            Err(Error::FormatNumber(n).into())
        } else {
            Ok(Format {
                has_gps_time: TIME_FORMATS.contains(&n),
                has_color: COLOR_FORMATS.contains(&n),
                has_waveform: WAVEFORM_FORMATS.contains(&n),
                has_nir: NIR_FORMATS.contains(&n),
                is_extended: n >= 6,
                ..Default::default()
            })
        }
    }

    /// Converts this point format into an extended format.
    ///
    /// "Extended" formats can contain more information per point, and must have gps time.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::point::Format;
    /// let mut format = Format::default();
    /// assert!(!format.has_gps_time);
    /// assert!(!format.is_extended);
    /// format.extend();
    /// assert!(format.has_gps_time);
    /// assert!(format.is_extended);
    pub fn extend(&mut self) {
        self.has_gps_time = true;
        self.is_extended = true;
    }

    /// Returns this point format's length.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::point::Format;
    /// let mut format = Format::new(0).unwrap();
    /// assert_eq!(20, format.len());
    /// format.has_gps_time = true;
    /// assert_eq!(28, format.len());
    /// ```
    pub fn len(&self) -> u16 {
        let mut len = if self.is_extended { 22 } else { 20 } + self.extra_bytes;
        if self.has_gps_time {
            len += 8;
        }
        if self.has_color {
            len += 6;
        }
        if self.has_nir {
            len += 2;
        }
        if self.has_waveform {
            len += 29;
        }
        len
    }

    /// Converts this point format to a u8.
    ///
    /// Can return an error if there is an invalid combination of attributes.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::point::Format;
    /// let mut format = Format::default();
    /// assert_eq!(0, format.to_u8().unwrap());
    /// format.is_extended = true;
    /// assert!(format.to_u8().is_err());
    /// format.has_gps_time = true;
    /// assert_eq!(6, format.to_u8().unwrap());
    /// ```
    pub fn to_u8(&self) -> Result<u8> {
        if self.is_extended {
            if self.has_gps_time {
                if self.has_color {
                    if self.has_nir {
                        if self.has_waveform { Ok(10) } else { Ok(8) }
                    } else {
                        if self.has_waveform {
                            Err(Error::Format(*self).into())
                        } else {
                            Ok(7)
                        }
                    }
                } else {
                    if self.has_nir {
                        Err(Error::Format(*self).into())
                    } else {
                        if self.has_waveform { Ok(9) } else { Ok(6) }
                    }
                }
            } else {
                Err(Error::Format(*self).into())
            }
        } else if self.has_nir {
            Err(Error::Format(*self).into())
        } else {
            if self.has_waveform {
                if self.has_gps_time {
                    if self.has_color { Ok(5) } else { Ok(4) }
                } else {
                    Err(Error::Format(*self).into())
                }
            } else {
                let mut n = if self.has_gps_time { 1 } else { 0 };
                if self.has_color {
                    n += 2;
                }
                Ok(n)
            }
        }
    }
}

impl fmt::Display for Format {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Ok(n) = self.to_u8() {
            write!(f, "point format {}", n)
        } else {
            write!(f, "point format that does not map onto a code: {:?}", self)
        }
    }
}

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

    macro_rules! format {
        ($name:ident, $n:expr, $expected:expr, $len:expr) => {
            mod $name {
                use point::Format;

                #[test]
                fn new() {
                    assert_eq!($expected, Format::new($n).unwrap());
                }

                #[test]
                fn len() {
                    assert_eq!($len, Format::new($n).unwrap().len());
                }

                #[test]
                fn to_u8() {
                    assert_eq!($n, Format::new($n).unwrap().to_u8().unwrap());
                }
            }
        }
    }

    format!(format_0, 0, Format::default(), 20);
    format!(
        format_1,
        1,
        Format {
            has_gps_time: true,
            ..Default::default()
        },
        28
    );
    format!(
        format_2,
        2,
        Format {
            has_color: true,
            ..Default::default()
        },
        26
    );
    format!(
        format_3,
        3,
        Format {
            has_gps_time: true,
            has_color: true,
            ..Default::default()
        },
        34
    );
    format!(
        format_4,
        4,
        Format {
            has_gps_time: true,
            has_waveform: true,
            ..Default::default()
        },
        57
    );
    format!(
        format_5,
        5,
        Format {
            has_gps_time: true,
            has_color: true,
            has_waveform: true,
            ..Default::default()
        },
        63
    );
    format!(
        format_6,
        6,
        Format {
            has_gps_time: true,
            is_extended: true,
            ..Default::default()
        },
        30
    );
    format!(
        format_7,
        7,
        Format {
            has_gps_time: true,
            has_color: true,
            is_extended: true,
            ..Default::default()
        },
        36
    );
    format!(
        format_8,
        8,
        Format {
            has_gps_time: true,
            has_color: true,
            has_nir: true,
            is_extended: true,
            ..Default::default()
        },
        38
    );
    format!(
        format_9,
        9,
        Format {
            has_gps_time: true,
            has_waveform: true,
            is_extended: true,
            ..Default::default()
        },
        59
    );
    format!(
        format_10,
        10,
        Format {
            has_gps_time: true,
            has_color: true,
            has_nir: true,
            has_waveform: true,
            is_extended: true,
            ..Default::default()
        },
        67
    );

    #[test]
    fn waveform_without_gps_time() {
        let format = Format {
            has_waveform: true,
            ..Default::default()
        };
        assert!(format.to_u8().is_err());
    }

    #[test]
    fn extended_without_gps_time() {
        let format = Format {
            is_extended: true,
            ..Default::default()
        };
        assert!(format.to_u8().is_err());
    }

    #[test]
    fn nir_without_extended() {
        let format = Format {
            has_nir: true,
            ..Default::default()
        };
        assert!(format.to_u8().is_err());
    }

    #[test]
    fn nir_without_color() {
        let format = Format {
            is_extended: true,
            has_nir: true,
            ..Default::default()
        };
        assert!(format.to_u8().is_err());
    }

    #[test]
    fn extra_bytes() {
        let format = Format {
            extra_bytes: 1,
            ..Default::default()
        };
        assert_eq!(21, format.len());
    }
}
<commit_msg>Ignore len_without_is_empty for point::Format<commit_after>use Result;
use point::Error;
use std::fmt;

const TIME_FORMATS: &'static [u8] = &[1, 3, 4, 5, 6, 7, 8, 9, 10];
const COLOR_FORMATS: &'static [u8] = &[2, 3, 5, 7, 8, 10];
const WAVEFORM_FORMATS: &'static [u8] = &[4, 5, 9, 10];
const NIR_FORMATS: &'static [u8] = &[8, 10];

/// Point formats are defined by the las spec.
///
/// As of las 1.4, there are eleven point formats (0-10). A new `Format` can be created from its
/// code and converted back into it:
///
/// ```
/// use las::point::Format;
///
/// let format_1 = Format::new(1).unwrap();
/// assert!(format_1.has_gps_time);
/// assert_eq!(1, format_1.to_u8().unwrap());
///
/// assert!(Format::new(11).is_err());
/// ```
///
/// Point formats can have extra bytes, which are user-defined attributes. Extra bytes were
/// introduced in las 1.4.
///
/// ```
/// use las::point::Format;
/// let mut format = Format::new(0).unwrap();
/// format.extra_bytes = 1;
/// assert_eq!(21, format.len());
/// ```
///
/// Certain combinations of attributes in a point format are illegal, e.g. gps time is required for
/// all formats >= 6:
///
/// ```
/// use las::point::Format;
/// let mut format = Format::new(6).unwrap();
/// format.has_gps_time = false;
/// assert!(format.to_u8().is_err());
/// ```
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Format {
    /// Does this point format include gps time?
    pub has_gps_time: bool,
    /// Does this point format include red, green, and blue colors?
    pub has_color: bool,
    /// Does this point format use two bytes for its flags and scaled scan angles?
    pub is_extended: bool,
    /// Does this point format have waveforms?
    pub has_waveform: bool,
    /// Does this point format have near infrared data?
    pub has_nir: bool,
    /// The number of extra bytes on each point.
    pub extra_bytes: u16,
}

#[cfg_attr(feature = "cargo-clippy", allow(len_without_is_empty))]
impl Format {
    /// Creates a new point format from a u8.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::point::Format;
    /// let format = Format::new(0).unwrap();
    /// assert!(!format.has_gps_time);
    /// assert!(!format.has_color);
    ///
    /// let format = Format::new(3).unwrap();
    /// assert!(format.has_gps_time);
    /// assert!(format.has_color);
    ///
    /// assert!(Format::new(11).is_err());
    /// ```
    pub fn new(n: u8) -> Result<Format> {
        if n > 10 {
            Err(Error::FormatNumber(n).into())
        } else {
            Ok(Format {
                has_gps_time: TIME_FORMATS.contains(&n),
                has_color: COLOR_FORMATS.contains(&n),
                has_waveform: WAVEFORM_FORMATS.contains(&n),
                has_nir: NIR_FORMATS.contains(&n),
                is_extended: n >= 6,
                ..Default::default()
            })
        }
    }

    /// Converts this point format into an extended format.
    ///
    /// "Extended" formats can contain more information per point, and must have gps time.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::point::Format;
    /// let mut format = Format::default();
    /// assert!(!format.has_gps_time);
    /// assert!(!format.is_extended);
    /// format.extend();
    /// assert!(format.has_gps_time);
    /// assert!(format.is_extended);
    pub fn extend(&mut self) {
        self.has_gps_time = true;
        self.is_extended = true;
    }

    /// Returns this point format's length.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::point::Format;
    /// let mut format = Format::new(0).unwrap();
    /// assert_eq!(20, format.len());
    /// format.has_gps_time = true;
    /// assert_eq!(28, format.len());
    /// ```
    pub fn len(&self) -> u16 {
        let mut len = if self.is_extended { 22 } else { 20 } + self.extra_bytes;
        if self.has_gps_time {
            len += 8;
        }
        if self.has_color {
            len += 6;
        }
        if self.has_nir {
            len += 2;
        }
        if self.has_waveform {
            len += 29;
        }
        len
    }

    /// Converts this point format to a u8.
    ///
    /// Can return an error if there is an invalid combination of attributes.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::point::Format;
    /// let mut format = Format::default();
    /// assert_eq!(0, format.to_u8().unwrap());
    /// format.is_extended = true;
    /// assert!(format.to_u8().is_err());
    /// format.has_gps_time = true;
    /// assert_eq!(6, format.to_u8().unwrap());
    /// ```
    pub fn to_u8(&self) -> Result<u8> {
        if self.is_extended {
            if self.has_gps_time {
                if self.has_color {
                    if self.has_nir {
                        if self.has_waveform { Ok(10) } else { Ok(8) }
                    } else {
                        if self.has_waveform {
                            Err(Error::Format(*self).into())
                        } else {
                            Ok(7)
                        }
                    }
                } else {
                    if self.has_nir {
                        Err(Error::Format(*self).into())
                    } else {
                        if self.has_waveform { Ok(9) } else { Ok(6) }
                    }
                }
            } else {
                Err(Error::Format(*self).into())
            }
        } else if self.has_nir {
            Err(Error::Format(*self).into())
        } else {
            if self.has_waveform {
                if self.has_gps_time {
                    if self.has_color { Ok(5) } else { Ok(4) }
                } else {
                    Err(Error::Format(*self).into())
                }
            } else {
                let mut n = if self.has_gps_time { 1 } else { 0 };
                if self.has_color {
                    n += 2;
                }
                Ok(n)
            }
        }
    }
}

impl fmt::Display for Format {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Ok(n) = self.to_u8() {
            write!(f, "point format {}", n)
        } else {
            write!(f, "point format that does not map onto a code: {:?}", self)
        }
    }
}

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

    macro_rules! format {
        ($name:ident, $n:expr, $expected:expr, $len:expr) => {
            mod $name {
                use point::Format;

                #[test]
                fn new() {
                    assert_eq!($expected, Format::new($n).unwrap());
                }

                #[test]
                fn len() {
                    assert_eq!($len, Format::new($n).unwrap().len());
                }

                #[test]
                fn to_u8() {
                    assert_eq!($n, Format::new($n).unwrap().to_u8().unwrap());
                }
            }
        }
    }

    format!(format_0, 0, Format::default(), 20);
    format!(
        format_1,
        1,
        Format {
            has_gps_time: true,
            ..Default::default()
        },
        28
    );
    format!(
        format_2,
        2,
        Format {
            has_color: true,
            ..Default::default()
        },
        26
    );
    format!(
        format_3,
        3,
        Format {
            has_gps_time: true,
            has_color: true,
            ..Default::default()
        },
        34
    );
    format!(
        format_4,
        4,
        Format {
            has_gps_time: true,
            has_waveform: true,
            ..Default::default()
        },
        57
    );
    format!(
        format_5,
        5,
        Format {
            has_gps_time: true,
            has_color: true,
            has_waveform: true,
            ..Default::default()
        },
        63
    );
    format!(
        format_6,
        6,
        Format {
            has_gps_time: true,
            is_extended: true,
            ..Default::default()
        },
        30
    );
    format!(
        format_7,
        7,
        Format {
            has_gps_time: true,
            has_color: true,
            is_extended: true,
            ..Default::default()
        },
        36
    );
    format!(
        format_8,
        8,
        Format {
            has_gps_time: true,
            has_color: true,
            has_nir: true,
            is_extended: true,
            ..Default::default()
        },
        38
    );
    format!(
        format_9,
        9,
        Format {
            has_gps_time: true,
            has_waveform: true,
            is_extended: true,
            ..Default::default()
        },
        59
    );
    format!(
        format_10,
        10,
        Format {
            has_gps_time: true,
            has_color: true,
            has_nir: true,
            has_waveform: true,
            is_extended: true,
            ..Default::default()
        },
        67
    );

    #[test]
    fn waveform_without_gps_time() {
        let format = Format {
            has_waveform: true,
            ..Default::default()
        };
        assert!(format.to_u8().is_err());
    }

    #[test]
    fn extended_without_gps_time() {
        let format = Format {
            is_extended: true,
            ..Default::default()
        };
        assert!(format.to_u8().is_err());
    }

    #[test]
    fn nir_without_extended() {
        let format = Format {
            has_nir: true,
            ..Default::default()
        };
        assert!(format.to_u8().is_err());
    }

    #[test]
    fn nir_without_color() {
        let format = Format {
            is_extended: true,
            has_nir: true,
            ..Default::default()
        };
        assert!(format.to_u8().is_err());
    }

    #[test]
    fn extra_bytes() {
        let format = Format {
            extra_bytes: 1,
            ..Default::default()
        };
        assert_eq!(21, format.len());
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
#![allow(unused_variables)]

pub mod board_geometry;
pub mod castling_rights;
pub mod chess_move;
pub mod board;

// use basetypes::*;
// use notation;
use self::board::{Board, IllegalBoard};

pub struct Position {
    board: Board,
    halfmove_clock: u32,
    fullmove_number: u32, /* move_stack
                           * move_history (including fullmove_number?)
                           * ply
                           * hply?
                           * various hash tables
                           * first_move_index[usize; MAX_PLY]
                           * undo_move data stack */
}

impl Position {
    pub fn from_fen(fen: &str) -> Result<Position, IllegalBoard> {
        let parts: Vec<_> = fen.split_whitespace().collect();

        if parts.len() == 6 {
            let p = Position {
                board: try!(Board::from_fen(fen)),
                halfmove_clock: try!(parts[4].parse::<u32>().map_err(|e| IllegalBoard)),
                fullmove_number: try!(parts[5].parse::<u32>().map_err(|e| IllegalBoard)),
            };
            Ok(p)
        } else {
            Err(IllegalBoard)
        }
    }
}

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

    #[test]
    fn test_fen_parsing() {
        assert!(Position::from_fen("nbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr1/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBN b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR/ b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNRR b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPP01PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPP91PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPP*1PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 * 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 *")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b - e3 0 1")
                    .is_ok());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_ok());
        assert!(Position::from_fen("8/8/8/8/8/8/8/8 w - - 0 1").is_err());
        assert!(Position::from_fen("8/8/8/8/8/8/8/7K w - - 0 1").is_err());
        assert!(Position::from_fen("k7/8/8/8/8/8/8/7K w - - 0 1").is_ok());
        assert!(Position::from_fen("k7/8/8/8/8/8/8/6KK w - - 0 1").is_err());
        assert!(Position::from_fen("k7/pppppppp/p7/8/8/8/8/7K w - - 0 1").is_err());
        assert!(Position::from_fen("k7/8/8/8/8/7P/PPPPPPPP/7K w - - 0 1").is_err());
        assert!(Position::from_fen("k7/pppppppp/8/8/8/8/PPPPPPPP/7K w - - 0 1").is_ok());
        assert!(Position::from_fen("k7/1P6/8/8/8/8/8/7K w - - 0 1").is_err());
        assert!(Position::from_fen("k7/1B6/8/8/8/8/8/7K w - - 0 1").is_err());
        assert!(Position::from_fen("k7/1N6/8/8/8/8/8/7K w - - 0 1").is_ok());
        assert!(Position::from_fen("k3P3/8/8/8/8/8/8/7K w - - 0 1").is_err());
        assert!(Position::from_fen("k3p3/8/8/8/8/8/8/7K w - - 0 1").is_err());
        assert!(Position::from_fen("k7/8/8/8/8/8/8/pP5K w - - 0 1").is_err());
        assert!(Position::from_fen("r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1").is_ok());
        assert!(Position::from_fen("r3k2r/8/8/8/8/8/8/R3K2B w KQkq - 0 1").is_err());
        assert!(Position::from_fen("r3k2r/8/8/8/8/8/8/R3K3 w KQkq - 0 1").is_err());
        assert!(Position::from_fen("r3k2r/8/8/8/8/8/8/R3K3 w KQkq - 0 1").is_err());
        assert!(Position::from_fen("r3k2r/8/8/8/8/8/8/R3K3 w Qkq - 0 1").is_ok());
        assert!(Position::from_fen("r2k3r/8/8/8/8/8/8/R3K3 w Qkq - 0 1").is_err());
        assert!(Position::from_fen("r2k3r/8/8/8/8/8/8/R3K3 w Qk - 0 1").is_err());
        assert!(Position::from_fen("r2k3r/8/8/8/8/8/8/R3K3 w Q - 0 1").is_ok());
        assert!(Position::from_fen("k7/8/8/8/7P/8/8/7K w - h3 0 1").is_err());
        assert!(Position::from_fen("k7/8/8/8/7P/8/8/7K b - h3 0 1").is_ok());
        assert!(Position::from_fen("k7/8/8/7P/8/8/8/7K b - h4 0 1").is_err());
        assert!(Position::from_fen("k7/8/8/8/7P/7P/8/7K b - h3 0 1").is_err());
        assert!(Position::from_fen("k7/8/8/8/7P/8/7P/7K b - h3 0 1").is_err());
        assert!(Position::from_fen("k7/8/8/8/6P1/7P/8/7K b - h3 0 1").is_err());
        assert!(Position::from_fen("8/8/8/6k1/7P/8/8/7K b - h3 0 1").is_ok());
        assert!(Position::from_fen("8/8/8/6k1/7P/8/8/6RK b - h3 0 1").is_err());
        assert!(Position::from_fen("8/8/8/6k1/3P4/8/8/2B4K b - d3 0 1").is_ok());
        assert!(Position::from_fen("8/8/8/6k1/7P/4B3/8/7K b - h3 0 1").is_err());
    }
}
<commit_msg>more docs<commit_after>//! This module "knows" how to play chess. It is aware of chess rules,
//! strategy, and tactics.

#![allow(dead_code)]
#![allow(unused_variables)]

pub mod board_geometry;
pub mod castling_rights;
pub mod chess_move;
pub mod board;

// use basetypes::*;
// use notation;
use self::board::{Board, IllegalBoard};

pub struct Position {
    board: Board,
    halfmove_clock: u32,
    fullmove_number: u32, /* move_stack
                           * move_history (including fullmove_number?)
                           * ply
                           * hply?
                           * various hash tables
                           * first_move_index[usize; MAX_PLY]
                           * undo_move data stack */
}

impl Position {
    pub fn from_fen(fen: &str) -> Result<Position, IllegalBoard> {
        let parts: Vec<_> = fen.split_whitespace().collect();

        if parts.len() == 6 {
            let p = Position {
                board: try!(Board::from_fen(fen)),
                halfmove_clock: try!(parts[4].parse::<u32>().map_err(|_| IllegalBoard)),
                fullmove_number: try!(parts[5].parse::<u32>().map_err(|_| IllegalBoard)),
            };
            Ok(p)
        } else {
            Err(IllegalBoard)
        }
    }
}

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

    #[test]
    fn test_fen_parsing() {
        assert!(Position::from_fen("nbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr1/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBN b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR/ b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNRR b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPP01PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPP91PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPP*1PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 * 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 *")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b - e3 0 1")
                    .is_ok());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_ok());
        assert!(Position::from_fen("8/8/8/8/8/8/8/8 w - - 0 1").is_err());
        assert!(Position::from_fen("8/8/8/8/8/8/8/7K w - - 0 1").is_err());
        assert!(Position::from_fen("k7/8/8/8/8/8/8/7K w - - 0 1").is_ok());
        assert!(Position::from_fen("k7/8/8/8/8/8/8/6KK w - - 0 1").is_err());
        assert!(Position::from_fen("k7/pppppppp/p7/8/8/8/8/7K w - - 0 1").is_err());
        assert!(Position::from_fen("k7/8/8/8/8/7P/PPPPPPPP/7K w - - 0 1").is_err());
        assert!(Position::from_fen("k7/pppppppp/8/8/8/8/PPPPPPPP/7K w - - 0 1").is_ok());
        assert!(Position::from_fen("k7/1P6/8/8/8/8/8/7K w - - 0 1").is_err());
        assert!(Position::from_fen("k7/1B6/8/8/8/8/8/7K w - - 0 1").is_err());
        assert!(Position::from_fen("k7/1N6/8/8/8/8/8/7K w - - 0 1").is_ok());
        assert!(Position::from_fen("k3P3/8/8/8/8/8/8/7K w - - 0 1").is_err());
        assert!(Position::from_fen("k3p3/8/8/8/8/8/8/7K w - - 0 1").is_err());
        assert!(Position::from_fen("k7/8/8/8/8/8/8/pP5K w - - 0 1").is_err());
        assert!(Position::from_fen("r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1").is_ok());
        assert!(Position::from_fen("r3k2r/8/8/8/8/8/8/R3K2B w KQkq - 0 1").is_err());
        assert!(Position::from_fen("r3k2r/8/8/8/8/8/8/R3K3 w KQkq - 0 1").is_err());
        assert!(Position::from_fen("r3k2r/8/8/8/8/8/8/R3K3 w KQkq - 0 1").is_err());
        assert!(Position::from_fen("r3k2r/8/8/8/8/8/8/R3K3 w Qkq - 0 1").is_ok());
        assert!(Position::from_fen("r2k3r/8/8/8/8/8/8/R3K3 w Qkq - 0 1").is_err());
        assert!(Position::from_fen("r2k3r/8/8/8/8/8/8/R3K3 w Qk - 0 1").is_err());
        assert!(Position::from_fen("r2k3r/8/8/8/8/8/8/R3K3 w Q - 0 1").is_ok());
        assert!(Position::from_fen("k7/8/8/8/7P/8/8/7K w - h3 0 1").is_err());
        assert!(Position::from_fen("k7/8/8/8/7P/8/8/7K b - h3 0 1").is_ok());
        assert!(Position::from_fen("k7/8/8/7P/8/8/8/7K b - h4 0 1").is_err());
        assert!(Position::from_fen("k7/8/8/8/7P/7P/8/7K b - h3 0 1").is_err());
        assert!(Position::from_fen("k7/8/8/8/7P/8/7P/7K b - h3 0 1").is_err());
        assert!(Position::from_fen("k7/8/8/8/6P1/7P/8/7K b - h3 0 1").is_err());
        assert!(Position::from_fen("8/8/8/6k1/7P/8/8/7K b - h3 0 1").is_ok());
        assert!(Position::from_fen("8/8/8/6k1/7P/8/8/6RK b - h3 0 1").is_err());
        assert!(Position::from_fen("8/8/8/6k1/3P4/8/8/2B4K b - d3 0 1").is_ok());
        assert!(Position::from_fen("8/8/8/6k1/7P/4B3/8/7K b - h3 0 1").is_err());
    }
}
<|endoftext|>


<commit_before>use tracing::Level;
use tracing_subscriber::{filter, prelude::*, EnvFilter};

/// Initializes the `tracing` logging framework.
///
/// Regular CLI output is influenced by the
/// [`RUST_LOG`](tracing_subscriber::filter::EnvFilter) environment variable.
///
/// This function also sets up the Sentry error reporting integration for the
/// `tracing` framework, which is hardcoded to include all `INFO` level events.
pub fn init() {
    let log_filter = EnvFilter::from_default_env();

    let sentry_filter = filter::Targets::new().with_default(Level::INFO);

    tracing_subscriber::registry()
        .with(tracing_logfmt::layer().with_filter(log_filter))
        .with(sentry::integrations::tracing::layer().with_filter(sentry_filter))
        .init();
}
<commit_msg>tracing: Simplify `sentry_filter` variable<commit_after>use tracing_subscriber::filter::LevelFilter;
use tracing_subscriber::{prelude::*, EnvFilter};

/// Initializes the `tracing` logging framework.
///
/// Regular CLI output is influenced by the
/// [`RUST_LOG`](tracing_subscriber::filter::EnvFilter) environment variable.
///
/// This function also sets up the Sentry error reporting integration for the
/// `tracing` framework, which is hardcoded to include all `INFO` level events.
pub fn init() {
    let log_filter = EnvFilter::from_default_env();

    let sentry_filter = LevelFilter::INFO;

    tracing_subscriber::registry()
        .with(tracing_logfmt::layer().with_filter(log_filter))
        .with(sentry::integrations::tracing::layer().with_filter(sentry_filter))
        .init();
}
<|endoftext|>


<commit_before>use std::collections::hashmap::HashMap;
use request::Request;
use middleware::{Continue, Middleware, MiddlewareResult};
use request;
use response;
use urlencoded;
use http::server::request::{RequestUri, Star, AbsoluteUri, AbsolutePath, Authority};
use url::UrlParser;

type QueryStore = HashMap<String, Vec<String>>;

#[deriving(Clone)]
pub struct QueryStringParser;

impl QueryStringParser {
    fn parse(origin: &RequestUri) -> QueryStore {
        match *origin {
            AbsoluteUri(ref url) => {
                for query in url.query.iter() {
                    return urlencoded::parse(query.as_slice())
                }
            },
            AbsolutePath(ref s) => {
                match UrlParser::new().parse_path(s.as_slice()) {
                    Ok((_, Some(query), _)) => {
                        return urlencoded::parse(query.as_slice())
                    }
                    Ok(..) => {}
                    // FIXME: If this fails to parse, then it really shouldn't
                    // have reached here.
                    Err(..) => {}
                }
            },
            Star | Authority(..) => {}
        }

        HashMap::new()
    }
}

impl Middleware for QueryStringParser {
    fn invoke(&self, req: &mut request::Request, _: &mut response::Response)
                -> MiddlewareResult {
        let parsed = QueryStringParser::parse(&req.origin.request_uri);
        req.map.insert(parsed);
        Ok(Continue)
    }
}

pub trait QueryString {
    fn query(&self, key: &str, default: &str) -> Vec<String>;
}

impl<'a, 'b> QueryString for request::Request<'a, 'b> {
    fn query(&self, key: &str, default: &str) -> Vec<String> {
        self.map.find::<QueryStore>().and_then(| store | {
            match store.find_copy(&key.to_string()) {
                Some(result) => Some(result),
                _ => Some(vec![default.to_string().clone()])
            }
        }).unwrap()
    }
}

#[test]
fn splits_and_parses_an_url() {
    use url::Url;
    let t = |url|{
        let store = QueryStringParser::parse(&url);
        assert_eq!(store["foo".to_string()], vec!["bar".to_string()]);
        assert_eq!(store["message".to_string()],
                        vec!["hello".to_string(), "world".to_string()]);
    };

    let raw = "http://www.foo.bar/query/test?foo=bar&message=hello&message=world";
    t(AbsoluteUri(Url::parse(raw).unwrap()));

    t(AbsolutePath("/query/test?foo=bar&message=hello&message=world".to_string()));

    assert_eq!(QueryStringParser::parse(&Star), HashMap::new());

    let store = QueryStringParser::parse(&Authority("host.com".to_string()));
    assert_eq!(store, HashMap::new());
}
<commit_msg>fix(query_string): improve error message for missing querystore<commit_after>use std::collections::hashmap::HashMap;
use request::Request;
use middleware::{Continue, Middleware, MiddlewareResult};
use request;
use response;
use urlencoded;
use http::server::request::{RequestUri, Star, AbsoluteUri, AbsolutePath, Authority};
use url::UrlParser;

type QueryStore = HashMap<String, Vec<String>>;

#[deriving(Clone)]
pub struct QueryStringParser;

impl QueryStringParser {
    fn parse(origin: &RequestUri) -> QueryStore {
        match *origin {
            AbsoluteUri(ref url) => {
                for query in url.query.iter() {
                    return urlencoded::parse(query.as_slice())
                }
            },
            AbsolutePath(ref s) => {
                match UrlParser::new().parse_path(s.as_slice()) {
                    Ok((_, Some(query), _)) => {
                        return urlencoded::parse(query.as_slice())
                    }
                    Ok(..) => {}
                    // FIXME: If this fails to parse, then it really shouldn't
                    // have reached here.
                    Err(..) => {}
                }
            },
            Star | Authority(..) => {}
        }

        HashMap::new()
    }
}

impl Middleware for QueryStringParser {
    fn invoke(&self, req: &mut request::Request, _: &mut response::Response)
                -> MiddlewareResult {
        let parsed = QueryStringParser::parse(&req.origin.request_uri);
        req.map.insert(parsed);
        Ok(Continue)
    }
}

pub trait QueryString {
    fn query(&self, key: &str, default: &str) -> Vec<String>;
}

impl<'a, 'b> QueryString for request::Request<'a, 'b> {
    fn query(&self, key: &str, default: &str) -> Vec<String> {
        self.map.find::<QueryStore>().and_then(| store | {
            match store.find_copy(&key.to_string()) {
                Some(result) => Some(result),
                _ => Some(vec![default.to_string().clone()])
            }
        }).expect("QueryStore not available. Ensure the middleware \
                  is added before the route that depends on it.")
    }
}

#[test]
fn splits_and_parses_an_url() {
    use url::Url;
    let t = |url|{
        let store = QueryStringParser::parse(&url);
        assert_eq!(store["foo".to_string()], vec!["bar".to_string()]);
        assert_eq!(store["message".to_string()],
                        vec!["hello".to_string(), "world".to_string()]);
    };

    let raw = "http://www.foo.bar/query/test?foo=bar&message=hello&message=world";
    t(AbsoluteUri(Url::parse(raw).unwrap()));

    t(AbsolutePath("/query/test?foo=bar&message=hello&message=world".to_string()));

    assert_eq!(QueryStringParser::parse(&Star), HashMap::new());

    let store = QueryStringParser::parse(&Authority("host.com".to_string()));
    assert_eq!(store, HashMap::new());
}
<|endoftext|>


<commit_before>use orbclient::{Renderer, Color};
use orbimage;
use std::cell::{ Cell, RefCell };
use std::sync::Arc;

use cell::CheckSet;
use event::Event;
use point::Point;
use rect::Rect;
use theme::{ ITEM_BACKGROUND, WINDOW_BACKGROUND, ITEM_SELECTION };
use traits::{ Click, Place };
use widgets::Widget;
use std::ops::Index;

/// An entry in a list
/// Each entry stores widgets within.
pub struct Entry {
    pub height: Cell<u32>,
    click_callback: RefCell<Option<Arc<Fn(&Entry, Point)>>>,
    widgets: RefCell<Vec<Arc<Widget>>>,
    pub highlight: Cell<Color>,
    highlighted: Cell<bool>,
}

impl Entry {
    pub fn new(h: u32) -> Arc<Self> {
        Arc::new(Entry {
            height: Cell::new(h),
            click_callback: RefCell::new(None),
            widgets: RefCell::new(vec![]),
            highlight: Cell::new(ITEM_SELECTION),
            highlighted: Cell::new(false),
        })
    }

    /// Adds a widget to the entry
    pub fn add<T: Widget>(&self, widget: &Arc<T>) {
        let mut widgets = self.widgets.borrow_mut();
        widgets.push(widget.clone());
    }

    fn widgets(&self) -> &RefCell<Vec<Arc<Widget>>> {
        &self.widgets
    }
}

impl Click for Entry {
    fn emit_click(&self, point: Point) {
        if let Some(ref click_callback) = *self.click_callback.borrow() {
            click_callback(self, point);
        }
    }

    fn on_click<T: Fn(&Self, Point) + 'static>(&self, func: T) -> &Self {
        *self.click_callback.borrow_mut() = Some(Arc::new(func));
        self
    }
}

pub struct List {
    pub rect: Cell<Rect>,
    v_scroll: Cell<i32>,
    current_height: Cell<u32>,
    entries: RefCell<Vec<Arc<Entry>>>,
    pressed: Cell<bool>,
    selected: Cell<Option<u32>>,
}

impl List {
    pub fn new() -> Arc<Self> {
        Arc::new(List {
            rect: Cell::new(Rect::default()),
            v_scroll: Cell::new(0),
            current_height: Cell::new(0),
            entries: RefCell::new(vec![]),
            pressed: Cell::new(false),
            selected: Cell::new(None),
        })
    }

    pub fn push(&self, entry: &Arc<Entry>) {
        let h = entry.height.get();
        self.entries.borrow_mut().push(entry.clone());
        self.current_height.set(self.current_height.get() + h);
    }

    // Given absolute coordinates, returns the list entry index
    // drawn at that point.
    fn get_entry_index(&self, p: Point) -> Option<u32> {
        if self.rect.get().contains(p) {
            let mut current_y = 0;
            let x = self.rect.get().x;
            let y = self.rect.get().y;
            let width = self.rect.get().width;
            let scroll = self.v_scroll.get();

            for (i, entry) in self.entries.borrow().iter().enumerate() {
                if Rect::new(x, y+current_y-scroll, width, entry.height.get()).contains(p) {
                    return Some(i as u32)
                }
                current_y += entry.height.get() as i32
            }
        }

        None
    }

    pub fn scroll(&self, y: i32) {
        let mut set_to = self.v_scroll.get() + y;
        if set_to < 0 {
            set_to = 0;
        } else if self.rect.get().height as i32 + set_to > self.current_height.get() as i32 {
            set_to = self.v_scroll.get() as i32;
        }
        self.v_scroll.set(set_to);
    }

    fn change_selection(&self, i: u32) {
        match self.selected.get() {
            Some(i) => {
                match self.entries.borrow().get(i as usize) {
                    Some(entry) => {
                        entry.highlighted.set(false);
                    },
                    None => {},
                }
            },
            _ => {},
        }

        if let Some(entry) = self.entries.borrow().get(i as usize) {
            entry.highlighted.set(true);
            self.selected.set(Some(i));

            let mut y = 0;

            for e in self.entries.borrow().index(0..(i as usize)) {
                y += e.height.get();
            }

            let v_scroll = self.v_scroll.get();

            if y < v_scroll as u32 {
                self.scroll(y as i32 - v_scroll);
            } else if (y + entry.height.get() as u32) > (v_scroll as u32 + self.rect.get().height) {
                self.scroll((y + entry.height.get()) as i32 - (v_scroll + self.rect.get().height as i32));
            }
        }
    }
}

impl Widget for List {
    fn rect(&self) -> &Cell<Rect> {
        &self.rect
    }

    fn draw(&self, renderer: &mut Renderer, _focused: bool) {
        let mut current_y = 0;
        let x = self.rect.get().x;
        let y = self.rect.get().y;
        let width = self.rect.get().width;
        let height = self.rect.get().height;

        let mut target = orbimage::Image::new(width, height);
        target.set(WINDOW_BACKGROUND);

        for entry in self.entries.borrow().iter() {
            let mut image = orbimage::Image::new(width, entry.height.get());

            if entry.highlighted.get() {
                image.set(entry.highlight.get());
            } else {
                image.set(ITEM_BACKGROUND);
            }

            for widget in entry.widgets().borrow().iter() {
                widget.draw(&mut image, false)
            }

            let image = image.data();
            target.image(x, current_y-self.v_scroll.get(), width, entry.height.get(), &image);

            current_y += entry.height.get() as i32
        }
        let target = target.data();
        renderer.image(x, y, width, height, &target)
    }

    fn event(&self, event: Event, focused: bool, redraw: &mut bool) -> bool {
        match event {
            Event::Mouse { point, left_button, .. } => {
                let mut click = false;

                let rect = self.rect.get();
                if rect.contains(point) {
                    if left_button {
                        if self.pressed.check_set(true) {
                            *redraw = true;
                        }
                    } else {
                        if self.pressed.check_set(false) {
                            click = true;
                            *redraw = true;
                        }
                    }
                } else {
                    if !left_button {
                        if self.pressed.check_set(false) {
                            *redraw = true;
                        }
                    }
                }

                if let Some(i) = self.get_entry_index(point) {
                    if click {
                        if let Some(entry) = self.entries.borrow().get(i as usize) {
                            entry.emit_click(point);
                        }
                    }

                    match self.selected.get() {
                        None => {
                            self.change_selection(i);
                            *redraw = true;
                        },
                        Some(selected) => {
                            if selected != i {
                                self.change_selection(i);
                                *redraw = true;
                            }
                        },
                    }
                }
            },
            Event::UpArrow => {
                match self.selected.get() {
                    None => {
                        self.change_selection(0);
                        *redraw = true;
                    },
                    Some(i) => {
                        if i > 0 {
                            self.change_selection(i - 1);
                            *redraw = true;
                        }
                    }
                }
            },
            Event::DownArrow => {
                match self.selected.get() {
                    None => {
                        self.change_selection(0);
                        *redraw = true;
                    },
                    Some(i) => {
                        if i < self.entries.borrow().len() as u32 - 1 {
                            self.change_selection(i + 1);
                            *redraw = true;
                        }
                    }
                }
            },
            Event::Home => {
                self.change_selection(0);
                *redraw = true
            },
            Event::End => {
                self.change_selection(self.entries.borrow().len() as u32 - 1);
                *redraw = true
            },
            Event::Enter => {
                match self.selected.get() {
                    Some(i) => {
                        match self.entries.borrow().get(i as usize) {
                            Some(entry) => {
                                entry.emit_click(Point { x: 0, y: 0});
                            },
                            None => {},
                        }
                    },
                    _ => {},
                }
            },
            Event::Scroll { y, .. } => {
                self.scroll(y * -96);
                *redraw = true;
            },
            _ => {}
        }
        focused
    }
}

impl Place for List {}

<commit_msg>Fix list bugs<commit_after>use orbclient::{Renderer, Color};
use orbimage;
use std::cell::{ Cell, RefCell };
use std::sync::Arc;

use cell::CheckSet;
use event::Event;
use point::Point;
use rect::Rect;
use theme::{ ITEM_BACKGROUND, WINDOW_BACKGROUND, ITEM_SELECTION };
use traits::{ Click, Place };
use widgets::Widget;
use std::ops::Index;

/// An entry in a list
/// Each entry stores widgets within.
pub struct Entry {
    pub height: Cell<u32>,
    click_callback: RefCell<Option<Arc<Fn(&Entry, Point)>>>,
    widgets: RefCell<Vec<Arc<Widget>>>,
    pub highlight: Cell<Color>,
    highlighted: Cell<bool>,
}

impl Entry {
    pub fn new(h: u32) -> Arc<Self> {
        Arc::new(Entry {
            height: Cell::new(h),
            click_callback: RefCell::new(None),
            widgets: RefCell::new(vec![]),
            highlight: Cell::new(ITEM_SELECTION),
            highlighted: Cell::new(false),
        })
    }

    /// Adds a widget to the entry
    pub fn add<T: Widget>(&self, widget: &Arc<T>) {
        let mut widgets = self.widgets.borrow_mut();
        widgets.push(widget.clone());
    }

    fn widgets(&self) -> &RefCell<Vec<Arc<Widget>>> {
        &self.widgets
    }
}

impl Click for Entry {
    fn emit_click(&self, point: Point) {
        if let Some(ref click_callback) = *self.click_callback.borrow() {
            click_callback(self, point);
        }
    }

    fn on_click<T: Fn(&Self, Point) + 'static>(&self, func: T) -> &Self {
        *self.click_callback.borrow_mut() = Some(Arc::new(func));
        self
    }
}

pub struct List {
    pub rect: Cell<Rect>,
    v_scroll: Cell<i32>,
    current_height: Cell<u32>,
    entries: RefCell<Vec<Arc<Entry>>>,
    pressed: Cell<bool>,
    selected: Cell<Option<u32>>,
}

impl List {
    pub fn new() -> Arc<Self> {
        Arc::new(List {
            rect: Cell::new(Rect::default()),
            v_scroll: Cell::new(0),
            current_height: Cell::new(0),
            entries: RefCell::new(vec![]),
            pressed: Cell::new(false),
            selected: Cell::new(None),
        })
    }

    pub fn push(&self, entry: &Arc<Entry>) {
        let h = entry.height.get();
        self.entries.borrow_mut().push(entry.clone());
        self.current_height.set(self.current_height.get() + h);
    }

    // Given absolute coordinates, returns the list entry index
    // drawn at that point.
    fn get_entry_index(&self, p: Point) -> Option<u32> {
        if self.rect.get().contains(p) {
            let mut current_y = 0;
            let x = self.rect.get().x;
            let y = self.rect.get().y;
            let width = self.rect.get().width;
            let scroll = self.v_scroll.get();

            for (i, entry) in self.entries.borrow().iter().enumerate() {
                if Rect::new(x, y+current_y-scroll, width, entry.height.get()).contains(p) {
                    return Some(i as u32)
                }
                current_y += entry.height.get() as i32
            }
        }

        None
    }

    pub fn scroll(&self, y: i32) {
        let mut set_to = self.v_scroll.get() + y;

        let max = self.current_height.get() as i32 - self.rect.get().height as i32;
        if set_to < 0 {
            set_to = 0;
        } else if set_to > max {
            set_to = max;
        }

        self.v_scroll.set(set_to);
    }

    fn change_selection(&self, i: u32) {
        match self.selected.get() {
            Some(i) => {
                match self.entries.borrow().get(i as usize) {
                    Some(entry) => {
                        entry.highlighted.set(false);
                    },
                    None => {},
                }
            },
            _ => {},
        }

        if let Some(entry) = self.entries.borrow().get(i as usize) {
            entry.highlighted.set(true);
            self.selected.set(Some(i));

            let mut y = 0;

            for e in self.entries.borrow().index(0..(i as usize)) {
                y += e.height.get();
            }

            let v_scroll = self.v_scroll.get();

            if y < v_scroll as u32 {
                self.scroll(y as i32 - v_scroll);
            } else if (y + entry.height.get() as u32) > (v_scroll as u32 + self.rect.get().height) {
                self.scroll((y + entry.height.get()) as i32 - (v_scroll + self.rect.get().height as i32));
            }
        }
    }
}

impl Widget for List {
    fn rect(&self) -> &Cell<Rect> {
        &self.rect
    }

    fn draw(&self, renderer: &mut Renderer, _focused: bool) {
        let mut current_y = 0;
        let x = self.rect.get().x;
        let y = self.rect.get().y;
        let width = self.rect.get().width;
        let height = self.rect.get().height;

        let mut target = orbimage::Image::new(width, height);
        target.set(WINDOW_BACKGROUND);

        for entry in self.entries.borrow().iter() {
            let mut image = orbimage::Image::new(width, entry.height.get());

            if entry.highlighted.get() {
                image.set(entry.highlight.get());
            } else {
                image.set(ITEM_BACKGROUND);
            }

            for widget in entry.widgets().borrow().iter() {
                widget.draw(&mut image, false)
            }

            let image = image.data();
            target.image(0, current_y-self.v_scroll.get(), width, entry.height.get(), &image);

            current_y += entry.height.get() as i32
        }
        let target = target.data();
        renderer.image(x, y, width, height, &target)
    }

    fn event(&self, event: Event, focused: bool, redraw: &mut bool) -> bool {
        match event {
            Event::Mouse { point, left_button, .. } => {
                let mut click = false;

                let rect = self.rect.get();
                if rect.contains(point) {
                    if left_button {
                        if self.pressed.check_set(true) {
                            *redraw = true;
                        }
                    } else {
                        if self.pressed.check_set(false) {
                            click = true;
                            *redraw = true;
                        }
                    }
                } else {
                    if !left_button {
                        if self.pressed.check_set(false) {
                            *redraw = true;
                        }
                    }
                }

                if let Some(i) = self.get_entry_index(point) {
                    if click {
                        if let Some(entry) = self.entries.borrow().get(i as usize) {
                            entry.emit_click(point);
                        }
                    }

                    match self.selected.get() {
                        None => {
                            self.change_selection(i);
                            *redraw = true;
                        },
                        Some(selected) => {
                            if selected != i {
                                self.change_selection(i);
                                *redraw = true;
                            }
                        },
                    }
                }
            },
            Event::UpArrow => {
                match self.selected.get() {
                    None => {
                        self.change_selection(0);
                        *redraw = true;
                    },
                    Some(i) => {
                        if i > 0 {
                            self.change_selection(i - 1);
                            *redraw = true;
                        }
                    }
                }
            },
            Event::DownArrow => {
                match self.selected.get() {
                    None => {
                        self.change_selection(0);
                        *redraw = true;
                    },
                    Some(i) => {
                        if i < self.entries.borrow().len() as u32 - 1 {
                            self.change_selection(i + 1);
                            *redraw = true;
                        }
                    }
                }
            },
            Event::Home => {
                self.change_selection(0);
                *redraw = true
            },
            Event::End => {
                self.change_selection(self.entries.borrow().len() as u32 - 1);
                *redraw = true
            },
            Event::Enter => {
                match self.selected.get() {
                    Some(i) => {
                        match self.entries.borrow().get(i as usize) {
                            Some(entry) => {
                                entry.emit_click(Point { x: 0, y: 0});
                            },
                            None => {},
                        }
                    },
                    _ => {},
                }
            },
            Event::Scroll { y, .. } => {
                self.scroll(y * -96);
                *redraw = true;
            },
            _ => {}
        }
        focused
    }
}

impl Place for List {}
<|endoftext|>


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

use std::cmp;
use std::mem::{size_of, transmute_copy};

use errors::{Result, ParquetError};
use util::bit_util::{self, BitReader};

// ----------------------------------------------------------------------
// RLE/Bit-Packing Hybrid Decoders

pub struct RleDecoder<'a> {
  /// Number of bits used to encode the value
  bit_width: usize,

  /// Bit reader loaded with input buffer.
  bit_reader: Option<BitReader<'a>>,

  /// The remaining number of values in RLE for this run
  rle_left: i64,

  /// The remaining number of values in Bit-Packing for this run
  bit_packing_left: i64,

  /// The current value for the case of RLE mode
  current_value: Option<u64>,
}

impl<'a> RleDecoder<'a> {
  pub fn new(bit_width: usize) -> Self {
    RleDecoder { bit_width: bit_width, rle_left: 0, bit_packing_left: 0,
                 bit_reader: None, current_value: None }
  }

  pub fn set_data(&mut self, data: &'a [u8]) {
    if let Some(ref mut bit_reader) = self.bit_reader {
      bit_reader.reset(data);
    } else {
      self.bit_reader = Some(BitReader::new(data));
    }

    let _ = self.reload();
  }

  pub fn decode<T: Default>(&mut self, buffer: &mut [T], max_values: usize) -> Result<usize> {
    assert!(buffer.len() >= max_values);
    assert!(self.bit_reader.is_some());
    assert!(size_of::<T>() <= 8);

    let mut values_read = 0;
    while values_read < max_values {
      if self.rle_left > 0 {
        assert!(self.current_value.is_some());
        let num_values = cmp::min(max_values - values_read, self.rle_left as usize);
        for i in 0..num_values {
          let repeated_value = unsafe {
            transmute_copy::<u64, T>(self.current_value.as_mut().unwrap())
          };
          buffer[values_read + i] = repeated_value;
        }
        self.rle_left -= num_values as i64;
        values_read += num_values;
      } else if self.bit_packing_left > 0 {
        let num_values = cmp::min(max_values - values_read, self.bit_packing_left as usize);
        if let Some(ref mut bit_reader) = self.bit_reader {
          for i in 0..num_values {
            if let Some(v) = bit_reader.get_value(self.bit_width) {
              buffer[values_read + i] = v;
            } else {
              return Err(decode_err!("Error when reading bit-packed value"));
            }
          }
          self.bit_packing_left -= num_values as i64;
          values_read += num_values;
        } else {
          return Err(decode_err!("Bit reader should not be None"));
        }
      } else {
        if !self.reload() {
          break;
        }
      }
    }

    Ok(values_read)
  }

  fn reload(&mut self) -> bool {
    assert!(self.bit_reader.is_some());
    if let Some(ref mut bit_reader) = self.bit_reader {
      if let Some(indicator_value) = bit_reader.get_vlq_int() {
        if indicator_value & 1 == 1 {
          self.bit_packing_left = (indicator_value >> 1) * 8;
        } else {
          self.rle_left = indicator_value >> 1;
          let value_width = bit_util::ceil(self.bit_width as i64, 8);
          self.current_value = bit_reader.get_aligned::<u64>(value_width as usize);
          assert!(self.current_value.is_some());
        }
        return true;
      }
    }
    return false;
  }
}

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

  #[test]
  fn test_rle_decode_int32() {
    // test data: 0-7 with bit width 3
    // 00000011 10001000 11000110 11111010
    let data = vec!(0x03, 0x88, 0xC6, 0xFA);
    let mut decoder: RleDecoder = RleDecoder::new(3);
    decoder.set_data(&data);
    let mut buffer = vec!(0; 8);
    let expected = vec!(0, 1, 2, 3, 4, 5, 6, 7);
    let result = decoder.decode::<i32>(&mut buffer, 8);
    assert!(result.is_ok());
    assert_eq!(buffer, expected);
  }

  #[test]
  fn test_rle_decode_bool() {
    // rle test data: 50 1s followed by 50 0s
    // 01100100 00000001 01100100 00000000
    let data1 = vec!(0x64, 0x01, 0x64, 0x00);

    // bit-packing test data: alternating 1s and 0s, 100 total
    // 100 / 8 = 13 groups
    // 00011011 10101010 ... 00001010
    let data2 = vec!(0x1B, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
                     0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x0A);

    let mut decoder: RleDecoder = RleDecoder::new(1);
    decoder.set_data(&data1);
    let mut buffer = vec!(false; 100);
    let mut expected = vec!();
    for i in 0..100 {
      if i < 50 {
        expected.push(true);
      } else {
        expected.push(false);
      }
    }
    let result = decoder.decode::<bool>(&mut buffer, 100);
    assert!(result.is_ok());
    assert_eq!(buffer, expected);

    decoder.set_data(&data2);
    let mut buffer = vec!(false; 100);
    let mut expected = vec!();
    for i in 0..100 {
      if i % 2 == 0 {
        expected.push(false);
      } else {
        expected.push(true);
      }
    }
    let result = decoder.decode::<bool>(&mut buffer, 100);
    assert!(result.is_ok());
    assert_eq!(buffer, expected);
  }
}
<commit_msg>Add decode_with_dict() and tests to RleDecoder<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

use std::cmp;
use std::mem::{size_of, transmute_copy};

use errors::{Result, ParquetError};
use util::bit_util::{self, BitReader};

// ----------------------------------------------------------------------
// RLE/Bit-Packing Hybrid Decoders

pub struct RleDecoder<'a> {
  /// Number of bits used to encode the value
  bit_width: usize,

  /// Bit reader loaded with input buffer.
  bit_reader: Option<BitReader<'a>>,

  /// The remaining number of values in RLE for this run
  rle_left: i64,

  /// The remaining number of values in Bit-Packing for this run
  bit_packing_left: i64,

  /// The current value for the case of RLE mode
  current_value: Option<u64>,
}

impl<'a> RleDecoder<'a> {
  pub fn new(bit_width: usize) -> Self {
    RleDecoder { bit_width: bit_width, rle_left: 0, bit_packing_left: 0,
                 bit_reader: None, current_value: None }
  }

  pub fn set_data(&mut self, data: &'a [u8]) {
    if let Some(ref mut bit_reader) = self.bit_reader {
      bit_reader.reset(data);
    } else {
      self.bit_reader = Some(BitReader::new(data));
    }

    let _ = self.reload();
  }

  pub fn decode<T: Default>(&mut self, buffer: &mut [T], max_values: usize) -> Result<usize> {
    assert!(buffer.len() >= max_values);
    assert!(self.bit_reader.is_some());
    assert!(size_of::<T>() <= 8);

    let mut values_read = 0;
    while values_read < max_values {
      if self.rle_left > 0 {
        assert!(self.current_value.is_some());
        let num_values = cmp::min(max_values - values_read, self.rle_left as usize);
        for i in 0..num_values {
          let repeated_value = unsafe {
            transmute_copy::<u64, T>(self.current_value.as_mut().unwrap())
          };
          buffer[values_read + i] = repeated_value;
        }
        self.rle_left -= num_values as i64;
        values_read += num_values;
      } else if self.bit_packing_left > 0 {
        let num_values = cmp::min(max_values - values_read, self.bit_packing_left as usize);
        if let Some(ref mut bit_reader) = self.bit_reader {
          for i in 0..num_values {
            if let Some(v) = bit_reader.get_value(self.bit_width) {
              buffer[values_read + i] = v;
            } else {
              return Err(decode_err!("Error when reading bit-packed value"));
            }
          }
          self.bit_packing_left -= num_values as i64;
          values_read += num_values;
        } else {
          return Err(decode_err!("Bit reader should not be None"));
        }
      } else {
        if !self.reload() {
          break;
        }
      }
    }

    Ok(values_read)
  }

  pub fn decode_with_dict<T>(&mut self, dict: &[T], buffer: &mut [T],
                             max_values: usize) -> Result<usize> where T: Default + Clone {
    assert!(buffer.len() >= max_values);
    assert!(self.bit_width > 0);

    let mut values_read = 0;
    while values_read < max_values {
      if self.rle_left > 0 {
        assert!(self.current_value.is_some());
        let num_values = cmp::min(max_values - values_read, self.rle_left as usize);
        let dict_idx = self.current_value.unwrap() as usize;
        println!("current value: {}, values_read: {}", dict_idx, values_read);
        for i in 0..num_values {
          buffer[values_read + i] = dict[dict_idx].clone();
        }
        self.rle_left -= num_values as i64;
        values_read += num_values;
      } else if self.bit_packing_left > 0 {
        let num_values = cmp::min(max_values - values_read, self.bit_packing_left as usize);
        if let Some(ref mut bit_reader) = self.bit_reader {
          for i in 0..num_values {
            if let Some(v) = bit_reader.get_value::<i32>(self.bit_width) {
              buffer[values_read + i] = dict[v as usize].clone();
            } else {
              return Err(decode_err!("Error when reading bit-packed value"));
            }
          }
          self.bit_packing_left -= num_values as i64;
          values_read += num_values;
        } else {
          return Err(decode_err!("Bit reader should not be None"));
        }
      } else {
        if !self.reload() {
          break;
        }
      }
    }

    Ok(values_read)
  }

  fn reload(&mut self) -> bool {
    assert!(self.bit_reader.is_some());
    if let Some(ref mut bit_reader) = self.bit_reader {
      if let Some(indicator_value) = bit_reader.get_vlq_int() {
        if indicator_value & 1 == 1 {
          self.bit_packing_left = (indicator_value >> 1) * 8;
        } else {
          self.rle_left = indicator_value >> 1;
          let value_width = bit_util::ceil(self.bit_width as i64, 8);
          self.current_value = bit_reader.get_aligned::<u64>(value_width as usize);
          assert!(self.current_value.is_some());
        }
        return true;
      }
    }
    return false;
  }
}

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

  #[test]
  fn test_rle_decode_int32() {
    // test data: 0-7 with bit width 3
    // 00000011 10001000 11000110 11111010
    let data = vec!(0x03, 0x88, 0xC6, 0xFA);
    let mut decoder: RleDecoder = RleDecoder::new(3);
    decoder.set_data(&data);
    let mut buffer = vec!(0; 8);
    let expected = vec!(0, 1, 2, 3, 4, 5, 6, 7);
    let result = decoder.decode::<i32>(&mut buffer, 8);
    assert!(result.is_ok());
    assert_eq!(buffer, expected);
  }

  #[test]
  fn test_rle_decode_bool() {
    // rle test data: 50 1s followed by 50 0s
    // 01100100 00000001 01100100 00000000
    let data1 = vec!(0x64, 0x01, 0x64, 0x00);

    // bit-packing test data: alternating 1s and 0s, 100 total
    // 100 / 8 = 13 groups
    // 00011011 10101010 ... 00001010
    let data2 = vec!(0x1B, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
                     0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x0A);

    let mut decoder: RleDecoder = RleDecoder::new(1);
    decoder.set_data(&data1);
    let mut buffer = vec!(false; 100);
    let mut expected = vec!();
    for i in 0..100 {
      if i < 50 {
        expected.push(true);
      } else {
        expected.push(false);
      }
    }
    let result = decoder.decode::<bool>(&mut buffer, 100);
    assert!(result.is_ok());
    assert_eq!(buffer, expected);

    decoder.set_data(&data2);
    let mut buffer = vec!(false; 100);
    let mut expected = vec!();
    for i in 0..100 {
      if i % 2 == 0 {
        expected.push(false);
      } else {
        expected.push(true);
      }
    }
    let result = decoder.decode::<bool>(&mut buffer, 100);
    assert!(result.is_ok());
    assert_eq!(buffer, expected);
  }

  #[test]
  fn test_rle_decode_with_dict_int32() {
    // test RLE encoding: 3 0s followed by 4 1s followed by 5 2s
    // 00000110 00000000 00001000 00000001 00001010 00000010
    let dict = vec!(10, 20, 30);
    let data = vec!(0x06, 0x00, 0x08, 0x01, 0x0A, 0x02);
    let mut decoder: RleDecoder = RleDecoder::new(3);
    decoder.set_data(&data);
    let mut buffer = vec!(0; 12);
    let expected = vec!(10, 10, 10, 20, 20, 20, 20, 30, 30, 30, 30, 30);
    let result = decoder.decode_with_dict::<i32>(&dict, &mut buffer, 12);
    assert!(result.is_ok());
    assert_eq!(buffer, expected);

    // test bit-pack encoding: 345345345455 (2 groups: 8 and 4)
    // 011 100 101 011 100 101 011 100 101 100 101 101
    // 00000011 01100011 11000111 10001110 00000011 01100101 00001011
    let dict = vec!("aaa", "bbb", "ccc", "ddd", "eee", "fff");
    let data = vec!(0x03, 0x63, 0xC7, 0x8E, 0x03, 0x65, 0x0B);
    let mut decoder: RleDecoder = RleDecoder::new(3);
    decoder.set_data(&data);
    let mut buffer = vec!(""; 12);
    let expected = vec!("ddd", "eee", "fff", "ddd", "eee", "fff",
                        "ddd", "eee", "fff", "eee", "fff", "fff");
    let result = decoder.decode_with_dict::<&str>(dict.as_slice(), buffer.as_mut_slice(), 12);
    assert!(result.is_ok());
    assert_eq!(buffer, expected);

  }
}
<|endoftext|>


<commit_before>pub fn add(num_l: &str, num_r: &str) -> String {
    let mut sum: Vec<u8> = denormalize(num_l).into();
    sum.extend(denormalize(num_r).bytes());

    sum.sort();
    sum.reverse();

    normalize(&String::from_utf8(sum).unwrap())
}

pub fn denormalize(num: &str) -> String {
    match num {
        "IV" => "IIII",
        "IX" => "VIIII",
        _ => num,
    }.to_string()
}

fn _factor_out(num: &str, before: &str, after: &str) -> String {
    let parts: Vec<&str> = num.split(before).collect();
    parts.join(after)
}

pub fn normalize(num: &str) -> String {
    let num = _factor_out(num, "IIIII", "V");
    let num = _factor_out(num.as_ref(), "IIII", "IV");
    let num = _factor_out(num.as_ref(), "VIV", "IX");
    let num = _factor_out(num.as_ref(), "VV", "X");
    num
}

#[cfg(test)]
mod tests {
    use super::add;
    use super::normalize;
    use super::denormalize;

    #[test]
    fn add_i_i() {
        assert_eq!("II", add("I", "I"));
    }

    #[test]
    fn add_i_ii() {
        assert_eq!("III", add("I", "II"));
    }

    #[test]
    fn add_ii_iii_requires_normalization_to_v() {
        assert_eq!("V", add("II", "III"));

    }

    #[test]
    fn add_v_i() {
        assert_eq!("VI", add("V", "I"));
    }

    #[test]
    fn add_i_v_understands_the_relative_order_of_v_and_i() {
        assert_eq!("VI", add("I", "V"));
    }

    #[test]
    fn add_i_iv_denormalizes_before_adding() {
        assert_eq!("V", add("I", "IV"));
    }

    #[test]
    fn denormalize_iv() {
        assert_eq!("IIII", denormalize("IV"));
    }

    #[test]
    fn denormalize_ix() {
        assert_eq!("VIIII", denormalize("IX"));
    }

    #[test]
    fn normalize_iiiii() {
        assert_eq!("V", normalize("IIIII"));
    }

    #[test]
    fn normalize_iiii() {
        assert_eq!("IV", normalize("IIII"));
    }

    #[test]
    fn normalize_vv() {
        assert_eq!("X", normalize("VV"));
    }

    #[test]
    fn normalize_viiii() {
        assert_eq!("IX", normalize("VIIII"));
    }

    #[test]
    fn normalize_viiiii() {
        assert_eq!("X", normalize("VIIIII"));
    }

}
<commit_msg>Partial denormalization in Rust<commit_after>pub fn add(num_l: &str, num_r: &str) -> String {
    let mut sum: Vec<u8> = denormalize(num_l).into();
    sum.extend(denormalize(num_r).bytes());

    sum.sort();
    sum.reverse();

    normalize(&String::from_utf8(sum).unwrap())
}

pub fn denormalize(num: &str) -> String {
    let num = _factor_out(num, "IV", "IIII");
    let num = _factor_out(num.as_ref(), "IX", "VIIII");
    num
}

fn _factor_out(num: &str, before: &str, after: &str) -> String {
    let parts: Vec<&str> = num.split(before).collect();
    parts.join(after)
}

pub fn normalize(num: &str) -> String {
    let num = _factor_out(num, "IIIII", "V");
    let num = _factor_out(num.as_ref(), "IIII", "IV");
    let num = _factor_out(num.as_ref(), "VIV", "IX");
    let num = _factor_out(num.as_ref(), "VV", "X");
    num
}

#[cfg(test)]
mod tests {
    use super::add;
    use super::normalize;
    use super::denormalize;

    #[test]
    fn add_i_i() {
        assert_eq!("II", add("I", "I"));
    }

    #[test]
    fn add_i_ii() {
        assert_eq!("III", add("I", "II"));
    }

    #[test]
    fn add_ii_iii_requires_normalization_to_v() {
        assert_eq!("V", add("II", "III"));

    }

    #[test]
    fn add_v_i() {
        assert_eq!("VI", add("V", "I"));
    }

    #[test]
    fn add_i_v_understands_the_relative_order_of_v_and_i() {
        assert_eq!("VI", add("I", "V"));
    }

    #[test]
    fn add_i_iv_denormalizes_before_adding() {
        assert_eq!("V", add("I", "IV"));
    }

    #[test]
    fn denormalize_iv() {
        assert_eq!("IIII", denormalize("IV"));
    }

    #[test]
    fn denormalize_ix() {
        assert_eq!("VIIII", denormalize("IX"));
    }

    #[test]
    fn denormalize_xiv_performs_a_partial_denormalization_on_tail() {
        assert_eq!("XIIII", denormalize("XIV"));
    }

    #[test]
    fn normalize_iiiii() {
        assert_eq!("V", normalize("IIIII"));
    }

    #[test]
    fn normalize_iiii() {
        assert_eq!("IV", normalize("IIII"));
    }

    #[test]
    fn normalize_vv() {
        assert_eq!("X", normalize("VV"));
    }

    #[test]
    fn normalize_viiii() {
        assert_eq!("IX", normalize("VIIII"));
    }

    #[test]
    fn normalize_viiiii() {
        assert_eq!("X", normalize("VIIIII"));
    }

}
<|endoftext|>


<commit_before>// Copyright 2013 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.

//! Markdown formatting for rustdoc
//!
//! This module implements markdown formatting through the sundown C-library
//! (bundled into the rust runtime). This module self-contains the C bindings
//! and necessary legwork to render markdown, and exposes all of the
//! functionality through a unit-struct, `Markdown`, which has an implementation
//! of `fmt::Show`. Example usage:
//!
//! ```rust,ignore
//! use rustdoc::html::markdown::Markdown;
//!
//! let s = "My *markdown* _text_";
//! let html = format!("{}", Markdown(s));
//! // ... something using html
//! ```

#[allow(non_camel_case_types)];

use std::cast;
use std::fmt;
use std::intrinsics;
use std::io;
use std::libc;
use std::local_data;
use std::mem;
use std::str;
use std::vec;
use collections::HashMap;

use html::highlight;
use html::escape::Escape;

/// A unit struct which has the `fmt::Show` trait implemented. When
/// formatted, this struct will emit the HTML corresponding to the rendered
/// version of the contained markdown string.
pub struct Markdown<'a>(&'a str);

static OUTPUT_UNIT: libc::size_t = 64;
static MKDEXT_NO_INTRA_EMPHASIS: libc::c_uint = 1 << 0;
static MKDEXT_TABLES: libc::c_uint = 1 << 1;
static MKDEXT_FENCED_CODE: libc::c_uint = 1 << 2;
static MKDEXT_AUTOLINK: libc::c_uint = 1 << 3;
static MKDEXT_STRIKETHROUGH: libc::c_uint = 1 << 4;

type sd_markdown = libc::c_void;  // this is opaque to us

struct sd_callbacks {
    blockcode: Option<extern "C" fn(*buf, *buf, *buf, *libc::c_void)>,
    blockquote: Option<extern "C" fn(*buf, *buf, *libc::c_void)>,
    blockhtml: Option<extern "C" fn(*buf, *buf, *libc::c_void)>,
    header: Option<extern "C" fn(*buf, *buf, libc::c_int, *libc::c_void)>,
    other: [libc::size_t, ..22],
}

struct html_toc_data {
    header_count: libc::c_int,
    current_level: libc::c_int,
    level_offset: libc::c_int,
}

struct html_renderopt {
    toc_data: html_toc_data,
    flags: libc::c_uint,
    link_attributes: Option<extern "C" fn(*buf, *buf, *libc::c_void)>,
}

struct my_opaque {
    opt: html_renderopt,
    dfltblk: extern "C" fn(*buf, *buf, *buf, *libc::c_void),
}

struct buf {
    data: *u8,
    size: libc::size_t,
    asize: libc::size_t,
    unit: libc::size_t,
}

// sundown FFI
#[link(name = "sundown", kind = "static")]
extern {
    fn sdhtml_renderer(callbacks: *sd_callbacks,
                       options_ptr: *html_renderopt,
                       render_flags: libc::c_uint);
    fn sd_markdown_new(extensions: libc::c_uint,
                       max_nesting: libc::size_t,
                       callbacks: *sd_callbacks,
                       opaque: *libc::c_void) -> *sd_markdown;
    fn sd_markdown_render(ob: *buf,
                          document: *u8,
                          doc_size: libc::size_t,
                          md: *sd_markdown);
    fn sd_markdown_free(md: *sd_markdown);

    fn bufnew(unit: libc::size_t) -> *buf;
    fn bufputs(b: *buf, c: *libc::c_char);
    fn bufrelease(b: *buf);

}

/// Returns Some(code) if `s` is a line that should be stripped from
/// documentation but used in example code. `code` is the portion of
/// `s` that should be used in tests. (None for lines that should be
/// left as-is.)
fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> {
    let trimmed = s.trim();
    if trimmed.starts_with("# ") {
        Some(trimmed.slice_from(2))
    } else {
        None
    }
}

local_data_key!(used_header_map: HashMap<~str, uint>)

pub fn render(w: &mut io::Writer, s: &str) -> fmt::Result {
    extern fn block(ob: *buf, text: *buf, lang: *buf, opaque: *libc::c_void) {
        unsafe {
            let my_opaque: &my_opaque = cast::transmute(opaque);
            vec::raw::buf_as_slice((*text).data, (*text).size as uint, |text| {
                let text = str::from_utf8(text).unwrap();
                let mut lines = text.lines().filter(|l| stripped_filtered_line(*l).is_none());
                let text = lines.to_owned_vec().connect("\n");

                let buf = buf {
                    data: text.as_bytes().as_ptr(),
                    size: text.len() as libc::size_t,
                    asize: text.len() as libc::size_t,
                    unit: 0,
                };
                let rendered = if lang.is_null() {
                    false
                } else {
                    vec::raw::buf_as_slice((*lang).data,
                                           (*lang).size as uint, |rlang| {
                        let rlang = str::from_utf8(rlang).unwrap();
                        if rlang.contains("notrust") {
                            (my_opaque.dfltblk)(ob, &buf, lang, opaque);
                            true
                        } else {
                            false
                        }
                    })
                };

                if !rendered {
                    let output = highlight::highlight(text, None).to_c_str();
                    output.with_ref(|r| {
                        bufputs(ob, r)
                    })
                }
            })
        }
    }

    extern fn header(ob: *buf, text: *buf, level: libc::c_int,
                     _opaque: *libc::c_void) {
        // sundown does this, we may as well too
        "\n".with_c_str(|p| unsafe { bufputs(ob, p) });

        // Extract the text provided
        let s = if text.is_null() {
            ~""
        } else {
            unsafe {
                str::raw::from_buf_len((*text).data, (*text).size as uint)
            }
        };

        // Transform the contents of the header into a hyphenated string
        let id = s.words().map(|s| {
            match s.to_ascii_opt() {
                Some(s) => s.to_lower().into_str(),
                None => s.to_owned()
            }
        }).to_owned_vec().connect("-");

        // Make sure our hyphenated ID is unique for this page
        let id = local_data::get_mut(used_header_map, |map| {
            let map = map.unwrap();
            match map.find_mut(&id) {
                None => {}
                Some(a) => { *a += 1; return format!("{}-{}", id, *a - 1) }
            }
            map.insert(id.clone(), 1);
            id.clone()
        });

        // Render the HTML
        let text = format!(r#"<h{lvl} id="{id}">{}</h{lvl}>"#,
                           Escape(s.as_slice()), lvl = level, id = id);
        text.with_c_str(|p| unsafe { bufputs(ob, p) });
    }

    // This code is all lifted from examples/sundown.c in the sundown repo
    unsafe {
        let ob = bufnew(OUTPUT_UNIT);
        let extensions = MKDEXT_NO_INTRA_EMPHASIS | MKDEXT_TABLES |
                         MKDEXT_FENCED_CODE | MKDEXT_AUTOLINK |
                         MKDEXT_STRIKETHROUGH;
        let options = html_renderopt {
            toc_data: html_toc_data {
                header_count: 0,
                current_level: 0,
                level_offset: 0,
            },
            flags: 0,
            link_attributes: None,
        };
        let mut callbacks: sd_callbacks = mem::init();

        sdhtml_renderer(&callbacks, &options, 0);
        let opaque = my_opaque {
            opt: options,
            dfltblk: callbacks.blockcode.unwrap(),
        };
        callbacks.blockcode = Some(block);
        callbacks.header = Some(header);
        let markdown = sd_markdown_new(extensions, 16, &callbacks,
                                       &opaque as *my_opaque as *libc::c_void);

        sd_markdown_render(ob, s.as_ptr(), s.len() as libc::size_t, markdown);
        sd_markdown_free(markdown);

        let ret = vec::raw::buf_as_slice((*ob).data, (*ob).size as uint, |buf| {
            w.write(buf)
        });

        bufrelease(ob);
        ret
    }
}

pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) {
    extern fn block(_ob: *buf, text: *buf, lang: *buf, opaque: *libc::c_void) {
        unsafe {
            if text.is_null() { return }
            let (shouldfail, ignore) = if lang.is_null() {
                (false, false)
            } else {
                vec::raw::buf_as_slice((*lang).data,
                                       (*lang).size as uint, |lang| {
                    let s = str::from_utf8(lang).unwrap();
                    (s.contains("should_fail"), s.contains("ignore") ||
                                                s.contains("notrust"))
                })
            };
            if ignore { return }
            vec::raw::buf_as_slice((*text).data, (*text).size as uint, |text| {
                let tests: &mut ::test::Collector = intrinsics::transmute(opaque);
                let text = str::from_utf8(text).unwrap();
                let mut lines = text.lines().map(|l| stripped_filtered_line(l).unwrap_or(l));
                let text = lines.to_owned_vec().connect("\n");
                tests.add_test(text, shouldfail);
            })
        }
    }

    unsafe {
        let ob = bufnew(OUTPUT_UNIT);
        let extensions = MKDEXT_NO_INTRA_EMPHASIS | MKDEXT_TABLES |
                         MKDEXT_FENCED_CODE | MKDEXT_AUTOLINK |
                         MKDEXT_STRIKETHROUGH;
        let callbacks = sd_callbacks {
            blockcode: Some(block),
            blockquote: None,
            blockhtml: None,
            header: None,
            other: mem::init()
        };

        let tests = tests as *mut ::test::Collector as *libc::c_void;
        let markdown = sd_markdown_new(extensions, 16, &callbacks, tests);

        sd_markdown_render(ob, doc.as_ptr(), doc.len() as libc::size_t,
                           markdown);
        sd_markdown_free(markdown);
        bufrelease(ob);
    }
}

/// By default this markdown renderer generates anchors for each header in the
/// rendered document. The anchor name is the contents of the header spearated
/// by hyphens, and a task-local map is used to disambiguate among duplicate
/// headers (numbers are appended).
///
/// This method will reset the local table for these headers. This is typically
/// used at the beginning of rendering an entire HTML page to reset from the
/// previous state (if any).
pub fn reset_headers() {
    local_data::set(used_header_map, HashMap::new())
}

impl<'a> fmt::Show for Markdown<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let Markdown(md) = *self;
        // This is actually common enough to special-case
        if md.len() == 0 { return Ok(()) }
        render(fmt.buf, md.as_slice())
    }
}
<commit_msg>rustdoc: Don't escape contents of headers<commit_after>// Copyright 2013 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.

//! Markdown formatting for rustdoc
//!
//! This module implements markdown formatting through the sundown C-library
//! (bundled into the rust runtime). This module self-contains the C bindings
//! and necessary legwork to render markdown, and exposes all of the
//! functionality through a unit-struct, `Markdown`, which has an implementation
//! of `fmt::Show`. Example usage:
//!
//! ```rust,ignore
//! use rustdoc::html::markdown::Markdown;
//!
//! let s = "My *markdown* _text_";
//! let html = format!("{}", Markdown(s));
//! // ... something using html
//! ```

#[allow(non_camel_case_types)];

use std::cast;
use std::fmt;
use std::intrinsics;
use std::io;
use std::libc;
use std::local_data;
use std::mem;
use std::str;
use std::vec;
use collections::HashMap;

use html::highlight;

/// A unit struct which has the `fmt::Show` trait implemented. When
/// formatted, this struct will emit the HTML corresponding to the rendered
/// version of the contained markdown string.
pub struct Markdown<'a>(&'a str);

static OUTPUT_UNIT: libc::size_t = 64;
static MKDEXT_NO_INTRA_EMPHASIS: libc::c_uint = 1 << 0;
static MKDEXT_TABLES: libc::c_uint = 1 << 1;
static MKDEXT_FENCED_CODE: libc::c_uint = 1 << 2;
static MKDEXT_AUTOLINK: libc::c_uint = 1 << 3;
static MKDEXT_STRIKETHROUGH: libc::c_uint = 1 << 4;

type sd_markdown = libc::c_void;  // this is opaque to us

struct sd_callbacks {
    blockcode: Option<extern "C" fn(*buf, *buf, *buf, *libc::c_void)>,
    blockquote: Option<extern "C" fn(*buf, *buf, *libc::c_void)>,
    blockhtml: Option<extern "C" fn(*buf, *buf, *libc::c_void)>,
    header: Option<extern "C" fn(*buf, *buf, libc::c_int, *libc::c_void)>,
    other: [libc::size_t, ..22],
}

struct html_toc_data {
    header_count: libc::c_int,
    current_level: libc::c_int,
    level_offset: libc::c_int,
}

struct html_renderopt {
    toc_data: html_toc_data,
    flags: libc::c_uint,
    link_attributes: Option<extern "C" fn(*buf, *buf, *libc::c_void)>,
}

struct my_opaque {
    opt: html_renderopt,
    dfltblk: extern "C" fn(*buf, *buf, *buf, *libc::c_void),
}

struct buf {
    data: *u8,
    size: libc::size_t,
    asize: libc::size_t,
    unit: libc::size_t,
}

// sundown FFI
#[link(name = "sundown", kind = "static")]
extern {
    fn sdhtml_renderer(callbacks: *sd_callbacks,
                       options_ptr: *html_renderopt,
                       render_flags: libc::c_uint);
    fn sd_markdown_new(extensions: libc::c_uint,
                       max_nesting: libc::size_t,
                       callbacks: *sd_callbacks,
                       opaque: *libc::c_void) -> *sd_markdown;
    fn sd_markdown_render(ob: *buf,
                          document: *u8,
                          doc_size: libc::size_t,
                          md: *sd_markdown);
    fn sd_markdown_free(md: *sd_markdown);

    fn bufnew(unit: libc::size_t) -> *buf;
    fn bufputs(b: *buf, c: *libc::c_char);
    fn bufrelease(b: *buf);

}

/// Returns Some(code) if `s` is a line that should be stripped from
/// documentation but used in example code. `code` is the portion of
/// `s` that should be used in tests. (None for lines that should be
/// left as-is.)
fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> {
    let trimmed = s.trim();
    if trimmed.starts_with("# ") {
        Some(trimmed.slice_from(2))
    } else {
        None
    }
}

local_data_key!(used_header_map: HashMap<~str, uint>)

pub fn render(w: &mut io::Writer, s: &str) -> fmt::Result {
    extern fn block(ob: *buf, text: *buf, lang: *buf, opaque: *libc::c_void) {
        unsafe {
            let my_opaque: &my_opaque = cast::transmute(opaque);
            vec::raw::buf_as_slice((*text).data, (*text).size as uint, |text| {
                let text = str::from_utf8(text).unwrap();
                let mut lines = text.lines().filter(|l| stripped_filtered_line(*l).is_none());
                let text = lines.to_owned_vec().connect("\n");

                let buf = buf {
                    data: text.as_bytes().as_ptr(),
                    size: text.len() as libc::size_t,
                    asize: text.len() as libc::size_t,
                    unit: 0,
                };
                let rendered = if lang.is_null() {
                    false
                } else {
                    vec::raw::buf_as_slice((*lang).data,
                                           (*lang).size as uint, |rlang| {
                        let rlang = str::from_utf8(rlang).unwrap();
                        if rlang.contains("notrust") {
                            (my_opaque.dfltblk)(ob, &buf, lang, opaque);
                            true
                        } else {
                            false
                        }
                    })
                };

                if !rendered {
                    let output = highlight::highlight(text, None).to_c_str();
                    output.with_ref(|r| {
                        bufputs(ob, r)
                    })
                }
            })
        }
    }

    extern fn header(ob: *buf, text: *buf, level: libc::c_int,
                     _opaque: *libc::c_void) {
        // sundown does this, we may as well too
        "\n".with_c_str(|p| unsafe { bufputs(ob, p) });

        // Extract the text provided
        let s = if text.is_null() {
            ~""
        } else {
            unsafe {
                str::raw::from_buf_len((*text).data, (*text).size as uint)
            }
        };

        // Transform the contents of the header into a hyphenated string
        let id = s.words().map(|s| {
            match s.to_ascii_opt() {
                Some(s) => s.to_lower().into_str(),
                None => s.to_owned()
            }
        }).to_owned_vec().connect("-");

        // Make sure our hyphenated ID is unique for this page
        let id = local_data::get_mut(used_header_map, |map| {
            let map = map.unwrap();
            match map.find_mut(&id) {
                None => {}
                Some(a) => { *a += 1; return format!("{}-{}", id, *a - 1) }
            }
            map.insert(id.clone(), 1);
            id.clone()
        });

        // Render the HTML
        let text = format!(r#"<h{lvl} id="{id}">{}</h{lvl}>"#,
                           s, lvl = level, id = id);
        text.with_c_str(|p| unsafe { bufputs(ob, p) });
    }

    // This code is all lifted from examples/sundown.c in the sundown repo
    unsafe {
        let ob = bufnew(OUTPUT_UNIT);
        let extensions = MKDEXT_NO_INTRA_EMPHASIS | MKDEXT_TABLES |
                         MKDEXT_FENCED_CODE | MKDEXT_AUTOLINK |
                         MKDEXT_STRIKETHROUGH;
        let options = html_renderopt {
            toc_data: html_toc_data {
                header_count: 0,
                current_level: 0,
                level_offset: 0,
            },
            flags: 0,
            link_attributes: None,
        };
        let mut callbacks: sd_callbacks = mem::init();

        sdhtml_renderer(&callbacks, &options, 0);
        let opaque = my_opaque {
            opt: options,
            dfltblk: callbacks.blockcode.unwrap(),
        };
        callbacks.blockcode = Some(block);
        callbacks.header = Some(header);
        let markdown = sd_markdown_new(extensions, 16, &callbacks,
                                       &opaque as *my_opaque as *libc::c_void);

        sd_markdown_render(ob, s.as_ptr(), s.len() as libc::size_t, markdown);
        sd_markdown_free(markdown);

        let ret = vec::raw::buf_as_slice((*ob).data, (*ob).size as uint, |buf| {
            w.write(buf)
        });

        bufrelease(ob);
        ret
    }
}

pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) {
    extern fn block(_ob: *buf, text: *buf, lang: *buf, opaque: *libc::c_void) {
        unsafe {
            if text.is_null() { return }
            let (shouldfail, ignore) = if lang.is_null() {
                (false, false)
            } else {
                vec::raw::buf_as_slice((*lang).data,
                                       (*lang).size as uint, |lang| {
                    let s = str::from_utf8(lang).unwrap();
                    (s.contains("should_fail"), s.contains("ignore") ||
                                                s.contains("notrust"))
                })
            };
            if ignore { return }
            vec::raw::buf_as_slice((*text).data, (*text).size as uint, |text| {
                let tests: &mut ::test::Collector = intrinsics::transmute(opaque);
                let text = str::from_utf8(text).unwrap();
                let mut lines = text.lines().map(|l| stripped_filtered_line(l).unwrap_or(l));
                let text = lines.to_owned_vec().connect("\n");
                tests.add_test(text, shouldfail);
            })
        }
    }

    unsafe {
        let ob = bufnew(OUTPUT_UNIT);
        let extensions = MKDEXT_NO_INTRA_EMPHASIS | MKDEXT_TABLES |
                         MKDEXT_FENCED_CODE | MKDEXT_AUTOLINK |
                         MKDEXT_STRIKETHROUGH;
        let callbacks = sd_callbacks {
            blockcode: Some(block),
            blockquote: None,
            blockhtml: None,
            header: None,
            other: mem::init()
        };

        let tests = tests as *mut ::test::Collector as *libc::c_void;
        let markdown = sd_markdown_new(extensions, 16, &callbacks, tests);

        sd_markdown_render(ob, doc.as_ptr(), doc.len() as libc::size_t,
                           markdown);
        sd_markdown_free(markdown);
        bufrelease(ob);
    }
}

/// By default this markdown renderer generates anchors for each header in the
/// rendered document. The anchor name is the contents of the header spearated
/// by hyphens, and a task-local map is used to disambiguate among duplicate
/// headers (numbers are appended).
///
/// This method will reset the local table for these headers. This is typically
/// used at the beginning of rendering an entire HTML page to reset from the
/// previous state (if any).
pub fn reset_headers() {
    local_data::set(used_header_map, HashMap::new())
}

impl<'a> fmt::Show for Markdown<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let Markdown(md) = *self;
        // This is actually common enough to special-case
        if md.len() == 0 { return Ok(()) }
        render(fmt.buf, md.as_slice())
    }
}
<|endoftext|>


<commit_before>//! Check that functions don't accept an "excessive" number of arguments.

use syntax::ast::{Block, FnDecl, NodeId};
use syntax::codemap::Span;
use syntax::visit::FnKind;
use rustc::lint::{Context, LintArray, LintPass};

const MAX_ARGS_DEFAULT: usize = 6;
const MAX_ARGS_FOR_CLOSURE: usize = 4;

declare_lint!(FN_ARG_LIST_LENGTH, Warn, "Warn about long argument lists");

pub struct Pass;

fn get_max_args_allowed(kind: &FnKind) -> usize {
    if let &FnKind::FkFnBlock = kind {
        MAX_ARGS_FOR_CLOSURE
    } else {
        MAX_ARGS_DEFAULT
    }
}

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(FN_ARG_LIST_LENGTH)
    }

    fn check_fn(&mut self, cx: &Context, kind: FnKind, decl: &FnDecl, _: &Block,
                span: Span, _: NodeId) {
        if decl.inputs.len() > get_max_args_allowed(&kind) {
            cx.span_lint(FN_ARG_LIST_LENGTH, span,
                            "function has an excessive number of arguments");
        }
    }
}
<commit_msg>Indentation fix<commit_after>//! Check that functions don't accept an "excessive" number of arguments.

use syntax::ast::{Block, FnDecl, NodeId};
use syntax::codemap::Span;
use syntax::visit::FnKind;
use rustc::lint::{Context, LintArray, LintPass};

const MAX_ARGS_DEFAULT: usize = 6;
const MAX_ARGS_FOR_CLOSURE: usize = 4;

declare_lint!(FN_ARG_LIST_LENGTH, Warn, "Warn about long argument lists");

pub struct Pass;

fn get_max_args_allowed(kind: &FnKind) -> usize {
    if let &FnKind::FkFnBlock = kind {
        MAX_ARGS_FOR_CLOSURE
    } else {
        MAX_ARGS_DEFAULT
    }
}

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(FN_ARG_LIST_LENGTH)
    }

    fn check_fn(&mut self, cx: &Context, kind: FnKind, decl: &FnDecl, _: &Block,
                span: Span, _: NodeId) {
        if decl.inputs.len() > get_max_args_allowed(&kind) {
            cx.span_lint(FN_ARG_LIST_LENGTH, span,
                         "function has an excessive number of arguments");
        }
    }
}
<|endoftext|>