<commit_before>//! Handling of `preserveAspectRatio` values
//!
//! This module handles `preserveAspectRatio` values [per the SVG specification][spec].
//! We have an [`AspectRatio`] struct which encapsulates such a value.
//!
//! ```ignore
//! assert_eq!(
//!     AspectRatio::parse("xMidYMid", ()),
//!     Ok(AspectRatio {
//!         defer: false,
//!         align: Some(Align {
//!             x: Align1D::Mid,
//!             y: Align1D::Mid,
//!             fit: FitMode::Meet,
//!         }),
//!     })
//! );
//! ```
//!
//! [`AspectRatio`]: struct.AspectRatio.html
//! [spec]: https://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute

use error::*;
use parsers::Parse;
use parsers::ParseError;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct AspectRatio {
    defer: bool,
    align: Option<Align>,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum FitMode {
    Meet,
    Slice,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
struct Align {
    x: Align1D,
    y: Align1D,
    fit: FitMode,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum Align1D {
    Min,
    Mid,
    Max,
}

impl Align1D {
    fn compute(self, dest_pos: f64, dest_size: f64, obj_size: f64) -> f64 {
        match self {
            Align1D::Min => dest_pos,
            Align1D::Mid => dest_pos + (dest_size - obj_size) / 2.0,
            Align1D::Max => dest_pos + dest_size - obj_size,
        }
    }
}

impl AspectRatio {
    pub fn is_slice(&self) -> bool {
        match self.align {
            Some(Align { fit: FitMode::Slice, .. }) => true,

            _ => false,
        }
    }

    pub fn compute(
        &self,
        object_width: f64,
        object_height: f64,
        dest_x: f64,
        dest_y: f64,
        dest_width: f64,
        dest_height: f64,
    ) -> (f64, f64, f64, f64) {
        match self.align {
            None => (dest_x, dest_y, dest_width, dest_height),

            Some(Align { x, y, fit }) => {
                let w_factor = dest_width / object_width;
                let h_factor = dest_height / object_height;
                let factor = match fit {
                    FitMode::Meet => w_factor.min(h_factor),
                    FitMode::Slice => w_factor.max(h_factor),
                };

                let w = object_width * factor;
                let h = object_height * factor;

                let xpos = x.compute(dest_x, dest_width, w);
                let ypos = y.compute(dest_y, dest_height, h);

                (xpos, ypos, w, h)
            }
        }
    }
}

impl Default for AspectRatio {
    fn default() -> AspectRatio {
        AspectRatio {
            defer: false,
            align: Some(Align::default()),
        }
    }
}

impl Default for FitMode {
    fn default() -> FitMode {
        FitMode::Meet
    }
}

impl Default for Align {
    fn default() -> Align {
        Align {
            x: Align1D::Mid,
            y: Align1D::Mid,
            fit: FitMode::default(),
        }
    }
}

impl Align {
    fn parse(s: &str) -> Result<Option<Align>, AttributeError> {
        match s {
            "none" => Ok(None),

            "xMinYMin" => Ok(Some((Align1D::Min, Align1D::Min))),
            "xMidYMin" => Ok(Some((Align1D::Mid, Align1D::Min))),
            "xMaxYMin" => Ok(Some((Align1D::Max, Align1D::Min))),

            "xMinYMid" => Ok(Some((Align1D::Min, Align1D::Mid))),
            "xMidYMid" => Ok(Some((Align1D::Mid, Align1D::Mid))),
            "xMaxYMid" => Ok(Some((Align1D::Max, Align1D::Mid))),

            "xMinYMax" => Ok(Some((Align1D::Min, Align1D::Max))),
            "xMidYMax" => Ok(Some((Align1D::Mid, Align1D::Max))),
            "xMaxYMax" => Ok(Some((Align1D::Max, Align1D::Max))),

            _ => Err(make_err()),
        }.map(|xy| {
            xy.map(|(x, y)| {
                Align {
                    x,
                    y,
                    fit: FitMode::default(),
                }
            })
        })
    }
}

impl FitMode {
    fn parse(s: &str) -> Result<FitMode, AttributeError> {
        match s {
            "meet" => Ok(FitMode::Meet),
            "slice" => Ok(FitMode::Slice),
            _ => Err(make_err()),
        }
    }
}

enum ParseState {
    Defer,
    Align,
    Fit,
    Finished,
}

fn make_err() -> AttributeError {
    AttributeError::Parse(ParseError::new(
        "expected \"[defer] <align> [meet | slice]\"",
    ))
}

impl Parse for AspectRatio {
    type Data = ();
    type Err = AttributeError;

    fn parse(s: &str, _: ()) -> Result<AspectRatio, AttributeError> {
        let mut defer = false;
        let mut align = Some(Align::default());
        let mut fit_mode = FitMode::Meet;

        let mut state = ParseState::Defer;

        for v in s.split_whitespace() {
            match state {
                ParseState::Defer => {
                    if v == "defer" {
                        defer = true;
                        state = ParseState::Align;
                    } else {
                        align = Align::parse(v)?;
                        state = ParseState::Fit;
                    }
                }

                ParseState::Align => {
                    align = Align::parse(v)?;
                    state = ParseState::Fit;
                }

                ParseState::Fit => {
                    fit_mode = FitMode::parse(v)?;
                    state = ParseState::Finished;
                }

                _ => {
                    return Err(make_err());
                }
            }
        }

        // The string must match "[defer] <align> [meet | slice]".
        // Since the meet|slice is optional, we can end up in either
        // of the following states:
        match state {
            ParseState::Fit | ParseState::Finished => {}
            _ => {
                return Err(make_err());
            }
        }

        Ok(AspectRatio {
            defer,
            align: match align {
                None => None,
                Some(Align { x, y, .. }) => Some(Align {
                    x,
                    y,
                    fit: fit_mode,
                }),
            },
        })
    }
}

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

    #[test]
    fn parsing_invalid_strings_yields_error() {
        assert!(AspectRatio::parse("", ()).is_err());

        assert!(AspectRatio::parse("defer", ()).is_err());

        assert!(AspectRatio::parse("defer foo", ()).is_err());

        assert!(AspectRatio::parse("defer xmidymid", ()).is_err());

        assert!(AspectRatio::parse("defer xMidYMid foo", ()).is_err());

        assert!(AspectRatio::parse("xmidymid", ()).is_err());

        assert!(AspectRatio::parse("xMidYMid foo", ()).is_err());

        assert!(AspectRatio::parse("defer xMidYMid meet foo", ()).is_err());
    }

    #[test]
    fn parses_valid_strings() {
        assert_eq!(
            AspectRatio::parse("defer none", ()),
            Ok(AspectRatio {
                defer: true,
                align: None,
            })
        );

        assert_eq!(
            AspectRatio::parse("xMidYMid", ()),
            Ok(AspectRatio {
                defer: false,
                align: Some(Align {
                    x: Align1D::Mid,
                    y: Align1D::Mid,
                    fit: FitMode::Meet,
                }),
            })
        );

        assert_eq!(
            AspectRatio::parse("defer xMidYMid", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: Align1D::Mid,
                    y: Align1D::Mid,
                    fit: FitMode::Meet,
                }),
            })
        );

        assert_eq!(
            AspectRatio::parse("defer xMinYMax", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: Align1D::Min,
                    y: Align1D::Max,
                    fit: FitMode::Meet,
                }),
            })
        );

        assert_eq!(
            AspectRatio::parse("defer xMaxYMid meet", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: Align1D::Max,
                    y: Align1D::Mid,
                    fit: FitMode::Meet,
                }),
            })
        );

        assert_eq!(
            AspectRatio::parse("defer xMinYMax slice", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: Align1D::Min,
                    y: Align1D::Max,
                    fit: FitMode::Slice,
                }),
            })
        );
    }

    #[test]
    fn aligns() {
        assert_eq!(
            AspectRatio::parse("xMinYMin meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMinYMin slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMinYMid meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMinYMid slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -49.5, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMinYMax meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMinYMax slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -99.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMidYMin meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (4.95, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMidYMin slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMidYMid meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (4.95, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMidYMid slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -49.5, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMidYMax meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (4.95, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMidYMax slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -99.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMaxYMin meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (9.9, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMaxYMin slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMaxYMid meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (9.9, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMaxYMid slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -49.5, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMaxYMax meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (9.9, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMaxYMax slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -99.0, 10.0, 100.0)
        );
    }
}
<commit_msg>aspect_ratio.rs: use cssparser<commit_after>//! Handling of `preserveAspectRatio` values
//!
//! This module handles `preserveAspectRatio` values [per the SVG specification][spec].
//! We have an [`AspectRatio`] struct which encapsulates such a value.
//!
//! ```ignore
//! assert_eq!(
//!     AspectRatio::parse("xMidYMid", ()),
//!     Ok(AspectRatio {
//!         defer: false,
//!         align: Some(Align {
//!             x: Align1D::Mid,
//!             y: Align1D::Mid,
//!             fit: FitMode::Meet,
//!         }),
//!     })
//! );
//! ```
//!
//! [`AspectRatio`]: struct.AspectRatio.html
//! [spec]: https://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute

use cssparser::{Parser, ParserInput};
use error::*;
use parsers::Parse;
use parsers::ParseError;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct AspectRatio {
    defer: bool,
    align: Option<Align>,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum FitMode {
    Meet,
    Slice,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
struct Align {
    x: Align1D,
    y: Align1D,
    fit: FitMode,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum Align1D {
    Min,
    Mid,
    Max,
}

impl Align1D {
    fn compute(self, dest_pos: f64, dest_size: f64, obj_size: f64) -> f64 {
        match self {
            Align1D::Min => dest_pos,
            Align1D::Mid => dest_pos + (dest_size - obj_size) / 2.0,
            Align1D::Max => dest_pos + dest_size - obj_size,
        }
    }
}

impl AspectRatio {
    pub fn is_slice(&self) -> bool {
        match self.align {
            Some(Align { fit: FitMode::Slice, .. }) => true,

            _ => false,
        }
    }

    pub fn compute(
        &self,
        object_width: f64,
        object_height: f64,
        dest_x: f64,
        dest_y: f64,
        dest_width: f64,
        dest_height: f64,
    ) -> (f64, f64, f64, f64) {
        match self.align {
            None => (dest_x, dest_y, dest_width, dest_height),

            Some(Align { x, y, fit }) => {
                let w_factor = dest_width / object_width;
                let h_factor = dest_height / object_height;
                let factor = match fit {
                    FitMode::Meet => w_factor.min(h_factor),
                    FitMode::Slice => w_factor.max(h_factor),
                };

                let w = object_width * factor;
                let h = object_height * factor;

                let xpos = x.compute(dest_x, dest_width, w);
                let ypos = y.compute(dest_y, dest_height, h);

                (xpos, ypos, w, h)
            }
        }
    }

    fn parse_input<'i, 't>(p: &mut Parser<'i, 't>) -> Result<AspectRatio, ()> {
        let defer = p.try(|p| p.expect_ident_matching("defer")).is_ok();

        let mut align = p.try(|p| {
            p.expect_ident().map_err(|_| ()).and_then(
                |ident| Align::parse(ident),
            )
        })?;

        let fit_mode = p.try(|p| {
            p.expect_ident().map_err(|_| ()).and_then(|ident| {
                FitMode::parse(ident)
            })
        });

        p.expect_exhausted().map_err(|_| ())?;

        if let Some(Align { ref mut fit, .. }) = align {
            *fit = fit_mode.unwrap_or(FitMode::default());
        }

        Ok(AspectRatio { defer, align })
    }
}

impl Default for AspectRatio {
    fn default() -> AspectRatio {
        AspectRatio {
            defer: false,
            align: Some(Align::default()),
        }
    }
}

impl Default for FitMode {
    fn default() -> FitMode {
        FitMode::Meet
    }
}

impl Default for Align {
    fn default() -> Align {
        Align {
            x: Align1D::Mid,
            y: Align1D::Mid,
            fit: FitMode::default(),
        }
    }
}

impl Align {
    fn parse(s: &str) -> Result<Option<Align>, ()> {
        let xy = match s {
            "none" => Ok(None),

            "xMinYMin" => Ok(Some((Align1D::Min, Align1D::Min))),
            "xMidYMin" => Ok(Some((Align1D::Mid, Align1D::Min))),
            "xMaxYMin" => Ok(Some((Align1D::Max, Align1D::Min))),

            "xMinYMid" => Ok(Some((Align1D::Min, Align1D::Mid))),
            "xMidYMid" => Ok(Some((Align1D::Mid, Align1D::Mid))),
            "xMaxYMid" => Ok(Some((Align1D::Max, Align1D::Mid))),

            "xMinYMax" => Ok(Some((Align1D::Min, Align1D::Max))),
            "xMidYMax" => Ok(Some((Align1D::Mid, Align1D::Max))),
            "xMaxYMax" => Ok(Some((Align1D::Max, Align1D::Max))),

            _ => Err(()),
        }?;

        let align = xy.map(|(x, y)| {
            Align {
                x,
                y,
                fit: FitMode::default(),
            }
        });

        Ok(align)
    }
}

impl FitMode {
    fn parse(s: &str) -> Result<FitMode, ()> {
        match s {
            "meet" => Ok(FitMode::Meet),
            "slice" => Ok(FitMode::Slice),
            _ => Err(()),
        }
    }
}

impl Parse for AspectRatio {
    type Data = ();
    type Err = AttributeError;

    fn parse(s: &str, _: ()) -> Result<AspectRatio, AttributeError> {
        let mut input = ParserInput::new(s);
        AspectRatio::parse_input(&mut Parser::new(&mut input)).map_err(|_| {
            AttributeError::Parse(ParseError::new(
                "expected \"[defer] <align> [meet | slice]\"",
            ))
        })
    }
}

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

    #[test]
    fn parsing_invalid_strings_yields_error() {
        assert!(AspectRatio::parse("", ()).is_err());

        assert!(AspectRatio::parse("defer", ()).is_err());

        assert!(AspectRatio::parse("defer foo", ()).is_err());

        assert!(AspectRatio::parse("defer xmidymid", ()).is_err());

        assert!(AspectRatio::parse("defer xMidYMid foo", ()).is_err());

        assert!(AspectRatio::parse("xmidymid", ()).is_err());

        assert!(AspectRatio::parse("xMidYMid foo", ()).is_err());

        assert!(AspectRatio::parse("defer xMidYMid meet foo", ()).is_err());
    }

    #[test]
    fn parses_valid_strings() {
        assert_eq!(
            AspectRatio::parse("defer none", ()),
            Ok(AspectRatio {
                defer: true,
                align: None,
            })
        );

        assert_eq!(
            AspectRatio::parse("xMidYMid", ()),
            Ok(AspectRatio {
                defer: false,
                align: Some(Align {
                    x: Align1D::Mid,
                    y: Align1D::Mid,
                    fit: FitMode::Meet,
                }),
            })
        );

        assert_eq!(
            AspectRatio::parse("defer xMidYMid", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: Align1D::Mid,
                    y: Align1D::Mid,
                    fit: FitMode::Meet,
                }),
            })
        );

        assert_eq!(
            AspectRatio::parse("defer xMinYMax", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: Align1D::Min,
                    y: Align1D::Max,
                    fit: FitMode::Meet,
                }),
            })
        );

        assert_eq!(
            AspectRatio::parse("defer xMaxYMid meet", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: Align1D::Max,
                    y: Align1D::Mid,
                    fit: FitMode::Meet,
                }),
            })
        );

        assert_eq!(
            AspectRatio::parse("defer xMinYMax slice", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: Align1D::Min,
                    y: Align1D::Max,
                    fit: FitMode::Slice,
                }),
            })
        );
    }

    #[test]
    fn aligns() {
        assert_eq!(
            AspectRatio::parse("xMinYMin meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMinYMin slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMinYMid meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMinYMid slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -49.5, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMinYMax meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMinYMax slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -99.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMidYMin meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (4.95, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMidYMin slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMidYMid meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (4.95, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMidYMid slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -49.5, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMidYMax meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (4.95, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMidYMax slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -99.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMaxYMin meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (9.9, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMaxYMin slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMaxYMid meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (9.9, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMaxYMid slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -49.5, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMaxYMax meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (9.9, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMaxYMax slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -99.0, 10.0, 100.0)
        );
    }
}
<|endoftext|>


<commit_before>extern crate webrender;
extern crate glutin;
extern crate gleam;
extern crate webrender_traits;
extern crate euclid;

use euclid::{Size2D, Point2D, Rect, Matrix4D};
use gleam::gl;
use std::path::PathBuf;
use std::ffi::CStr;
use webrender_traits::{AuxiliaryListsBuilder, ColorF, Epoch, GlyphInstance};
use webrender_traits::{ImageData, ImageFormat, PipelineId, RendererKind};
use std::fs::File;
use std::io::Read;
use std::env;

fn _load_file(name: &str) -> Vec<u8> {
    let mut file = File::open(name).unwrap();
    let mut buffer = vec![];
    file.read_to_end(&mut buffer).unwrap();
    buffer
}

struct Notifier {
    window_proxy: glutin::WindowProxy,
}

impl Notifier {
    fn new(window_proxy: glutin::WindowProxy) -> Notifier {
        Notifier {
            window_proxy: window_proxy,
        }
    }
}

pub struct WebRenderFrameBuilder {
    pub root_pipeline_id: PipelineId,
    pub next_scroll_layer_id: usize,
}

impl webrender_traits::RenderNotifier for Notifier {
    fn new_frame_ready(&mut self) {
        self.window_proxy.wakeup_event_loop();
    }

    fn new_scroll_frame_ready(&mut self, _composite_needed: bool) {
        self.window_proxy.wakeup_event_loop();
    }

    fn pipeline_size_changed(&mut self,
                             _: PipelineId,
                             _: Option<Size2D<f32>>) {
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let res_path = if args.len() > 1 {
        Some(PathBuf::from(&args[1]))
    } else {
        None
    };

    let window = glutin::WindowBuilder::new()
                .with_title("WebRender Sample")
                .with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2)))
                .build()
                .unwrap();

    unsafe {
        window.make_current().ok();
        gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);
        gl::clear_color(0.3, 0.0, 0.0, 1.0);
    }

    let version = unsafe {
        let data = CStr::from_ptr(gl::GetString(gl::VERSION) as *const _).to_bytes().to_vec();
        String::from_utf8(data).unwrap()
    };

    println!("OpenGL version {}", version);
    println!("Shader resource path: {:?}", res_path);

    let (width, height) = window.get_inner_size().unwrap();

    let opts = webrender::RendererOptions {
        device_pixel_ratio: 1.0,
        resource_override_path: res_path,
        enable_aa: false,
        enable_msaa: false,
        enable_profiler: false,
        enable_recording: false,
        enable_scrollbars: false,
        debug: true,
        precache_shaders: true,
        renderer_kind: RendererKind::Native,
        enable_subpixel_aa: false,
    };

    let (mut renderer, sender) = webrender::renderer::Renderer::new(opts);
    let api = sender.create_api();

//     let font_path = "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf";
//     let font_bytes = load_file(font_path);
//     let font_key = api.add_raw_font(font_bytes);

    let notifier = Box::new(Notifier::new(window.create_window_proxy()));
    renderer.set_render_notifier(notifier);

    let pipeline_id = PipelineId(0, 0);
    let epoch = Epoch(0);
    let root_background_color = ColorF::new(0.3, 0.0, 0.0, 1.0);

    let mut auxiliary_lists_builder = AuxiliaryListsBuilder::new();
    let mut builder = webrender_traits::DisplayListBuilder::new();

    let bounds = Rect::new(Point2D::new(0.0, 0.0), Size2D::new(width as f32, height as f32));
    builder.push_stacking_context(
        webrender_traits::StackingContext::new(webrender_traits::ScrollPolicy::Scrollable,
                                               bounds,
                                               bounds,
                                               0,
                                               &Matrix4D::identity(),
                                               &Matrix4D::identity(),
                                               webrender_traits::MixBlendMode::Normal,
                                               Vec::new(),
                                               &mut auxiliary_lists_builder));

    let clip_region = {
        let mask = webrender_traits::ImageMask {
            image: api.add_image(2, 2, None, ImageFormat::A8, ImageData::new(vec![0,80, 180, 255])),
            rect: Rect::new(Point2D::new(75.0, 75.0), Size2D::new(100.0, 100.0)),
            repeat: false,
        };
        let radius = webrender_traits::BorderRadius::uniform(20.0);
        let complex = webrender_traits::ComplexClipRegion::new(
            Rect::new(Point2D::new(50.0, 50.0), Size2D::new(100.0, 100.0)),
            radius);

        webrender_traits::ClipRegion::new(&bounds,
                                          vec![complex],
                                          Some(mask),
                                          &mut auxiliary_lists_builder)
    };

    builder.push_rect(Rect::new(Point2D::new(100.0, 100.0), Size2D::new(100.0, 100.0)),
                      clip_region,
                      ColorF::new(0.0, 1.0, 0.0, 1.0));

    let _text_bounds = Rect::new(Point2D::new(100.0, 200.0), Size2D::new(700.0, 300.0));

    let _glyphs = vec![
        GlyphInstance {
            index: 48,
            x: 100.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 68,
            x: 150.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 80,
            x: 200.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 82,
            x: 250.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 81,
            x: 300.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 3,
            x: 350.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 86,
            x: 400.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 79,
            x: 450.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 72,
            x: 500.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 83,
            x: 550.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 87,
            x: 600.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 17,
            x: 650.0,
            y: 100.0,
        },
    ];

//     builder.push_text(text_bounds,
//                       clip_region,
//                       glyphs,
//                       font_key,
//                       ColorF::new(1.0, 1.0, 0.0, 1.0),
//                       Au::from_px(32),
//                       Au::from_px(0),
//                       &mut frame_builder.auxiliary_lists_builder);

    builder.pop_stacking_context();

    api.set_root_display_list(
        root_background_color,
        epoch,
        pipeline_id,
        Size2D::new(width as f32, height as f32),
        builder.finalize(),
        auxiliary_lists_builder.finalize());
    api.set_root_pipeline(pipeline_id);

    for event in window.wait_events() {
        gl::clear(gl::COLOR_BUFFER_BIT);
        renderer.update();

        renderer.render(Size2D::new(width, height));

        window.swap_buffers().ok();

        match event {
            glutin::Event::Closed => break,
            glutin::Event::KeyboardInput(_element_state, scan_code, _virtual_key_code) => {
                if scan_code == 9 {
                    break;
                }
            }
            _ => ()
        }
    }
}
<commit_msg>Auto merge of #584 - frewsxcv:get_string, r=glennw<commit_after>extern crate webrender;
extern crate glutin;
extern crate gleam;
extern crate webrender_traits;
extern crate euclid;

use euclid::{Size2D, Point2D, Rect, Matrix4D};
use gleam::gl;
use std::path::PathBuf;
use std::ffi::CStr;
use webrender_traits::{AuxiliaryListsBuilder, ColorF, Epoch, GlyphInstance};
use webrender_traits::{ImageData, ImageFormat, PipelineId, RendererKind};
use std::fs::File;
use std::io::Read;
use std::env;

fn _load_file(name: &str) -> Vec<u8> {
    let mut file = File::open(name).unwrap();
    let mut buffer = vec![];
    file.read_to_end(&mut buffer).unwrap();
    buffer
}

struct Notifier {
    window_proxy: glutin::WindowProxy,
}

impl Notifier {
    fn new(window_proxy: glutin::WindowProxy) -> Notifier {
        Notifier {
            window_proxy: window_proxy,
        }
    }
}

pub struct WebRenderFrameBuilder {
    pub root_pipeline_id: PipelineId,
    pub next_scroll_layer_id: usize,
}

impl webrender_traits::RenderNotifier for Notifier {
    fn new_frame_ready(&mut self) {
        self.window_proxy.wakeup_event_loop();
    }

    fn new_scroll_frame_ready(&mut self, _composite_needed: bool) {
        self.window_proxy.wakeup_event_loop();
    }

    fn pipeline_size_changed(&mut self,
                             _: PipelineId,
                             _: Option<Size2D<f32>>) {
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let res_path = if args.len() > 1 {
        Some(PathBuf::from(&args[1]))
    } else {
        None
    };

    let window = glutin::WindowBuilder::new()
                .with_title("WebRender Sample")
                .with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2)))
                .build()
                .unwrap();

    unsafe {
        window.make_current().ok();
        gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);
        gl::clear_color(0.3, 0.0, 0.0, 1.0);
    }

    println!("OpenGL version {}", gl::get_string(gl::VERSION));
    println!("Shader resource path: {:?}", res_path);

    let (width, height) = window.get_inner_size().unwrap();

    let opts = webrender::RendererOptions {
        device_pixel_ratio: 1.0,
        resource_override_path: res_path,
        enable_aa: false,
        enable_msaa: false,
        enable_profiler: false,
        enable_recording: false,
        enable_scrollbars: false,
        debug: true,
        precache_shaders: true,
        renderer_kind: RendererKind::Native,
        enable_subpixel_aa: false,
    };

    let (mut renderer, sender) = webrender::renderer::Renderer::new(opts);
    let api = sender.create_api();

//     let font_path = "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf";
//     let font_bytes = load_file(font_path);
//     let font_key = api.add_raw_font(font_bytes);

    let notifier = Box::new(Notifier::new(window.create_window_proxy()));
    renderer.set_render_notifier(notifier);

    let pipeline_id = PipelineId(0, 0);
    let epoch = Epoch(0);
    let root_background_color = ColorF::new(0.3, 0.0, 0.0, 1.0);

    let mut auxiliary_lists_builder = AuxiliaryListsBuilder::new();
    let mut builder = webrender_traits::DisplayListBuilder::new();

    let bounds = Rect::new(Point2D::new(0.0, 0.0), Size2D::new(width as f32, height as f32));
    builder.push_stacking_context(
        webrender_traits::StackingContext::new(webrender_traits::ScrollPolicy::Scrollable,
                                               bounds,
                                               bounds,
                                               0,
                                               &Matrix4D::identity(),
                                               &Matrix4D::identity(),
                                               webrender_traits::MixBlendMode::Normal,
                                               Vec::new(),
                                               &mut auxiliary_lists_builder));

    let clip_region = {
        let mask = webrender_traits::ImageMask {
            image: api.add_image(2, 2, None, ImageFormat::A8, ImageData::new(vec![0,80, 180, 255])),
            rect: Rect::new(Point2D::new(75.0, 75.0), Size2D::new(100.0, 100.0)),
            repeat: false,
        };
        let radius = webrender_traits::BorderRadius::uniform(20.0);
        let complex = webrender_traits::ComplexClipRegion::new(
            Rect::new(Point2D::new(50.0, 50.0), Size2D::new(100.0, 100.0)),
            radius);

        webrender_traits::ClipRegion::new(&bounds,
                                          vec![complex],
                                          Some(mask),
                                          &mut auxiliary_lists_builder)
    };

    builder.push_rect(Rect::new(Point2D::new(100.0, 100.0), Size2D::new(100.0, 100.0)),
                      clip_region,
                      ColorF::new(0.0, 1.0, 0.0, 1.0));

    let _text_bounds = Rect::new(Point2D::new(100.0, 200.0), Size2D::new(700.0, 300.0));

    let _glyphs = vec![
        GlyphInstance {
            index: 48,
            x: 100.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 68,
            x: 150.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 80,
            x: 200.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 82,
            x: 250.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 81,
            x: 300.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 3,
            x: 350.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 86,
            x: 400.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 79,
            x: 450.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 72,
            x: 500.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 83,
            x: 550.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 87,
            x: 600.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 17,
            x: 650.0,
            y: 100.0,
        },
    ];

//     builder.push_text(text_bounds,
//                       clip_region,
//                       glyphs,
//                       font_key,
//                       ColorF::new(1.0, 1.0, 0.0, 1.0),
//                       Au::from_px(32),
//                       Au::from_px(0),
//                       &mut frame_builder.auxiliary_lists_builder);

    builder.pop_stacking_context();

    api.set_root_display_list(
        root_background_color,
        epoch,
        pipeline_id,
        Size2D::new(width as f32, height as f32),
        builder.finalize(),
        auxiliary_lists_builder.finalize());
    api.set_root_pipeline(pipeline_id);

    for event in window.wait_events() {
        gl::clear(gl::COLOR_BUFFER_BIT);
        renderer.update();

        renderer.render(Size2D::new(width, height));

        window.swap_buffers().ok();

        match event {
            glutin::Event::Closed => break,
            glutin::Event::KeyboardInput(_element_state, scan_code, _virtual_key_code) => {
                if scan_code == 9 {
                    break;
                }
            }
            _ => ()
        }
    }
}
<|endoftext|>


<commit_before>use crate::schema::*;
use diesel::sql_types::Text;
use diesel::*;

#[test]
fn association_where_struct_name_doesnt_match_table_name() {
    #[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations)]
    #[belongs_to(Post)]
    #[table_name = "comments"]
    struct OtherComment {
        id: i32,
        post_id: i32,
    }

    let connection = connection_with_sean_and_tess_in_users_table();

    let sean = find_user_by_name("Sean", &connection);
    insert_into(posts::table)
        .values(&sean.new_post("Hello", None))
        .execute(&connection)
        .unwrap();
    let post = posts::table.first::<Post>(&connection).unwrap();
    insert_into(comments::table)
        .values(&NewComment(post.id, "comment"))
        .execute(&connection)
        .unwrap();

    let comment_text = OtherComment::belonging_to(&post)
        .select(comments::text)
        .first::<String>(&connection);
    assert_eq!(Ok("comment".into()), comment_text);
}

#[test]
#[cfg(not(any(feature = "sqlite", feature = "mysql")))]
fn association_where_parent_and_child_have_underscores() {
    #[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations)]
    #[belongs_to(User)]
    pub struct SpecialPost {
        id: i32,
        user_id: i32,
        title: String,
    }

    #[derive(Insertable)]
    #[table_name = "special_posts"]
    struct NewSpecialPost {
        user_id: i32,
        title: String,
    }

    impl SpecialPost {
        fn new(user_id: i32, title: &str) -> NewSpecialPost {
            NewSpecialPost {
                user_id: user_id,
                title: title.to_owned(),
            }
        }
    }

    #[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations)]
    #[belongs_to(SpecialPost)]
    struct SpecialComment {
        id: i32,
        special_post_id: i32,
    }

    impl SpecialComment {
        fn new(special_post_id: i32) -> NewSpecialComment {
            NewSpecialComment {
                special_post_id: special_post_id,
            }
        }
    }

    #[derive(Insertable)]
    #[table_name = "special_comments"]
    struct NewSpecialComment {
        special_post_id: i32,
    }

    let connection = connection_with_sean_and_tess_in_users_table();

    let sean = find_user_by_name("Sean", &connection);
    let new_post = SpecialPost::new(sean.id, "title");
    let special_post: SpecialPost = insert_into(special_posts::table)
        .values(&new_post)
        .get_result(&connection)
        .unwrap();
    let new_comment = SpecialComment::new(special_post.id);
    insert_into(special_comments::table)
        .values(&new_comment)
        .execute(&connection)
        .unwrap();

    let comment: SpecialComment = SpecialComment::belonging_to(&special_post)
        .first(&connection)
        .unwrap();

    assert_eq!(special_post.id, comment.special_post_id);
}

// This module has no test functions, as it's only to test compilation.
mod associations_can_have_nullable_foreign_keys {
    #![allow(dead_code)]

    table! {
        foos{
            id -> Integer,
        }
    }

    table! {
        bars {
            id -> Integer,
            foo_id -> Nullable<Integer>,
        }
    }
    // This test has no assertions, as it is for compilation purposes only.
    #[derive(Identifiable)]
    pub struct Foo {
        id: i32,
    }

    #[belongs_to(Foo)]
    #[derive(Identifiable, Associations)]
    pub struct Bar {
        id: i32,
        foo_id: Option<i32>,
    }
}

// This module has no test functions, as it's only to test compilation.
mod multiple_lifetimes_in_insertable_struct_definition {
    #![allow(dead_code)]
    use crate::schema::posts;

    #[derive(Insertable)]
    #[table_name = "posts"]
    pub struct MyPost<'a> {
        title: &'a str,
        body: &'a str,
    }
}

mod lifetimes_with_names_other_than_a {
    #![allow(dead_code)]
    use crate::schema::posts;

    #[derive(Insertable)]
    #[table_name = "posts"]
    pub struct MyPost<'a, 'b> {
        id: i32,
        title: &'b str,
        body: &'a str,
    }
}

mod insertable_with_cow {
    #![allow(dead_code)]
    use crate::schema::posts;
    use std::borrow::Cow;

    #[derive(Insertable)]
    #[table_name = "posts"]
    pub struct MyPost<'a> {
        id: i32,
        title: Cow<'a, str>,
        body: Cow<'a, str>,
    }
}

mod custom_foreign_keys_are_respected_on_belongs_to {
    #![allow(dead_code)]

    use crate::schema::User;

    table! { special_posts { id -> Integer, author_id -> Integer, } }

    #[derive(Identifiable, Associations)]
    #[belongs_to(User, foreign_key = "author_id")]
    pub struct SpecialPost {
        id: i32,
        author_id: i32,
    }
}

mod derive_identifiable_with_lifetime {
    #![allow(dead_code)]
    use crate::schema::posts;

    #[derive(Identifiable)]
    pub struct Post<'a> {
        id: &'a i32,
    }
}

#[test]
fn derive_identifiable_with_non_standard_pk() {
    use diesel::associations::*;

    #[derive(Identifiable)]
    #[table_name = "posts"]
    #[primary_key(foo_id)]
    #[allow(dead_code)]
    struct Foo<'a> {
        id: i32,
        foo_id: &'a str,
        foo: i32,
    }

    let foo1 = Foo {
        id: 1,
        foo_id: "hi",
        foo: 2,
    };
    let foo2 = Foo {
        id: 2,
        foo_id: "there",
        foo: 3,
    };
    assert_eq!(&"hi", foo1.id());
    assert_eq!(&"there", foo2.id());
    // Fails to compile if wrong table is generated.
    let _: posts::table = Foo::<'static>::table();
}

#[test]
fn derive_identifiable_with_composite_pk() {
    use diesel::associations::Identifiable;

    #[derive(Identifiable)]
    #[primary_key(foo_id, bar_id)]
    #[table_name = "posts"]
    #[allow(dead_code)]
    struct Foo {
        id: i32,
        foo_id: i32,
        bar_id: i32,
        foo: i32,
    }

    let foo1 = Foo {
        id: 1,
        foo_id: 2,
        bar_id: 3,
        foo: 4,
    };
    let foo2 = Foo {
        id: 5,
        foo_id: 6,
        bar_id: 7,
        foo: 8,
    };
    assert_eq!((&2, &3), foo1.id());
    assert_eq!((&6, &7), foo2.id());
}

#[test]
fn derive_insertable_with_option_for_not_null_field_with_default() {
    #[derive(Insertable)]
    #[table_name = "users"]
    struct NewUser {
        id: Option<i32>,
        name: &'static str,
    }

    let conn = connection();
    let data = vec![
        NewUser {
            id: None,
            name: "Jim",
        },
        NewUser {
            id: Some(123),
            name: "Bob",
        },
    ];
    assert_eq!(
        Ok(2),
        insert_into(users::table).values(&data).execute(&conn)
    );

    let users = users::table.load::<User>(&conn).unwrap();
    let jim = users.iter().find(|u| u.name == "Jim");
    let bob = users.iter().find(|u| u.name == "Bob");

    assert!(jim.is_some());
    assert_eq!(Some(&User::new(123, "Bob")), bob);
}

sql_function!(fn nextval(a: Text) -> Integer);

#[test]
#[cfg(feature = "postgres")]
fn derive_insertable_with_field_that_cannot_convert_expression_to_nullable() {
    #[derive(Insertable)]
    #[table_name = "users"]
    struct NewUser {
        id: nextval::HelperType<&'static str>,
        name: &'static str,
    }

    let conn = connection();
    let data = NewUser {
        id: nextval("users_id_seq"),
        name: "Jim",
    };
    assert_eq!(
        Ok(1),
        insert_into(users::table).values(&data).execute(&conn)
    );

    let users = users::table.load::<User>(&conn).unwrap();
    let jim = users.iter().find(|u| u.name == "Jim");

    assert!(jim.is_some());
}

#[test]
fn nested_queryable_derives() {
    #[derive(Queryable, Debug, PartialEq)]
    struct UserAndPost {
        user: User,
        post: Post,
    }

    let conn = connection_with_sean_and_tess_in_users_table();
    let sean = find_user_by_name("Sean", &conn);
    insert_into(posts::table)
        .values(&sean.new_post("Hi", None))
        .execute(&conn)
        .unwrap();
    let post = posts::table.first(&conn).unwrap();

    let expected = UserAndPost { user: sean, post };
    let actual = users::table.inner_join(posts::table).get_result(&conn);

    assert_eq!(Ok(expected), actual);
}
<commit_msg>Fix a unreleated compilation test failure caused by a new beta lint<commit_after>use crate::schema::*;
use diesel::sql_types::Text;
use diesel::*;

#[test]
fn association_where_struct_name_doesnt_match_table_name() {
    #[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations)]
    #[belongs_to(Post)]
    #[table_name = "comments"]
    struct OtherComment {
        id: i32,
        post_id: i32,
    }

    let connection = connection_with_sean_and_tess_in_users_table();

    let sean = find_user_by_name("Sean", &connection);
    insert_into(posts::table)
        .values(&sean.new_post("Hello", None))
        .execute(&connection)
        .unwrap();
    let post = posts::table.first::<Post>(&connection).unwrap();
    insert_into(comments::table)
        .values(&NewComment(post.id, "comment"))
        .execute(&connection)
        .unwrap();

    let comment_text = OtherComment::belonging_to(&post)
        .select(comments::text)
        .first::<String>(&connection);
    assert_eq!(Ok("comment".into()), comment_text);
}

#[test]
#[cfg(not(any(feature = "sqlite", feature = "mysql")))]
fn association_where_parent_and_child_have_underscores() {
    #[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations)]
    #[belongs_to(User)]
    pub struct SpecialPost {
        id: i32,
        user_id: i32,
        title: String,
    }

    #[derive(Insertable)]
    #[table_name = "special_posts"]
    struct NewSpecialPost {
        user_id: i32,
        title: String,
    }

    impl SpecialPost {
        fn new(user_id: i32, title: &str) -> NewSpecialPost {
            NewSpecialPost {
                user_id: user_id,
                title: title.to_owned(),
            }
        }
    }

    #[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations)]
    #[belongs_to(SpecialPost)]
    struct SpecialComment {
        id: i32,
        special_post_id: i32,
    }

    impl SpecialComment {
        fn new(special_post_id: i32) -> NewSpecialComment {
            NewSpecialComment {
                special_post_id: special_post_id,
            }
        }
    }

    #[derive(Insertable)]
    #[table_name = "special_comments"]
    struct NewSpecialComment {
        special_post_id: i32,
    }

    let connection = connection_with_sean_and_tess_in_users_table();

    let sean = find_user_by_name("Sean", &connection);
    let new_post = SpecialPost::new(sean.id, "title");
    let special_post: SpecialPost = insert_into(special_posts::table)
        .values(&new_post)
        .get_result(&connection)
        .unwrap();
    let new_comment = SpecialComment::new(special_post.id);
    insert_into(special_comments::table)
        .values(&new_comment)
        .execute(&connection)
        .unwrap();

    let comment: SpecialComment = SpecialComment::belonging_to(&special_post)
        .first(&connection)
        .unwrap();

    assert_eq!(special_post.id, comment.special_post_id);
}

// This module has no test functions, as it's only to test compilation.
mod associations_can_have_nullable_foreign_keys {
    #![allow(dead_code)]

    table! {
        foos{
            id -> Integer,
        }
    }

    table! {
        bars {
            id -> Integer,
            foo_id -> Nullable<Integer>,
        }
    }
    // This test has no assertions, as it is for compilation purposes only.
    #[derive(Identifiable)]
    pub struct Foo {
        id: i32,
    }

    #[derive(Identifiable, Associations)]
    #[belongs_to(Foo)]
    pub struct Bar {
        id: i32,
        foo_id: Option<i32>,
    }
}

// This module has no test functions, as it's only to test compilation.
mod multiple_lifetimes_in_insertable_struct_definition {
    #![allow(dead_code)]
    use crate::schema::posts;

    #[derive(Insertable)]
    #[table_name = "posts"]
    pub struct MyPost<'a> {
        title: &'a str,
        body: &'a str,
    }
}

mod lifetimes_with_names_other_than_a {
    #![allow(dead_code)]
    use crate::schema::posts;

    #[derive(Insertable)]
    #[table_name = "posts"]
    pub struct MyPost<'a, 'b> {
        id: i32,
        title: &'b str,
        body: &'a str,
    }
}

mod insertable_with_cow {
    #![allow(dead_code)]
    use crate::schema::posts;
    use std::borrow::Cow;

    #[derive(Insertable)]
    #[table_name = "posts"]
    pub struct MyPost<'a> {
        id: i32,
        title: Cow<'a, str>,
        body: Cow<'a, str>,
    }
}

mod custom_foreign_keys_are_respected_on_belongs_to {
    #![allow(dead_code)]

    use crate::schema::User;

    table! { special_posts { id -> Integer, author_id -> Integer, } }

    #[derive(Identifiable, Associations)]
    #[belongs_to(User, foreign_key = "author_id")]
    pub struct SpecialPost {
        id: i32,
        author_id: i32,
    }
}

mod derive_identifiable_with_lifetime {
    #![allow(dead_code)]
    use crate::schema::posts;

    #[derive(Identifiable)]
    pub struct Post<'a> {
        id: &'a i32,
    }
}

#[test]
fn derive_identifiable_with_non_standard_pk() {
    use diesel::associations::*;

    #[derive(Identifiable)]
    #[table_name = "posts"]
    #[primary_key(foo_id)]
    #[allow(dead_code)]
    struct Foo<'a> {
        id: i32,
        foo_id: &'a str,
        foo: i32,
    }

    let foo1 = Foo {
        id: 1,
        foo_id: "hi",
        foo: 2,
    };
    let foo2 = Foo {
        id: 2,
        foo_id: "there",
        foo: 3,
    };
    assert_eq!(&"hi", foo1.id());
    assert_eq!(&"there", foo2.id());
    // Fails to compile if wrong table is generated.
    let _: posts::table = Foo::<'static>::table();
}

#[test]
fn derive_identifiable_with_composite_pk() {
    use diesel::associations::Identifiable;

    #[derive(Identifiable)]
    #[primary_key(foo_id, bar_id)]
    #[table_name = "posts"]
    #[allow(dead_code)]
    struct Foo {
        id: i32,
        foo_id: i32,
        bar_id: i32,
        foo: i32,
    }

    let foo1 = Foo {
        id: 1,
        foo_id: 2,
        bar_id: 3,
        foo: 4,
    };
    let foo2 = Foo {
        id: 5,
        foo_id: 6,
        bar_id: 7,
        foo: 8,
    };
    assert_eq!((&2, &3), foo1.id());
    assert_eq!((&6, &7), foo2.id());
}

#[test]
fn derive_insertable_with_option_for_not_null_field_with_default() {
    #[derive(Insertable)]
    #[table_name = "users"]
    struct NewUser {
        id: Option<i32>,
        name: &'static str,
    }

    let conn = connection();
    let data = vec![
        NewUser {
            id: None,
            name: "Jim",
        },
        NewUser {
            id: Some(123),
            name: "Bob",
        },
    ];
    assert_eq!(
        Ok(2),
        insert_into(users::table).values(&data).execute(&conn)
    );

    let users = users::table.load::<User>(&conn).unwrap();
    let jim = users.iter().find(|u| u.name == "Jim");
    let bob = users.iter().find(|u| u.name == "Bob");

    assert!(jim.is_some());
    assert_eq!(Some(&User::new(123, "Bob")), bob);
}

sql_function!(fn nextval(a: Text) -> Integer);

#[test]
#[cfg(feature = "postgres")]
fn derive_insertable_with_field_that_cannot_convert_expression_to_nullable() {
    #[derive(Insertable)]
    #[table_name = "users"]
    struct NewUser {
        id: nextval::HelperType<&'static str>,
        name: &'static str,
    }

    let conn = connection();
    let data = NewUser {
        id: nextval("users_id_seq"),
        name: "Jim",
    };
    assert_eq!(
        Ok(1),
        insert_into(users::table).values(&data).execute(&conn)
    );

    let users = users::table.load::<User>(&conn).unwrap();
    let jim = users.iter().find(|u| u.name == "Jim");

    assert!(jim.is_some());
}

#[test]
fn nested_queryable_derives() {
    #[derive(Queryable, Debug, PartialEq)]
    struct UserAndPost {
        user: User,
        post: Post,
    }

    let conn = connection_with_sean_and_tess_in_users_table();
    let sean = find_user_by_name("Sean", &conn);
    insert_into(posts::table)
        .values(&sean.new_post("Hi", None))
        .execute(&conn)
        .unwrap();
    let post = posts::table.first(&conn).unwrap();

    let expected = UserAndPost { user: sean, post };
    let actual = users::table.inner_join(posts::table).get_result(&conn);

    assert_eq!(Ok(expected), actual);
}
<|endoftext|>


<commit_before>//! This is the actual Bot module. For ergonomic reasons there is a RcBot which composes the real
//! bot as an underlying field. You should always use RcBot.

use objects;
use error::Error;

use std::str;
use std::time::Duration;
use std::collections::HashMap;
use std::rc::Rc;
use std::cell::{RefCell, Cell};
use std::sync::{Arc, Mutex};

use curl::easy::{Easy, List, InfoType};
use tokio_curl::Session;
use tokio_core::reactor::{Handle, Interval};
use serde::Deserialize;
use serde_json;
use futures::{Future, IntoFuture, Stream, stream};
use futures::sync::mpsc;
use futures::sync::mpsc::UnboundedSender;

/// A clonable, single threaded bot
///
/// The outer API gets implemented on RcBot
#[derive(Clone)]
pub struct RcBot {
    pub inner: Rc<Bot>,
}

impl RcBot {
    pub fn new<'a>(handle: Handle, key: &str) -> impl Future<Item = RcBot, Error = Error> + 'a {
        use functions::FunctionGetMe;
        let bot = RcBot { inner: Rc::new(Bot::new(handle, key)) };
        bot.get_me().send().map(|(mut bot, me)| {
            Rc::get_mut(&mut bot.inner).as_mut().unwrap().id = me.id;
            Rc::get_mut(&mut bot.inner).as_mut().unwrap().username = me.username.unwrap();
            bot
        })
    }
}

/// The main bot structure
pub struct Bot {
    pub key: String,
    pub handle: Handle,
    pub last_id: Cell<u32>,
    pub update_interval: Cell<u64>,
    pub handlers: RefCell<HashMap<String, UnboundedSender<(RcBot, objects::Message)>>>,
    pub session: Session,
    pub username: String,
    pub id: i64,
}

impl Bot {
    pub fn new(handle: Handle, key: &str) -> Bot {
        Bot {
            handle: handle.clone(),
            key: key.into(),
            last_id: Cell::new(0),
            update_interval: Cell::new(1000),
            handlers: RefCell::new(HashMap::new()),
            session: Session::new(handle.clone()),
            username: String::new(),
            id: 0,
        }
    }

    /// Creates a new request and adds a JSON message to it. The returned Future contains a the
    /// reply as a string.  This method should be used if no file is added because a JSON msg is
    /// always compacter than a formdata one.
    pub fn fetch_json<'a, T: Deserialize + 'a>(
        &self,
        func: &str,
        msg: &str,
    ) -> impl Future<Item = T, Error = Error> + 'a {
        println!("Send JSON: {}", msg);

        let mut header = List::new();
        header.append("Content-Type: application/json").unwrap();

        let mut a = Easy::new();
        a.http_headers(header).unwrap();
        a.post_fields_copy(msg.as_bytes()).unwrap();
        a.post(true).unwrap();

        self._fetch(func, a)
    }

    /// calls cURL and parses the result for an error
    pub fn _fetch<'a, T: Deserialize + 'a>(
        &self,
        func: &str,
        mut a: Easy,
    ) -> impl Future<Item = T, Error = Error> + 'a {
        let result = Arc::new(Mutex::new(Vec::new()));

        a.url(&format!(
            "https://api.telegram.org/bot{}/{}",
            self.key,
            func
        )).unwrap();

        let r2 = result.clone();
        a.write_function(move |data| {
            r2.lock().unwrap().extend_from_slice(data);
            Ok(data.len())
        }).unwrap();

        // print debug information
        a.debug_function(|info, data| {
            match info {
                InfoType::DataOut => {
                    println!("DataOut");
                }
                InfoType::Text => {
                    println!("Text");
                }
                InfoType::HeaderOut => {
                    println!("HeaderOut");
                }
                InfoType::SslDataOut => {
                    println!("SslDataOut");
                }
                _ => println!("something else"),
            }

            println!("{:?}", String::from_utf8_lossy(data));
        }).unwrap();

        self.session.perform(a).map_err(|e| e.into()).and_then(
            move |_| {
                let response = result.lock().unwrap();
                let response = str::from_utf8(&response).unwrap();
                let response: Response<T> = serde_json::from_str(&response)?;
                if response.ok {
                    Ok(response.result.unwrap())
                } else {
                    Err(Error::Telegram(
                        response.error_code.unwrap(),
                        response.description.unwrap(),
                        response.parameters,
                    ))
                }
            },
        )
    }
}

#[derive(Deserialize)]
struct Response<T: Deserialize> {
    ok: bool,
    result: Option<T>,
    error_code: Option<u32>,
    description: Option<String>,
    parameters: Option<objects::ResponseParameters>,
}

impl RcBot {
    /// Sets the update interval to an integer in milliseconds
    pub fn update_interval(self, interval: u64) -> RcBot {
        self.inner.update_interval.set(interval);

        self
    }

    /// Creates a new command and returns a stream which
    /// will yield a message when the command is send
    pub fn new_cmd(
        &self,
        cmd: &str,
    ) -> impl Stream<Item = (RcBot, objects::Message), Error = Error> {
        let (sender, receiver) = mpsc::unbounded();

        self.inner.handlers.borrow_mut().insert(cmd.into(), sender);

        receiver.map_err(|_| Error::Unknown)
    }

    /// Register a new commnd
    pub fn register<T>(&self, hnd: T)
    where
        T: Stream + 'static,
    {
        self.inner.handle.spawn(
            hnd.for_each(|_| Ok(()))
                .into_future()
                .map(|_| ())
                .map_err(|_| ()),
        );
    }

    /// The main update loop, the update function is called every update_interval milliseconds
    /// When an update is available the last_id will be updated and the message is filtered
    /// for commands
    /// The message is forwarded to the returned stream if no command was found
    pub fn get_stream<'a>(
        &'a self,
    ) -> impl Stream<Item = (RcBot, objects::Update), Error = Error> + 'a {
        use functions::*;

        Interval::new(
            Duration::from_millis(self.inner.update_interval.get()),
            &self.inner.handle,
        ).unwrap()
            .map_err(|_| Error::Unknown)
            .and_then(move |_| {
                self.get_updates().offset(self.inner.last_id.get()).send()
            })
            .map(|(_, x)| {
                stream::iter(x.0.into_iter().map(|x| Ok(x)).collect::<Vec<
                    Result<
                        objects::Update,
                        Error,
                    >,
                >>())
            })
            .flatten()
            .and_then(move |x| {
                if self.inner.last_id.get() < x.update_id as u32 + 1 {
                    self.inner.last_id.set(x.update_id as u32 + 1);
                }

                Ok(x)
            })
            .filter_map(move |mut val| {
                let mut forward: Option<String> = None;

                if let Some(ref mut message) = val.message {
                    if let Some(text) = message.text.clone() {
                        let mut content = text.split_whitespace();
                        if let Some(cmd) = content.next() {
                            let s: Vec<&str> = cmd.split("@").take(2).collect();
                            if s.len() > 0 && (s.len() < 2 || s[1] == self.inner.username) &&
                                self.inner.handlers.borrow().contains_key(s[0])
                            {
                                message.text = Some(content.collect::<Vec<&str>>().join(" "));

                                forward = Some(s[0].into());
                            }
                        }
                    }
                }

                if let Some(cmd) = forward {
                    if let Some(sender) = self.inner.handlers.borrow_mut().get_mut(&cmd) {
                        sender.send((self.clone(), val.message.unwrap())).unwrap();
                    }
                    return None;
                } else {
                    return Some((self.clone(), val));
                }
            })
    }
}
<commit_msg>Add a timeout to `getUpdates`<commit_after>//! This is the actual Bot module. For ergonomic reasons there is a RcBot which composes the real
//! bot as an underlying field. You should always use RcBot.

use objects;
use error::Error;

use std::str;
use std::time::Duration;
use std::collections::HashMap;
use std::rc::Rc;
use std::cell::{RefCell, Cell};
use std::sync::{Arc, Mutex};

use curl::easy::{Easy, List};
use tokio_curl::Session;
use tokio_core::reactor::{Handle, Interval};
use serde::Deserialize;
use serde_json;
use futures::{Future, IntoFuture, Stream, stream};
use futures::sync::mpsc;
use futures::sync::mpsc::UnboundedSender;

/// A clonable, single threaded bot
///
/// The outer API gets implemented on RcBot
#[derive(Clone)]
pub struct RcBot {
    pub inner: Rc<Bot>,
}

impl RcBot {
    pub fn new<'a>(handle: Handle, key: &str) -> impl Future<Item = RcBot, Error = Error> + 'a {
        use functions::FunctionGetMe;
        let bot = RcBot { inner: Rc::new(Bot::new(handle, key)) };
        bot.get_me().send().map(|(mut bot, me)| {
            Rc::get_mut(&mut bot.inner).as_mut().unwrap().id = me.id;
            Rc::get_mut(&mut bot.inner).as_mut().unwrap().username = me.username.unwrap();
            bot
        })
    }
}

/// The main bot structure
pub struct Bot {
    pub key: String,
    pub handle: Handle,
    pub last_id: Cell<u32>,
    pub update_interval: Cell<u64>,
    pub handlers: RefCell<HashMap<String, UnboundedSender<(RcBot, objects::Message)>>>,
    pub session: Session,
    pub username: String,
    pub id: i64,
}

impl Bot {
    pub fn new(handle: Handle, key: &str) -> Bot {
        Bot {
            handle: handle.clone(),
            key: key.into(),
            last_id: Cell::new(0),
            update_interval: Cell::new(1000),
            handlers: RefCell::new(HashMap::new()),
            session: Session::new(handle.clone()),
            username: String::new(),
            id: 0,
        }
    }

    /// Creates a new request and adds a JSON message to it. The returned Future contains a the
    /// reply as a string.  This method should be used if no file is added because a JSON msg is
    /// always compacter than a formdata one.
    pub fn fetch_json<'a, T: Deserialize + 'a>(
        &self,
        func: &str,
        msg: &str,
    ) -> impl Future<Item = T, Error = Error> + 'a {
        println!("Send JSON: {}", msg);

        let mut header = List::new();
        header.append("Content-Type: application/json").unwrap();

        let mut req = Easy::new();
        req.http_headers(header).unwrap();
        req.post_fields_copy(msg.as_bytes()).unwrap();
        req.post(true).unwrap();

        self.fetch(func, req)
    }

    /// calls cURL and parses the result for an error
    pub fn fetch<'a, T: Deserialize + 'a>(
        &self,
        func: &str,
        mut req: Easy,
    ) -> impl Future<Item = T, Error = Error> + 'a {
        let result = Arc::new(Mutex::new(Vec::new()));

        req.url(&format!(
            "https://api.telegram.org/bot{}/{}",
            self.key,
            func
        )).unwrap();

        let r2 = result.clone();
        req.write_function(move |data| {
            r2.lock().unwrap().extend_from_slice(data);
            Ok(data.len())
        }).unwrap();

        self.session.perform(req).map_err(|e| e.into()).and_then(
            move |_| {
                let response = result.lock().unwrap();
                let response = str::from_utf8(&response).unwrap();
                let response: Response<T> = serde_json::from_str(&response)?;
                if response.ok {
                    Ok(response.result.unwrap())
                } else {
                    Err(Error::Telegram(
                        response.error_code.unwrap(),
                        response.description.unwrap(),
                        response.parameters,
                    ))
                }
            },
        )
    }
}

#[derive(Deserialize)]
struct Response<T: Deserialize> {
    ok: bool,
    result: Option<T>,
    error_code: Option<u32>,
    description: Option<String>,
    parameters: Option<objects::ResponseParameters>,
}

impl RcBot {
    /// Sets the update interval to an integer in milliseconds
    pub fn update_interval(self, interval: u64) -> RcBot {
        self.inner.update_interval.set(interval);

        self
    }

    /// Creates a new command and returns a stream which
    /// will yield a message when the command is send
    pub fn new_cmd(
        &self,
        cmd: &str,
    ) -> impl Stream<Item = (RcBot, objects::Message), Error = Error> {
        let (sender, receiver) = mpsc::unbounded();

        self.inner.handlers.borrow_mut().insert(cmd.into(), sender);

        receiver.map_err(|_| Error::Unknown)
    }

    /// Register a new commnd
    pub fn register<T>(&self, hnd: T)
    where
        T: Stream + 'static,
    {
        self.inner.handle.spawn(
            hnd.for_each(|_| Ok(()))
                .into_future()
                .map(|_| ())
                .map_err(|_| ()),
        );
    }

    /// The main update loop, the update function is called every update_interval milliseconds
    /// When an update is available the last_id will be updated and the message is filtered
    /// for commands
    /// The message is forwarded to the returned stream if no command was found
    pub fn get_stream<'a>(
        &'a self,
    ) -> impl Stream<Item = (RcBot, objects::Update), Error = Error> + 'a {
        use functions::*;

        Interval::new(
            Duration::from_millis(self.inner.update_interval.get()),
            &self.inner.handle,
        ).unwrap()
            .map_err(|_| Error::Unknown)
            .and_then(move |_| {
                self.get_updates()
                    .offset(self.inner.last_id.get())
                    .timeout(60)
                    .send()
            })
            .map(|(_, x)| {
                stream::iter(x.0.into_iter().map(|x| Ok(x)).collect::<Vec<
                    Result<
                        objects::Update,
                        Error,
                    >,
                >>())
            })
            .flatten()
            .and_then(move |x| {
                if self.inner.last_id.get() < x.update_id as u32 + 1 {
                    self.inner.last_id.set(x.update_id as u32 + 1);
                }

                Ok(x)
            })
            .filter_map(move |mut val| {
                let mut forward: Option<String> = None;

                if let Some(ref mut message) = val.message {
                    if let Some(text) = message.text.clone() {
                        let mut content = text.split_whitespace();
                        if let Some(cmd) = content.next() {
                            let s: Vec<&str> = cmd.split("@").take(2).collect();
                            if s.len() > 0 && (s.len() < 2 || s[1] == self.inner.username) &&
                                self.inner.handlers.borrow().contains_key(s[0])
                            {
                                message.text = Some(content.collect::<Vec<&str>>().join(" "));

                                forward = Some(s[0].into());
                            }
                        }
                    }
                }

                if let Some(cmd) = forward {
                    if let Some(sender) = self.inner.handlers.borrow_mut().get_mut(&cmd) {
                        sender.send((self.clone(), val.message.unwrap())).unwrap();
                    }
                    return None;
                } else {
                    return Some((self.clone(), val));
                }
            })
    }
}
<|endoftext|>


<commit_before>use super::*;

#[test]
fn macro_rules_are_globally_visible() {
    let map = def_map(
        r"
        //- /lib.rs
        macro_rules! structs {
            ($($i:ident),*) => {
                $(struct $i { field: u32 } )*
            }
        }
        structs!(Foo);
        mod nested;

        //- /nested.rs
        structs!(Bar, Baz);
        ",
    );
    assert_snapshot!(map, @r###"
   ⋮crate
   ⋮Foo: t v
   ⋮nested: t
   ⋮
   ⋮crate::nested
   ⋮Bar: t v
   ⋮Baz: t v
    "###);
}

#[test]
fn macro_rules_can_define_modules() {
    let map = def_map(
        r"
        //- /lib.rs
        macro_rules! m {
            ($name:ident) => { mod $name;  }
        }
        m!(n1);

        mod m {
            m!(n3)
        }

        //- /n1.rs
        m!(n2)
        //- /n1/n2.rs
        struct X;
        //- /m/n3.rs
        struct Y;
        ",
    );
    assert_snapshot!(map, @r###"
        ⋮crate
        ⋮m: t
        ⋮n1: t
        ⋮
        ⋮crate::m
        ⋮n3: t
        ⋮
        ⋮crate::m::n3
        ⋮Y: t v
        ⋮
        ⋮crate::n1
        ⋮n2: t
        ⋮
        ⋮crate::n1::n2
        ⋮X: t v
    "###);
}

#[test]
fn macro_rules_from_other_crates_are_visible() {
    let map = def_map(
        "
        //- /main.rs crate:main deps:foo
        foo::structs!(Foo, Bar)
        mod bar;

        //- /bar.rs
        use crate::*;

        //- /lib.rs crate:foo
        #[macro_export]
        macro_rules! structs {
            ($($i:ident),*) => {
                $(struct $i { field: u32 } )*
            }
        }
        ",
    );
    assert_snapshot!(map, @r###"
   ⋮crate
   ⋮Bar: t v
   ⋮Foo: t v
   ⋮bar: t
   ⋮
   ⋮crate::bar
   ⋮Bar: t v
   ⋮Foo: t v
   ⋮bar: t
    "###);
}

#[test]
fn macro_rules_export_with_local_inner_macros_are_visible() {
    let map = def_map(
        "
        //- /main.rs crate:main deps:foo
        foo::structs!(Foo, Bar)
        mod bar;

        //- /bar.rs
        use crate::*;

        //- /lib.rs crate:foo
        #[macro_export(local_inner_macros)]
        macro_rules! structs {
            ($($i:ident),*) => {
                $(struct $i { field: u32 } )*
            }
        }
        ",
    );
    assert_snapshot!(map, @r###"
   ⋮crate
   ⋮Bar: t v
   ⋮Foo: t v
   ⋮bar: t
   ⋮
   ⋮crate::bar
   ⋮Bar: t v
   ⋮Foo: t v
   ⋮bar: t
    "###);
}

#[test]
fn unexpanded_macro_should_expand_by_fixedpoint_loop() {
    let map = def_map(
        "
        //- /main.rs crate:main deps:foo
        macro_rules! baz {
            () => {
                use foo::bar;
            }
        }

        foo!();
        bar!();
        baz!();

        //- /lib.rs crate:foo
        #[macro_export]
        macro_rules! foo {
            () => {
                struct Foo { field: u32 }
            }
        }
        #[macro_export]
        macro_rules! bar {
            () => {
                use foo::foo;
            }
        }
        ",
    );
    assert_snapshot!(map, @r###"
   ⋮crate
   ⋮Foo: t v
   ⋮bar: m
   ⋮foo: m
    "###);
}

#[test]
fn macro_rules_from_other_crates_are_visible_with_macro_use() {
    covers!(macro_rules_from_other_crates_are_visible_with_macro_use);
    let map = def_map(
        "
        //- /main.rs crate:main deps:foo
        structs!(Foo);
        structs_priv!(Bar);
        structs_not_exported!(MacroNotResolved1);
        crate::structs!(MacroNotResolved2);

        mod bar;

        #[macro_use]
        extern crate foo;

        //- /bar.rs
        structs!(Baz);
        crate::structs!(MacroNotResolved3);

        //- /lib.rs crate:foo
        #[macro_export]
        macro_rules! structs {
            ($i:ident) => { struct $i; }
        }

        macro_rules! structs_not_exported {
            ($i:ident) => { struct $i; }
        }

        mod priv_mod {
            #[macro_export]
            macro_rules! structs_priv {
                ($i:ident) => { struct $i; }
            }
        }
        ",
    );
    assert_snapshot!(map, @r###"
   ⋮crate
   ⋮Bar: t v
   ⋮Foo: t v
   ⋮bar: t
   ⋮foo: t
   ⋮
   ⋮crate::bar
   ⋮Baz: t v
    "###);
}

#[test]
fn prelude_is_macro_use() {
    covers!(prelude_is_macro_use);
    let map = def_map(
        "
        //- /main.rs crate:main deps:foo
        structs!(Foo);
        structs_priv!(Bar);
        structs_outside!(Out);
        crate::structs!(MacroNotResolved2);

        mod bar;

        //- /bar.rs
        structs!(Baz);
        crate::structs!(MacroNotResolved3);

        //- /lib.rs crate:foo
        #[prelude_import]
        use self::prelude::*;

        mod prelude {
            #[macro_export]
            macro_rules! structs {
                ($i:ident) => { struct $i; }
            }

            mod priv_mod {
                #[macro_export]
                macro_rules! structs_priv {
                    ($i:ident) => { struct $i; }
                }
            }
        }

        #[macro_export]
        macro_rules! structs_outside {
            ($i:ident) => { struct $i; }
        }
        ",
    );
    assert_snapshot!(map, @r###"
   ⋮crate
   ⋮Bar: t v
   ⋮Foo: t v
   ⋮Out: t v
   ⋮bar: t
   ⋮
   ⋮crate::bar
   ⋮Baz: t v
    "###);
}

#[test]
fn prelude_cycle() {
    let map = def_map(
        "
        //- /lib.rs
        #[prelude_import]
        use self::prelude::*;

        declare_mod!();

        mod prelude {
            macro_rules! declare_mod {
                () => (mod foo {})
            }
        }
        ",
    );
    assert_snapshot!(map, @r###"
        ⋮crate
        ⋮prelude: t
        ⋮
        ⋮crate::prelude
    "###);
}

#[test]
fn plain_macros_are_legacy_textual_scoped() {
    let map = def_map(
        r#"
        //- /main.rs
        mod m1;
        bar!(NotFoundNotMacroUse);

        mod m2 {
            foo!(NotFoundBeforeInside2);
        }

        macro_rules! foo {
            ($x:ident) => { struct $x; }
        }
        foo!(Ok);

        mod m3;
        foo!(OkShadowStop);
        bar!(NotFoundMacroUseStop);

        #[macro_use]
        mod m5 {
            #[macro_use]
            mod m6 {
                macro_rules! foo {
                    ($x:ident) => { fn $x() {} }
                }
            }
        }
        foo!(ok_double_macro_use_shadow);

        baz!(NotFoundBefore);
        #[macro_use]
        mod m7 {
            macro_rules! baz {
                ($x:ident) => { struct $x; }
            }
        }
        baz!(OkAfter);

        //- /m1.rs
        foo!(NotFoundBeforeInside1);
        macro_rules! bar {
            ($x:ident) => { struct $x; }
        }

        //- /m3/mod.rs
        foo!(OkAfterInside);
        macro_rules! foo {
            ($x:ident) => { fn $x() {} }
        }
        foo!(ok_shadow);

        #[macro_use]
        mod m4;
        bar!(OkMacroUse);

        //- /m3/m4.rs
        foo!(ok_shadow_deep);
        macro_rules! bar {
            ($x:ident) => { struct $x; }
        }
        "#,
    );
    assert_snapshot!(map, @r###"
   ⋮crate
   ⋮Ok: t v
   ⋮OkAfter: t v
   ⋮OkShadowStop: t v
   ⋮m1: t
   ⋮m2: t
   ⋮m3: t
   ⋮m5: t
   ⋮m7: t
   ⋮ok_double_macro_use_shadow: v
   ⋮
   ⋮crate::m7
   ⋮
   ⋮crate::m1
   ⋮
   ⋮crate::m5
   ⋮m6: t
   ⋮
   ⋮crate::m5::m6
   ⋮
   ⋮crate::m2
   ⋮
   ⋮crate::m3
   ⋮OkAfterInside: t v
   ⋮OkMacroUse: t v
   ⋮m4: t
   ⋮ok_shadow: v
   ⋮
   ⋮crate::m3::m4
   ⋮ok_shadow_deep: v
    "###);
}

#[test]
fn type_value_macro_live_in_different_scopes() {
    let map = def_map(
        "
        //- /main.rs
        #[macro_export]
        macro_rules! foo {
            ($x:ident) => { type $x = (); }
        }

        foo!(foo);
        use foo as bar;

        use self::foo as baz;
        fn baz() {}
        ",
    );
    assert_snapshot!(map, @r###"
        ⋮crate
        ⋮bar: t m
        ⋮baz: t v m
        ⋮foo: t m
    "###);
}

#[test]
fn macro_use_can_be_aliased() {
    let map = def_map(
        "
        //- /main.rs crate:main deps:foo
        #[macro_use]
        extern crate foo;

        foo!(Direct);
        bar!(Alias);

        //- /lib.rs crate:foo
        use crate::foo as bar;

        mod m {
            #[macro_export]
            macro_rules! foo {
                ($x:ident) => { struct $x; }
            }
        }
        ",
    );
    assert_snapshot!(map, @r###"
        ⋮crate
        ⋮Alias: t v
        ⋮Direct: t v
        ⋮foo: t
    "###);
}

#[test]
fn path_qualified_macros() {
    let map = def_map(
        "
        //- /main.rs
        macro_rules! foo {
            ($x:ident) => { struct $x; }
        }

        crate::foo!(NotResolved);

        crate::bar!(OkCrate);
        bar!(OkPlain);
        alias1!(NotHere);
        m::alias1!(OkAliasPlain);
        m::alias2!(OkAliasSuper);
        m::alias3!(OkAliasCrate);
        not_found!(NotFound);

        mod m {
            #[macro_export]
            macro_rules! bar {
                ($x:ident) => { struct $x; }
            }

            pub use bar as alias1;
            pub use super::bar as alias2;
            pub use crate::bar as alias3;
            pub use self::bar as not_found;
        }
        ",
    );
    assert_snapshot!(map, @r###"
        ⋮crate
        ⋮OkAliasCrate: t v
        ⋮OkAliasPlain: t v
        ⋮OkAliasSuper: t v
        ⋮OkCrate: t v
        ⋮OkPlain: t v
        ⋮bar: m
        ⋮m: t
        ⋮
        ⋮crate::m
        ⋮alias1: m
        ⋮alias2: m
        ⋮alias3: m
        ⋮not_found: _
    "###);
}

#[test]
fn macro_dollar_crate_is_correct_in_item() {
    covers!(macro_dollar_crate_self);
    covers!(macro_dollar_crate_other);
    let map = def_map(
        "
        //- /main.rs crate:main deps:foo
        #[macro_use]
        extern crate foo;

        #[macro_use]
        mod m {
            macro_rules! current {
                () => {
                    use $crate::Foo as FooSelf;
                }
            }
        }

        struct Foo;

        current!();
        not_current1!();
        foo::not_current2!();

        //- /lib.rs crate:foo
        mod m {
            #[macro_export]
            macro_rules! not_current1 {
                () => {
                    use $crate::Bar;
                }
            }
        }

        #[macro_export]
        macro_rules! not_current2 {
            () => {
                use $crate::Baz;
            }
        }

        struct Bar;
        struct Baz;
        ",
    );
    assert_snapshot!(map, @r###"
        ⋮crate
        ⋮Bar: t v
        ⋮Baz: t v
        ⋮Foo: t v
        ⋮FooSelf: t v
        ⋮foo: t
        ⋮m: t
        ⋮
        ⋮crate::m
    "###);
}

#[test]
fn macro_dollar_crate_is_correct_in_indirect_deps() {
    covers!(macro_dollar_crate_other);
    // From std
    let map = def_map(
        r#"
        //- /main.rs crate:main deps:std
        foo!();

        //- /std.rs crate:std deps:core
        #[prelude_import]
        use self::prelude::*;

        pub use core::foo;

        mod prelude {}

        #[macro_use]
        mod std_macros;

        //- /core.rs crate:core
        #[macro_export]
        macro_rules! foo {
            () => {
                use $crate::bar;
            }
        }

        pub struct bar;
        "#,
    );
    assert_snapshot!(map, @r###"
        ⋮crate
        ⋮bar: t v
    "###);
}

#[test]
fn expand_derive() {
    let map = compute_crate_def_map(
        "
        //- /main.rs
        #[derive(Clone)]
        struct Foo;
        ",
    );
    assert_eq!(map.modules[map.root].scope.impls().len(), 1);
}

#[test]
fn expand_multiple_derive() {
    let map = compute_crate_def_map(
        "
        //- /main.rs
        #[derive(Copy, Clone)]
        struct Foo;
        ",
    );
    assert_eq!(map.modules[map.root].scope.impls().len(), 2);
}
<commit_msg>Add test in name resolutions<commit_after>use super::*;

#[test]
fn macro_rules_are_globally_visible() {
    let map = def_map(
        r"
        //- /lib.rs
        macro_rules! structs {
            ($($i:ident),*) => {
                $(struct $i { field: u32 } )*
            }
        }
        structs!(Foo);
        mod nested;

        //- /nested.rs
        structs!(Bar, Baz);
        ",
    );
    assert_snapshot!(map, @r###"
   ⋮crate
   ⋮Foo: t v
   ⋮nested: t
   ⋮
   ⋮crate::nested
   ⋮Bar: t v
   ⋮Baz: t v
    "###);
}

#[test]
fn macro_rules_can_define_modules() {
    let map = def_map(
        r"
        //- /lib.rs
        macro_rules! m {
            ($name:ident) => { mod $name;  }
        }
        m!(n1);

        mod m {
            m!(n3)
        }

        //- /n1.rs
        m!(n2)
        //- /n1/n2.rs
        struct X;
        //- /m/n3.rs
        struct Y;
        ",
    );
    assert_snapshot!(map, @r###"
        ⋮crate
        ⋮m: t
        ⋮n1: t
        ⋮
        ⋮crate::m
        ⋮n3: t
        ⋮
        ⋮crate::m::n3
        ⋮Y: t v
        ⋮
        ⋮crate::n1
        ⋮n2: t
        ⋮
        ⋮crate::n1::n2
        ⋮X: t v
    "###);
}

#[test]
fn macro_rules_from_other_crates_are_visible() {
    let map = def_map(
        "
        //- /main.rs crate:main deps:foo
        foo::structs!(Foo, Bar)
        mod bar;

        //- /bar.rs
        use crate::*;

        //- /lib.rs crate:foo
        #[macro_export]
        macro_rules! structs {
            ($($i:ident),*) => {
                $(struct $i { field: u32 } )*
            }
        }
        ",
    );
    assert_snapshot!(map, @r###"
   ⋮crate
   ⋮Bar: t v
   ⋮Foo: t v
   ⋮bar: t
   ⋮
   ⋮crate::bar
   ⋮Bar: t v
   ⋮Foo: t v
   ⋮bar: t
    "###);
}

#[test]
fn macro_rules_export_with_local_inner_macros_are_visible() {
    let map = def_map(
        "
        //- /main.rs crate:main deps:foo
        foo::structs!(Foo, Bar)
        mod bar;

        //- /bar.rs
        use crate::*;

        //- /lib.rs crate:foo
        #[macro_export(local_inner_macros)]
        macro_rules! structs {
            ($($i:ident),*) => {
                $(struct $i { field: u32 } )*
            }
        }
        ",
    );
    assert_snapshot!(map, @r###"
   ⋮crate
   ⋮Bar: t v
   ⋮Foo: t v
   ⋮bar: t
   ⋮
   ⋮crate::bar
   ⋮Bar: t v
   ⋮Foo: t v
   ⋮bar: t
    "###);
}

#[test]
fn local_inner_macros_makes_local_macros_usable() {
    let map = def_map(
        "
        //- /main.rs crate:main deps:foo
        foo::structs!(Foo, Bar);
        mod bar;
        //- /bar.rs
        use crate::*;
        //- /lib.rs crate:foo
        #[macro_export(local_inner_macros)]
        macro_rules! structs {
            ($($i:ident),*) => {
                inner!($($i),*);
            }
        }
        #[macro_export]
        macro_rules! inner {
            ($($i:ident),*) => {
                $(struct $i { field: u32 } )*
            }
        }
        ",
    );
    assert_snapshot!(map, @r###"
   ⋮crate
   ⋮Bar: t v
   ⋮Foo: t v
   ⋮bar: t
   ⋮
   ⋮crate::bar
   ⋮Bar: t v
   ⋮Foo: t v
   ⋮bar: t
    "###);
}

#[test]
fn unexpanded_macro_should_expand_by_fixedpoint_loop() {
    let map = def_map(
        "
        //- /main.rs crate:main deps:foo
        macro_rules! baz {
            () => {
                use foo::bar;
            }
        }

        foo!();
        bar!();
        baz!();

        //- /lib.rs crate:foo
        #[macro_export]
        macro_rules! foo {
            () => {
                struct Foo { field: u32 }
            }
        }
        #[macro_export]
        macro_rules! bar {
            () => {
                use foo::foo;
            }
        }
        ",
    );
    assert_snapshot!(map, @r###"
   ⋮crate
   ⋮Foo: t v
   ⋮bar: m
   ⋮foo: m
    "###);
}

#[test]
fn macro_rules_from_other_crates_are_visible_with_macro_use() {
    covers!(macro_rules_from_other_crates_are_visible_with_macro_use);
    let map = def_map(
        "
        //- /main.rs crate:main deps:foo
        structs!(Foo);
        structs_priv!(Bar);
        structs_not_exported!(MacroNotResolved1);
        crate::structs!(MacroNotResolved2);

        mod bar;

        #[macro_use]
        extern crate foo;

        //- /bar.rs
        structs!(Baz);
        crate::structs!(MacroNotResolved3);

        //- /lib.rs crate:foo
        #[macro_export]
        macro_rules! structs {
            ($i:ident) => { struct $i; }
        }

        macro_rules! structs_not_exported {
            ($i:ident) => { struct $i; }
        }

        mod priv_mod {
            #[macro_export]
            macro_rules! structs_priv {
                ($i:ident) => { struct $i; }
            }
        }
        ",
    );
    assert_snapshot!(map, @r###"
   ⋮crate
   ⋮Bar: t v
   ⋮Foo: t v
   ⋮bar: t
   ⋮foo: t
   ⋮
   ⋮crate::bar
   ⋮Baz: t v
    "###);
}

#[test]
fn prelude_is_macro_use() {
    covers!(prelude_is_macro_use);
    let map = def_map(
        "
        //- /main.rs crate:main deps:foo
        structs!(Foo);
        structs_priv!(Bar);
        structs_outside!(Out);
        crate::structs!(MacroNotResolved2);

        mod bar;

        //- /bar.rs
        structs!(Baz);
        crate::structs!(MacroNotResolved3);

        //- /lib.rs crate:foo
        #[prelude_import]
        use self::prelude::*;

        mod prelude {
            #[macro_export]
            macro_rules! structs {
                ($i:ident) => { struct $i; }
            }

            mod priv_mod {
                #[macro_export]
                macro_rules! structs_priv {
                    ($i:ident) => { struct $i; }
                }
            }
        }

        #[macro_export]
        macro_rules! structs_outside {
            ($i:ident) => { struct $i; }
        }
        ",
    );
    assert_snapshot!(map, @r###"
   ⋮crate
   ⋮Bar: t v
   ⋮Foo: t v
   ⋮Out: t v
   ⋮bar: t
   ⋮
   ⋮crate::bar
   ⋮Baz: t v
    "###);
}

#[test]
fn prelude_cycle() {
    let map = def_map(
        "
        //- /lib.rs
        #[prelude_import]
        use self::prelude::*;

        declare_mod!();

        mod prelude {
            macro_rules! declare_mod {
                () => (mod foo {})
            }
        }
        ",
    );
    assert_snapshot!(map, @r###"
        ⋮crate
        ⋮prelude: t
        ⋮
        ⋮crate::prelude
    "###);
}

#[test]
fn plain_macros_are_legacy_textual_scoped() {
    let map = def_map(
        r#"
        //- /main.rs
        mod m1;
        bar!(NotFoundNotMacroUse);

        mod m2 {
            foo!(NotFoundBeforeInside2);
        }

        macro_rules! foo {
            ($x:ident) => { struct $x; }
        }
        foo!(Ok);

        mod m3;
        foo!(OkShadowStop);
        bar!(NotFoundMacroUseStop);

        #[macro_use]
        mod m5 {
            #[macro_use]
            mod m6 {
                macro_rules! foo {
                    ($x:ident) => { fn $x() {} }
                }
            }
        }
        foo!(ok_double_macro_use_shadow);

        baz!(NotFoundBefore);
        #[macro_use]
        mod m7 {
            macro_rules! baz {
                ($x:ident) => { struct $x; }
            }
        }
        baz!(OkAfter);

        //- /m1.rs
        foo!(NotFoundBeforeInside1);
        macro_rules! bar {
            ($x:ident) => { struct $x; }
        }

        //- /m3/mod.rs
        foo!(OkAfterInside);
        macro_rules! foo {
            ($x:ident) => { fn $x() {} }
        }
        foo!(ok_shadow);

        #[macro_use]
        mod m4;
        bar!(OkMacroUse);

        //- /m3/m4.rs
        foo!(ok_shadow_deep);
        macro_rules! bar {
            ($x:ident) => { struct $x; }
        }
        "#,
    );
    assert_snapshot!(map, @r###"
   ⋮crate
   ⋮Ok: t v
   ⋮OkAfter: t v
   ⋮OkShadowStop: t v
   ⋮m1: t
   ⋮m2: t
   ⋮m3: t
   ⋮m5: t
   ⋮m7: t
   ⋮ok_double_macro_use_shadow: v
   ⋮
   ⋮crate::m7
   ⋮
   ⋮crate::m1
   ⋮
   ⋮crate::m5
   ⋮m6: t
   ⋮
   ⋮crate::m5::m6
   ⋮
   ⋮crate::m2
   ⋮
   ⋮crate::m3
   ⋮OkAfterInside: t v
   ⋮OkMacroUse: t v
   ⋮m4: t
   ⋮ok_shadow: v
   ⋮
   ⋮crate::m3::m4
   ⋮ok_shadow_deep: v
    "###);
}

#[test]
fn type_value_macro_live_in_different_scopes() {
    let map = def_map(
        "
        //- /main.rs
        #[macro_export]
        macro_rules! foo {
            ($x:ident) => { type $x = (); }
        }

        foo!(foo);
        use foo as bar;

        use self::foo as baz;
        fn baz() {}
        ",
    );
    assert_snapshot!(map, @r###"
        ⋮crate
        ⋮bar: t m
        ⋮baz: t v m
        ⋮foo: t m
    "###);
}

#[test]
fn macro_use_can_be_aliased() {
    let map = def_map(
        "
        //- /main.rs crate:main deps:foo
        #[macro_use]
        extern crate foo;

        foo!(Direct);
        bar!(Alias);

        //- /lib.rs crate:foo
        use crate::foo as bar;

        mod m {
            #[macro_export]
            macro_rules! foo {
                ($x:ident) => { struct $x; }
            }
        }
        ",
    );
    assert_snapshot!(map, @r###"
        ⋮crate
        ⋮Alias: t v
        ⋮Direct: t v
        ⋮foo: t
    "###);
}

#[test]
fn path_qualified_macros() {
    let map = def_map(
        "
        //- /main.rs
        macro_rules! foo {
            ($x:ident) => { struct $x; }
        }

        crate::foo!(NotResolved);

        crate::bar!(OkCrate);
        bar!(OkPlain);
        alias1!(NotHere);
        m::alias1!(OkAliasPlain);
        m::alias2!(OkAliasSuper);
        m::alias3!(OkAliasCrate);
        not_found!(NotFound);

        mod m {
            #[macro_export]
            macro_rules! bar {
                ($x:ident) => { struct $x; }
            }

            pub use bar as alias1;
            pub use super::bar as alias2;
            pub use crate::bar as alias3;
            pub use self::bar as not_found;
        }
        ",
    );
    assert_snapshot!(map, @r###"
        ⋮crate
        ⋮OkAliasCrate: t v
        ⋮OkAliasPlain: t v
        ⋮OkAliasSuper: t v
        ⋮OkCrate: t v
        ⋮OkPlain: t v
        ⋮bar: m
        ⋮m: t
        ⋮
        ⋮crate::m
        ⋮alias1: m
        ⋮alias2: m
        ⋮alias3: m
        ⋮not_found: _
    "###);
}

#[test]
fn macro_dollar_crate_is_correct_in_item() {
    covers!(macro_dollar_crate_self);
    covers!(macro_dollar_crate_other);
    let map = def_map(
        "
        //- /main.rs crate:main deps:foo
        #[macro_use]
        extern crate foo;

        #[macro_use]
        mod m {
            macro_rules! current {
                () => {
                    use $crate::Foo as FooSelf;
                }
            }
        }

        struct Foo;

        current!();
        not_current1!();
        foo::not_current2!();

        //- /lib.rs crate:foo
        mod m {
            #[macro_export]
            macro_rules! not_current1 {
                () => {
                    use $crate::Bar;
                }
            }
        }

        #[macro_export]
        macro_rules! not_current2 {
            () => {
                use $crate::Baz;
            }
        }

        struct Bar;
        struct Baz;
        ",
    );
    assert_snapshot!(map, @r###"
        ⋮crate
        ⋮Bar: t v
        ⋮Baz: t v
        ⋮Foo: t v
        ⋮FooSelf: t v
        ⋮foo: t
        ⋮m: t
        ⋮
        ⋮crate::m
    "###);
}

#[test]
fn macro_dollar_crate_is_correct_in_indirect_deps() {
    covers!(macro_dollar_crate_other);
    // From std
    let map = def_map(
        r#"
        //- /main.rs crate:main deps:std
        foo!();

        //- /std.rs crate:std deps:core
        #[prelude_import]
        use self::prelude::*;

        pub use core::foo;

        mod prelude {}

        #[macro_use]
        mod std_macros;

        //- /core.rs crate:core
        #[macro_export]
        macro_rules! foo {
            () => {
                use $crate::bar;
            }
        }

        pub struct bar;
        "#,
    );
    assert_snapshot!(map, @r###"
        ⋮crate
        ⋮bar: t v
    "###);
}

#[test]
fn expand_derive() {
    let map = compute_crate_def_map(
        "
        //- /main.rs
        #[derive(Clone)]
        struct Foo;
        ",
    );
    assert_eq!(map.modules[map.root].scope.impls().len(), 1);
}

#[test]
fn expand_multiple_derive() {
    let map = compute_crate_def_map(
        "
        //- /main.rs
        #[derive(Copy, Clone)]
        struct Foo;
        ",
    );
    assert_eq!(map.modules[map.root].scope.impls().len(), 2);
}
<|endoftext|>