<commit_before>use core::cmp::{Eq, Ord};
use iter::BaseIter;

pub trait PersistentMap<K: Copy Eq Ord, V: Copy> {
  pure fn get(k: K) -> @Option<V>;
  pure fn put(k: K, v: V) -> self;
  pure fn delete(k: K) -> self;
}

enum RBColor {
  Red,
  Black
}

pub enum RBMap<K: Copy Eq Ord, V: Copy> {
  //   color    left         k  value       right
  Tree(RBColor, @RBMap<K,V>, K, @Option<V>, @RBMap<K,V>),
  Leaf
}

pure fn RBMap<K: Copy Eq Ord, V: Copy>(key: K, value: V) -> @RBMap<K, V> {
  @Tree(Red, @Leaf, key, @Some(value), @Leaf)
}

/**
 * A purely functional Left-Leaning Red-Black Tree.
 */
impl<K: Copy Eq Ord, V: Copy> @RBMap<K, V> : PersistentMap<K, V> {
  pure fn get(k: K) -> @Option<V> {
    match self {
      @Leaf => @None,
      @Tree(_, left, key, maybe_value, right) => {
        if (k.lt(&key)) {
          left.get(k)
        } else if (k.gt(&key)) {
          right.get(k)
        } else {
          maybe_value
        }
      }
    }
  }

  pure fn put(k: K, new_value: V) -> @RBMap<K, V> {
    self.modify(k, @Some(new_value))
  }

  pure fn delete(k: K) -> @RBMap<K, V> {
    self.modify(k, @None)
  }

  priv pure fn modify(k: K, new_value: @Option<V>) -> @RBMap<K, V> {
    match self {
      @Leaf => @Tree(Red, self, k, new_value, self),
      @Tree(color, left, key, original_value, right) => {
        if (k.lt(&key)) {
          self.balanceLeft(color, left.modify(k, new_value), key, original_value, right)
        } else if (k == key) {
          @Tree(color, left, k, new_value, right)
        } else {
          self.balanceRight(color, left, key, original_value, right.modify(k, new_value))
        }
      }
    }
  }

  priv pure fn balanceLeft(c: RBColor, l: @RBMap<K,V>, k: K, v: @Option<V>, r: @RBMap<K,V>) -> @RBMap<K,V> {
    match (c, l, k, v, r) {
      (Black,@Tree(Red,@Tree(Red,a,xK,xV,b),yK,yV,c),zK,zV,d) =>
        @Tree(Red,@Tree(Black,a,xK,xV,b),yK,yV,@Tree(Black,c,zK,zV,d)),
      (c,a,xK,xV,b) =>
        @Tree(c,a,xK,xV,b)
    }
  }

  priv pure fn balanceRight(c: RBColor, l: @RBMap<K,V>, k: K, v: @Option<V>, r: @RBMap<K,V>) -> @RBMap<K,V> {
    match (c, l, k, v, r) {
      (Black, @Tree(Red, t1, k1, v1, t2), k0, v0, @Tree(Red, t3, k2, v2, t4)) =>
        @Tree(Red, @Tree(Black, t1, k1, v1, t2), k0, v0, @Tree(Black, t3, k2, v2, t4)),
      (c, l, k, v, @Tree(Red, t1, k1, v1, t2)) =>
        @Tree(c, @Tree(Red, l, k, v, t1), k1, v1, t2),
      (c,a,xK,xV,b) =>
        @Tree(c,a,xK,xV,b)
    }
  }
}

impl<K: Copy Eq Ord, V: Copy> RBMap<K, V>: iter::BaseIter<(&K, &V)> {
  pure fn size_hint() -> Option<uint> {
    None
  }

  pure fn each(f: fn(&(&K, &V)) -> bool) {
    match self {
      Leaf => (),
      Tree(_, left, key, maybe_value, right) => {
        left.each(f);
        match maybe_value {
          @Some(value) => f(&(&key, &value)),
          @None => false,
        };
        right.each(f);
      }
    }
  }
}

#[test]
fn test_rb_tree() {
  let v1 = RBMap("stevej", 150);
  let v2 = v1.put("thatstacy", 187);

  assert(v2.get("stevej") == @Some(150));
  assert(v2.get("thatstacy") == @Some(187));

  let v3 = v2.delete("stevej");
  assert(v3.get("stevej") == @None);
  assert(v3.get("thatstacy") == @Some(187));

  let v4 = v2.put("jeremy", 16);

  let v5 = v4.put("ev", 20);
  let v6 = v5.put("zhana", 51573);

  assert(v6.get("jeremy") == @Some(16));
  assert(v6.get("stevej") == @Some(150));
  assert(v6.get("thatstacy") == @Some(187));
  assert(v6.get("ev") == @Some(20));
  assert(v6.get("zhana") == @Some(51573));
}

#[test]
fn test_base_iter_each() {
  let v1 = RBMap(1, 0);
  let v2 = v1.put(4, 0);
  let v3 = v2.put(3, 0);
  let v4 = v3.put(5, 0);
  let v5 = v4.put(2, 0);

  let n = @mut 1;

  fn t(n: @mut int, kv: &(&int, &int)) -> bool{
    match kv {
      &(k, _) => {
        assert (*n == *k);
        *n += 1;
      }
    }
    false
  }

  v5.each(|z| t(n, z));
}
<commit_msg>moving private methods into anonymous trait<commit_after>use core::cmp::{Eq, Ord};
use iter::BaseIter;

pub trait PersistentMap<K: Copy Eq Ord, V: Copy> {
  pure fn get(k: K) -> @Option<V>;
  pure fn put(k: K, v: V) -> self;
  pure fn delete(k: K) -> self;
}

enum RBColor {
  Red,
  Black
}

pub enum RBMap<K: Copy Eq Ord, V: Copy> {
  //   color    left         k  value       right
  Tree(RBColor, @RBMap<K,V>, K, @Option<V>, @RBMap<K,V>),
  Leaf
}

pure fn RBMap<K: Copy Eq Ord, V: Copy>(key: K, value: V) -> @RBMap<K, V> {
  @Tree(Red, @Leaf, key, @Some(value), @Leaf)
}

impl<K: Copy Eq Ord, V: Copy> @RBMap<K, V> {
  pure fn modify(k: K, new_value: @Option<V>) -> @RBMap<K, V> {
    match self {
      @Leaf => @Tree(Red, self, k, new_value, self),
      @Tree(color, left, key, original_value, right) => {
        if (k.lt(&key)) {
          self.balanceLeft(color, left.modify(k, new_value), key, original_value, right)
        } else if (k == key) {
          @Tree(color, left, k, new_value, right)
        } else {
          self.balanceRight(color, left, key, original_value, right.modify(k, new_value))
        }
      }
    }
  }

  pure fn balanceLeft(c: RBColor, l: @RBMap<K,V>, k: K, v: @Option<V>, r: @RBMap<K,V>) -> @RBMap<K,V> {
    match (c, l, k, v, r) {
      (Black,@Tree(Red,@Tree(Red,a,xK,xV,b),yK,yV,c),zK,zV,d) =>
        @Tree(Red,@Tree(Black,a,xK,xV,b),yK,yV,@Tree(Black,c,zK,zV,d)),
      (c,a,xK,xV,b) =>
        @Tree(c,a,xK,xV,b)
    }
  }

  pure fn balanceRight(c: RBColor, l: @RBMap<K,V>, k: K, v: @Option<V>, r: @RBMap<K,V>) -> @RBMap<K,V> {
    match (c, l, k, v, r) {
      (Black, @Tree(Red, t1, k1, v1, t2), k0, v0, @Tree(Red, t3, k2, v2, t4)) =>
        @Tree(Red, @Tree(Black, t1, k1, v1, t2), k0, v0, @Tree(Black, t3, k2, v2, t4)),
      (c, l, k, v, @Tree(Red, t1, k1, v1, t2)) =>
        @Tree(c, @Tree(Red, l, k, v, t1), k1, v1, t2),
      (c,a,xK,xV,b) =>
        @Tree(c,a,xK,xV,b)
    }
  }
}

/**
 * A purely functional Left-Leaning Red-Black Tree.
 */
impl<K: Copy Eq Ord, V: Copy> @RBMap<K, V> : PersistentMap<K, V> {
  pure fn get(k: K) -> @Option<V> {
    match self {
      @Leaf => @None,
      @Tree(_, left, key, maybe_value, right) => {
        if (k.lt(&key)) {
          left.get(k)
        } else if (k.gt(&key)) {
          right.get(k)
        } else {
          maybe_value
        }
      }
    }
  }

  pure fn put(k: K, new_value: V) -> @RBMap<K, V> {
    self.modify(k, @Some(new_value))
  }

  pure fn delete(k: K) -> @RBMap<K, V> {
    self.modify(k, @None)
  }
}

impl<K: Copy Eq Ord, V: Copy> RBMap<K, V>: iter::BaseIter<(&K, &V)> {
  pure fn size_hint() -> Option<uint> {
    None
  }

  pure fn each(f: fn(&(&K, &V)) -> bool) {
    match self {
      Leaf => (),
      Tree(_, left, key, maybe_value, right) => {
        left.each(f);
        match maybe_value {
          @Some(value) => f(&(&key, &value)),
          @None => false,
        };
        right.each(f);
      }
    }
  }
}

#[test]
fn test_rb_tree() {
  let v1 = RBMap("stevej", 150);
  let v2 = v1.put("thatstacy", 187);

  assert(v2.get("stevej") == @Some(150));
  assert(v2.get("thatstacy") == @Some(187));

  let v3 = v2.delete("stevej");
  assert(v3.get("stevej") == @None);
  assert(v3.get("thatstacy") == @Some(187));

  let v4 = v2.put("jeremy", 16);

  let v5 = v4.put("ev", 20);
  let v6 = v5.put("zhana", 51573);

  assert(v6.get("jeremy") == @Some(16));
  assert(v6.get("stevej") == @Some(150));
  assert(v6.get("thatstacy") == @Some(187));
  assert(v6.get("ev") == @Some(20));
  assert(v6.get("zhana") == @Some(51573));
}

#[test]
fn test_base_iter_each() {
  let v1 = RBMap(1, 0);
  let v2 = v1.put(4, 0);
  let v3 = v2.put(3, 0);
  let v4 = v3.put(5, 0);
  let v5 = v4.put(2, 0);

  let n = @mut 1;

  fn t(n: @mut int, kv: &(&int, &int)) -> bool{
    match kv {
      &(k, _) => {
        assert (*n == *k);
        *n += 1;
      }
    }
    false
  }

  v5.each(|z| t(n, z));
}
<|endoftext|>


<commit_before>extern crate exitcode;

use std::process;

pub fn parse_int_or_return_error_exitcode(s: String) -> Result<i32, exitcode::ExitCode> {
    match s.parse::<i32>() {
        Ok(i) => Ok(i),
        Err(_) => Err(exitcode::USAGE)
    }

}

pub fn main() {

    match parse_int_or_return_error_exitcode("123".to_string()) {
        Ok(i) => println!("Parsed: {}", i),
        Err(code) => {
            println!("Parse error.  Exiting with code: {}", code);
            process::exit(code);
        }
    }

    match parse_int_or_return_error_exitcode("foo".to_string()) {
        Ok(i) => println!("Parsed: {}", i),
        Err(code) => {
            println!("Parse error.  Exiting with code: {}", code);
            process::exit(code);
        }
    }

    println!("Exiting with code: {}", exitcode::OK);
    process::exit(exitcode::OK);

}
<commit_msg>Update example<commit_after>extern crate exitcode;

use std::process;
use std::io::{Write, stderr};

pub fn parse_int_or_return_error_exitcode(s: &str) -> Result<i32, exitcode::ExitCode> {
    match s.parse::<i32>() {
        Ok(i) => Ok(i),
        Err(_) => Err(exitcode::USAGE)
    }
}

pub fn main() {
    match parse_int_or_return_error_exitcode("foo") {
        Ok(i) => {
            println!("Parsed: {}", i);
            process::exit(exitcode::OK);
        },
        Err(code) => {
            writeln!(stderr(), "Parse error.  Exiting with code: {}", code).unwrap();
            process::exit(code);
        }
    }
}
<|endoftext|>


<commit_before>use cssparser::{BasicParseError, Parser, Token};

use drawing_ctx::ViewParams;
use error::*;
use length::{Length, LengthDir, LengthUnit, POINTS_PER_INCH};
use parsers::{Parse, ParseError};
use state::ComputedValues;

// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-size
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FontSizeSpec {
    Smaller,
    Larger,
    XXSmall,
    XSmall,
    Small,
    Medium,
    Large,
    XLarge,
    XXLarge,
    Value(Length),
}

impl FontSizeSpec {
    pub fn value(&self) -> Length {
        match self {
            FontSizeSpec::Value(s) => s.clone(),
            _ => unreachable!(),
        }
    }

    pub fn compute(&self, v: &ComputedValues) -> Self {
        let compute_points = |p| 12.0 * 1.2f64.powf(p) / POINTS_PER_INCH;

        let size = v.font_size.0.value();

        let new_size = match self {
            FontSizeSpec::Smaller => Length::new(size.length / 1.2, size.unit, LengthDir::Both),
            FontSizeSpec::Larger => Length::new(size.length * 1.2, size.unit, LengthDir::Both),
            FontSizeSpec::XXSmall => {
                Length::new(compute_points(-3.0), LengthUnit::Inch, LengthDir::Both)
            }
            FontSizeSpec::XSmall => {
                Length::new(compute_points(-2.0), LengthUnit::Inch, LengthDir::Both)
            }
            FontSizeSpec::Small => {
                Length::new(compute_points(-1.0), LengthUnit::Inch, LengthDir::Both)
            }
            FontSizeSpec::Medium => {
                Length::new(compute_points(0.0), LengthUnit::Inch, LengthDir::Both)
            }
            FontSizeSpec::Large => {
                Length::new(compute_points(1.0), LengthUnit::Inch, LengthDir::Both)
            }
            FontSizeSpec::XLarge => {
                Length::new(compute_points(2.0), LengthUnit::Inch, LengthDir::Both)
            }
            FontSizeSpec::XXLarge => {
                Length::new(compute_points(3.0), LengthUnit::Inch, LengthDir::Both)
            }
            FontSizeSpec::Value(s) if s.unit == LengthUnit::Percent => {
                Length::new(size.length * s.length, size.unit, LengthDir::Both)
            }
            FontSizeSpec::Value(s) => s.clone(),
        };

        FontSizeSpec::Value(new_size)
    }

    pub fn normalize(&self, values: &ComputedValues, params: &ViewParams) -> f64 {
        self.value().normalize(values, params)
    }
}

impl Parse for FontSizeSpec {
    type Data = ();
    type Err = ValueErrorKind;

    fn parse(
        parser: &mut Parser<'_, '_>,
        _: Self::Data,
    ) -> Result<FontSizeSpec, ::error::ValueErrorKind> {
        let parser_state = parser.state();

        Length::parse(parser, LengthDir::Both)
            .and_then(|s| Ok(FontSizeSpec::Value(s)))
            .or_else(|e| {
                parser.reset(&parser_state);

                {
                    let token = parser.next().map_err(|_| {
                        ::error::ValueErrorKind::Parse(::parsers::ParseError::new("expected token"))
                    })?;

                    if let Token::Ident(ref cow) = token {
                        match cow.as_ref() {
                            "smaller" => return Ok(FontSizeSpec::Smaller),
                            "larger" => return Ok(FontSizeSpec::Larger),
                            "xx-small" => return Ok(FontSizeSpec::XXSmall),
                            "x-small" => return Ok(FontSizeSpec::XSmall),
                            "small" => return Ok(FontSizeSpec::Small),
                            "medium" => return Ok(FontSizeSpec::Medium),
                            "large" => return Ok(FontSizeSpec::Large),
                            "x-large" => return Ok(FontSizeSpec::XLarge),
                            "xx-large" => return Ok(FontSizeSpec::XXLarge),
                            _ => (),
                        };
                    }
                }

                parser.reset(&parser_state);

                Err(e)
            })
    }
}

// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-weight
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FontWeightSpec {
    Normal,
    Bold,
    Bolder,
    Lighter,
    W100,
    W200,
    W300,
    W400,
    W500,
    W600,
    W700,
    W800,
    W900,
}

impl Parse for FontWeightSpec {
    type Data = ();
    type Err = ValueErrorKind;

    fn parse(
        parser: &mut Parser<'_, '_>,
        _: Self::Data,
    ) -> Result<FontWeightSpec, ::error::ValueErrorKind> {
        if let Ok(r) = parser.try(|p| {
            p.expect_ident()
                .map_err(|_| ())
                .and_then(|cow| match cow.as_ref() {
                    "normal" => Ok(FontWeightSpec::Normal),
                    "bold" => Ok(FontWeightSpec::Bold),
                    "bolder" => Ok(FontWeightSpec::Bolder),
                    "lighter" => Ok(FontWeightSpec::Lighter),
                    _ => Err(()),
                })
        }) {
            return Ok(r);
        }

        if let Ok(r) = parser
            .expect_integer()
            .map_err(|_| ())
            .and_then(|i| match i {
                100 => Ok(FontWeightSpec::W100),
                200 => Ok(FontWeightSpec::W200),
                300 => Ok(FontWeightSpec::W300),
                400 => Ok(FontWeightSpec::W400),
                500 => Ok(FontWeightSpec::W500),
                600 => Ok(FontWeightSpec::W600),
                700 => Ok(FontWeightSpec::W700),
                800 => Ok(FontWeightSpec::W800),
                900 => Ok(FontWeightSpec::W900),
                _ => Err(()),
            }) {
            Ok(r)
        } else {
            Err(ValueErrorKind::Parse(ParseError::new(
                "invalid font-weight specification",
            )))
        }
    }
}

// https://www.w3.org/TR/css-text-3/#letter-spacing-property
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum LetterSpacingSpec {
    Normal,
    Value(Length),
}

impl LetterSpacingSpec {
    pub fn value(&self) -> Length {
        match self {
            LetterSpacingSpec::Value(s) => s.clone(),
            _ => unreachable!(),
        }
    }

    pub fn compute(&self) -> Self {
        let spacing = match self {
            LetterSpacingSpec::Normal => {
                Length::new(0.0, LengthUnit::Default, LengthDir::Horizontal)
            }
            LetterSpacingSpec::Value(s) => s.clone(),
        };

        LetterSpacingSpec::Value(spacing)
    }

    pub fn normalize(&self, values: &ComputedValues, params: &ViewParams) -> f64 {
        self.value().normalize(values, params)
    }
}

impl Parse for LetterSpacingSpec {
    type Data = ();
    type Err = ValueErrorKind;

    fn parse(
        parser: &mut Parser<'_, '_>,
        _: Self::Data,
    ) -> Result<LetterSpacingSpec, ::error::ValueErrorKind> {
        let parser_state = parser.state();

        Length::parse(parser, LengthDir::Horizontal)
            .and_then(|s| Ok(LetterSpacingSpec::Value(s)))
            .or_else(|e| {
                parser.reset(&parser_state);

                {
                    let token = parser.next().map_err(|_| {
                        ::error::ValueErrorKind::Parse(::parsers::ParseError::new("expected token"))
                    })?;

                    if let Token::Ident(ref cow) = token {
                        match cow.as_ref() {
                            "normal" => return Ok(LetterSpacingSpec::Normal),
                            _ => (),
                        };
                    }
                }

                parser.reset(&parser_state);

                Err(e)
            })
    }
}

/// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-family
#[derive(Debug, Clone, PartialEq)]
pub struct SingleFontFamily(pub String);

impl Parse for SingleFontFamily {
    type Data = ();
    type Err = ValueErrorKind;

    fn parse(
        parser: &mut Parser<'_, '_>,
        _: Self::Data,
    ) -> Result<SingleFontFamily, ValueErrorKind> {
        parse_single_font_family(parser)
            .map_err(|_| ValueErrorKind::from(ParseError::new("expected font family")))
    }
}

fn parse_single_font_family<'i>(
    parser: &'i mut Parser<'_, '_>,
) -> Result<SingleFontFamily, BasicParseError<'i>> {
    if let Ok(cow) = parser.try(|p| p.expect_string_cloned()) {
        return Ok(SingleFontFamily((*cow).to_owned()));
    }

    let first_ident = parser.expect_ident()?.clone();

    let mut value = first_ident.as_ref().to_owned();

    while let Ok(cow) = parser.try(|p| p.expect_ident_cloned()) {
        value.push(' ');
        value.push_str(&cow);
    }

    Ok(SingleFontFamily(value))
}

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

    #[test]
    fn detects_invalid_invalid_font_size() {
        assert!(is_parse_error(&FontSizeSpec::parse_str("furlong", ())));
    }

    #[test]
    fn parses_font_weight() {
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("normal", ()),
            Ok(FontWeightSpec::Normal)
        );
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("bold", ()),
            Ok(FontWeightSpec::Bold)
        );
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("100", ()),
            Ok(FontWeightSpec::W100)
        );
    }

    #[test]
    fn detects_invalid_font_weight() {
        assert!(<FontWeightSpec as Parse>::parse_str("", ()).is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("strange", ()).is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("314", ()).is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("3.14", ()).is_err());
    }

    #[test]
    fn parses_letter_spacing() {
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("normal", ()),
            Ok(LetterSpacingSpec::Normal)
        );
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("10em", ()),
            Ok(LetterSpacingSpec::Value(Length::new(
                10.0,
                LengthUnit::FontEm,
                LengthDir::Horizontal
            )))
        );
    }

    #[test]
    fn computes_letter_spacing() {
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("normal", ()).map(|s| s.compute()),
            Ok(LetterSpacingSpec::Value(Length::new(
                0.0,
                LengthUnit::Default,
                LengthDir::Horizontal
            )))
        );
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("10em", ()).map(|s| s.compute()),
            Ok(LetterSpacingSpec::Value(Length::new(
                10.0,
                LengthUnit::FontEm,
                LengthDir::Horizontal
            )))
        );
    }

    #[test]
    fn detects_invalid_invalid_letter_spacing() {
        assert!(is_parse_error(&LetterSpacingSpec::parse_str("furlong", ())));
    }

    #[test]
    fn parses_font_family() {
        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("'Hello world'", ()),
            Ok(SingleFontFamily("Hello world".to_owned()))
        );

        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("\"Hello world\"", ()),
            Ok(SingleFontFamily("Hello world".to_owned()))
        );

        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("  Hello  world  ", ()),
            Ok(SingleFontFamily("Hello world".to_owned()))
        );

        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("Plonk", ()),
            Ok(SingleFontFamily("Plonk".to_owned()))
        );
    }

    #[test]
    fn detects_invalid_font_family() {
        assert!(<SingleFontFamily as Parse>::parse_str("", ()).is_err());

        // assert!(<SingleFontFamily as Parse>::parse_str("''", ()).is_err());

        assert!(<SingleFontFamily as Parse>::parse_str("42", ()).is_err());
    }
}
<commit_msg>rustfmt<commit_after>use cssparser::{BasicParseError, Parser, Token};

use drawing_ctx::ViewParams;
use error::*;
use length::{Length, LengthDir, LengthUnit, POINTS_PER_INCH};
use parsers::{Parse, ParseError};
use state::ComputedValues;

// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-size
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FontSizeSpec {
    Smaller,
    Larger,
    XXSmall,
    XSmall,
    Small,
    Medium,
    Large,
    XLarge,
    XXLarge,
    Value(Length),
}

impl FontSizeSpec {
    pub fn value(&self) -> Length {
        match self {
            FontSizeSpec::Value(s) => s.clone(),
            _ => unreachable!(),
        }
    }

    pub fn compute(&self, v: &ComputedValues) -> Self {
        let compute_points = |p| 12.0 * 1.2f64.powf(p) / POINTS_PER_INCH;

        let size = v.font_size.0.value();

        let new_size = match self {
            FontSizeSpec::Smaller => Length::new(size.length / 1.2, size.unit, LengthDir::Both),
            FontSizeSpec::Larger => Length::new(size.length * 1.2, size.unit, LengthDir::Both),
            FontSizeSpec::XXSmall => {
                Length::new(compute_points(-3.0), LengthUnit::Inch, LengthDir::Both)
            }
            FontSizeSpec::XSmall => {
                Length::new(compute_points(-2.0), LengthUnit::Inch, LengthDir::Both)
            }
            FontSizeSpec::Small => {
                Length::new(compute_points(-1.0), LengthUnit::Inch, LengthDir::Both)
            }
            FontSizeSpec::Medium => {
                Length::new(compute_points(0.0), LengthUnit::Inch, LengthDir::Both)
            }
            FontSizeSpec::Large => {
                Length::new(compute_points(1.0), LengthUnit::Inch, LengthDir::Both)
            }
            FontSizeSpec::XLarge => {
                Length::new(compute_points(2.0), LengthUnit::Inch, LengthDir::Both)
            }
            FontSizeSpec::XXLarge => {
                Length::new(compute_points(3.0), LengthUnit::Inch, LengthDir::Both)
            }
            FontSizeSpec::Value(s) if s.unit == LengthUnit::Percent => {
                Length::new(size.length * s.length, size.unit, LengthDir::Both)
            }
            FontSizeSpec::Value(s) => s.clone(),
        };

        FontSizeSpec::Value(new_size)
    }

    pub fn normalize(&self, values: &ComputedValues, params: &ViewParams) -> f64 {
        self.value().normalize(values, params)
    }
}

impl Parse for FontSizeSpec {
    type Data = ();
    type Err = ValueErrorKind;

    fn parse(
        parser: &mut Parser<'_, '_>,
        _: Self::Data,
    ) -> Result<FontSizeSpec, ::error::ValueErrorKind> {
        let parser_state = parser.state();

        Length::parse(parser, LengthDir::Both)
            .and_then(|s| Ok(FontSizeSpec::Value(s)))
            .or_else(|e| {
                parser.reset(&parser_state);

                {
                    let token = parser.next().map_err(|_| {
                        ::error::ValueErrorKind::Parse(::parsers::ParseError::new("expected token"))
                    })?;

                    if let Token::Ident(ref cow) = token {
                        match cow.as_ref() {
                            "smaller" => return Ok(FontSizeSpec::Smaller),
                            "larger" => return Ok(FontSizeSpec::Larger),
                            "xx-small" => return Ok(FontSizeSpec::XXSmall),
                            "x-small" => return Ok(FontSizeSpec::XSmall),
                            "small" => return Ok(FontSizeSpec::Small),
                            "medium" => return Ok(FontSizeSpec::Medium),
                            "large" => return Ok(FontSizeSpec::Large),
                            "x-large" => return Ok(FontSizeSpec::XLarge),
                            "xx-large" => return Ok(FontSizeSpec::XXLarge),
                            _ => (),
                        };
                    }
                }

                parser.reset(&parser_state);

                Err(e)
            })
    }
}

// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-weight
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FontWeightSpec {
    Normal,
    Bold,
    Bolder,
    Lighter,
    W100,
    W200,
    W300,
    W400,
    W500,
    W600,
    W700,
    W800,
    W900,
}

impl Parse for FontWeightSpec {
    type Data = ();
    type Err = ValueErrorKind;

    fn parse(
        parser: &mut Parser<'_, '_>,
        _: Self::Data,
    ) -> Result<FontWeightSpec, ::error::ValueErrorKind> {
        if let Ok(r) = parser.try(|p| {
            p.expect_ident()
                .map_err(|_| ())
                .and_then(|cow| match cow.as_ref() {
                    "normal" => Ok(FontWeightSpec::Normal),
                    "bold" => Ok(FontWeightSpec::Bold),
                    "bolder" => Ok(FontWeightSpec::Bolder),
                    "lighter" => Ok(FontWeightSpec::Lighter),
                    _ => Err(()),
                })
        }) {
            return Ok(r);
        }

        if let Ok(r) = parser
            .expect_integer()
            .map_err(|_| ())
            .and_then(|i| match i {
                100 => Ok(FontWeightSpec::W100),
                200 => Ok(FontWeightSpec::W200),
                300 => Ok(FontWeightSpec::W300),
                400 => Ok(FontWeightSpec::W400),
                500 => Ok(FontWeightSpec::W500),
                600 => Ok(FontWeightSpec::W600),
                700 => Ok(FontWeightSpec::W700),
                800 => Ok(FontWeightSpec::W800),
                900 => Ok(FontWeightSpec::W900),
                _ => Err(()),
            })
        {
            Ok(r)
        } else {
            Err(ValueErrorKind::Parse(ParseError::new(
                "invalid font-weight specification",
            )))
        }
    }
}

// https://www.w3.org/TR/css-text-3/#letter-spacing-property
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum LetterSpacingSpec {
    Normal,
    Value(Length),
}

impl LetterSpacingSpec {
    pub fn value(&self) -> Length {
        match self {
            LetterSpacingSpec::Value(s) => s.clone(),
            _ => unreachable!(),
        }
    }

    pub fn compute(&self) -> Self {
        let spacing = match self {
            LetterSpacingSpec::Normal => {
                Length::new(0.0, LengthUnit::Default, LengthDir::Horizontal)
            }
            LetterSpacingSpec::Value(s) => s.clone(),
        };

        LetterSpacingSpec::Value(spacing)
    }

    pub fn normalize(&self, values: &ComputedValues, params: &ViewParams) -> f64 {
        self.value().normalize(values, params)
    }
}

impl Parse for LetterSpacingSpec {
    type Data = ();
    type Err = ValueErrorKind;

    fn parse(
        parser: &mut Parser<'_, '_>,
        _: Self::Data,
    ) -> Result<LetterSpacingSpec, ::error::ValueErrorKind> {
        let parser_state = parser.state();

        Length::parse(parser, LengthDir::Horizontal)
            .and_then(|s| Ok(LetterSpacingSpec::Value(s)))
            .or_else(|e| {
                parser.reset(&parser_state);

                {
                    let token = parser.next().map_err(|_| {
                        ::error::ValueErrorKind::Parse(::parsers::ParseError::new("expected token"))
                    })?;

                    if let Token::Ident(ref cow) = token {
                        match cow.as_ref() {
                            "normal" => return Ok(LetterSpacingSpec::Normal),
                            _ => (),
                        };
                    }
                }

                parser.reset(&parser_state);

                Err(e)
            })
    }
}

/// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-family
#[derive(Debug, Clone, PartialEq)]
pub struct SingleFontFamily(pub String);

impl Parse for SingleFontFamily {
    type Data = ();
    type Err = ValueErrorKind;

    fn parse(
        parser: &mut Parser<'_, '_>,
        _: Self::Data,
    ) -> Result<SingleFontFamily, ValueErrorKind> {
        parse_single_font_family(parser)
            .map_err(|_| ValueErrorKind::from(ParseError::new("expected font family")))
    }
}

fn parse_single_font_family<'i>(
    parser: &'i mut Parser<'_, '_>,
) -> Result<SingleFontFamily, BasicParseError<'i>> {
    if let Ok(cow) = parser.try(|p| p.expect_string_cloned()) {
        return Ok(SingleFontFamily((*cow).to_owned()));
    }

    let first_ident = parser.expect_ident()?.clone();

    let mut value = first_ident.as_ref().to_owned();

    while let Ok(cow) = parser.try(|p| p.expect_ident_cloned()) {
        value.push(' ');
        value.push_str(&cow);
    }

    Ok(SingleFontFamily(value))
}

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

    #[test]
    fn detects_invalid_invalid_font_size() {
        assert!(is_parse_error(&FontSizeSpec::parse_str("furlong", ())));
    }

    #[test]
    fn parses_font_weight() {
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("normal", ()),
            Ok(FontWeightSpec::Normal)
        );
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("bold", ()),
            Ok(FontWeightSpec::Bold)
        );
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("100", ()),
            Ok(FontWeightSpec::W100)
        );
    }

    #[test]
    fn detects_invalid_font_weight() {
        assert!(<FontWeightSpec as Parse>::parse_str("", ()).is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("strange", ()).is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("314", ()).is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("3.14", ()).is_err());
    }

    #[test]
    fn parses_letter_spacing() {
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("normal", ()),
            Ok(LetterSpacingSpec::Normal)
        );
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("10em", ()),
            Ok(LetterSpacingSpec::Value(Length::new(
                10.0,
                LengthUnit::FontEm,
                LengthDir::Horizontal
            )))
        );
    }

    #[test]
    fn computes_letter_spacing() {
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("normal", ()).map(|s| s.compute()),
            Ok(LetterSpacingSpec::Value(Length::new(
                0.0,
                LengthUnit::Default,
                LengthDir::Horizontal
            )))
        );
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("10em", ()).map(|s| s.compute()),
            Ok(LetterSpacingSpec::Value(Length::new(
                10.0,
                LengthUnit::FontEm,
                LengthDir::Horizontal
            )))
        );
    }

    #[test]
    fn detects_invalid_invalid_letter_spacing() {
        assert!(is_parse_error(&LetterSpacingSpec::parse_str("furlong", ())));
    }

    #[test]
    fn parses_font_family() {
        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("'Hello world'", ()),
            Ok(SingleFontFamily("Hello world".to_owned()))
        );

        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("\"Hello world\"", ()),
            Ok(SingleFontFamily("Hello world".to_owned()))
        );

        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("  Hello  world  ", ()),
            Ok(SingleFontFamily("Hello world".to_owned()))
        );

        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("Plonk", ()),
            Ok(SingleFontFamily("Plonk".to_owned()))
        );
    }

    #[test]
    fn detects_invalid_font_family() {
        assert!(<SingleFontFamily as Parse>::parse_str("", ()).is_err());

        // assert!(<SingleFontFamily as Parse>::parse_str("''", ()).is_err());

        assert!(<SingleFontFamily as Parse>::parse_str("42", ()).is_err());
    }
}
<|endoftext|>


<commit_before>use system::SystemData;

pub struct Registers
{
    pub accumulator:u8,
    pub flags:u8,
    pub b_register:u8,
    pub c_register:u8,
    pub d_register:u8,
    pub e_register:u8,
    pub h_register:u8,
    pub l_register:u8,
    pub stack_pointer: u16,
    pub program_counter: u16,
}

// Returns clock cycles passed during opcode
pub fn parse_opcode(system_data: &mut SystemData, registers: &mut Registers) -> u8
{
    let mut cycles: u8 = 0;
    let opcode: u8 = system_data.mem_map[registers.program_counter as usize];
    println!("{:x}", opcode);

    //inc
    if (opcode & 0xC7) == 0x04
    {
        if (opcode & 0x38) == 0x38{
            registers.accumulator += 1;
            registers.program_counter += 1;
            cycles = 1;
        }
        else
        {
            println!("No Opcode Found");
        }
    }
    //8bit ld group
    //ld r, n
    else if (opcode & 0xC7) == 0x06
    {
        cycles = 2;

        if(opcode & 0x38) == 0x38
        {
            registers.accumulator = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if(opcode & 0x38) == 0x00
        {
            registers.b_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if(opcode & 0x38) == 0x08
        {
            registers.c_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if(opcode & 0x38) == 0x10
        {
            registers.d_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if(opcode & 0x38) == 0x18
        {
            registers.e_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if(opcode & 0x38) == 0x20
        {
            registers.h_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if(opcode & 0x38) == 0x28
        {
            registers.l_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else
        {
            cycles = 0;
            println!("No Opcode Found");
        }
        registers.program_counter += 2;
    }
    //16 bit ld group
    else if (opcode & 0xCF) == 0x01
    {
        cycles = 2;

        if (opcode & 0x30) == 0x30
        {
            registers.stack_pointer = system_data.mem_map[(registers.program_counter + 1) as usize] as u16 | (system_data.mem_map[(registers.program_counter + 2) as usize] as u16) << 8;
        }
        else if (opcode & 0x30) == 0x20
        {
            registers.h_register = system_data.mem_map[(registers.program_counter + 2) as usize];
            registers.l_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if (opcode & 0x30) == 0x10
        {
            registers.d_register = system_data.mem_map[(registers.program_counter + 2) as usize];
            registers.e_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if (opcode & 0x30) == 0x00
        {
            registers.b_register = system_data.mem_map[(registers.program_counter + 2) as usize];
            registers.c_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else
        {
            cycles = 0;
            println!("No Opcode Found");
        }

        registers.program_counter += 3;
    }
    //xor
    else if (opcode & 0xF8) == 0xA8
    {
        if (opcode & 0x07) == 0x07
        {
            registers.accumulator = registers.accumulator ^ registers.accumulator;
            registers.program_counter += 1;
            cycles = 1;
            registers.flags = 0x00;
            if  registers.accumulator ==  0 {
                registers.flags = registers.flags | 0x80;
            }
        }
        else
        {
            println!("No Opcode Found");
        }
    }
    else if (opcode == 0x20)
    {
        if (registers.flags & 0x80) != 0x80 {
            cycles = 3;
            let pc_dest: i8 = (system_data.mem_map[(registers.program_counter + 1) as usize] + 2) as i8;
            registers.program_counter = (registers.program_counter as i32 + pc_dest as i32) as u16;
        }
        else {
            cycles = 2;
            registers.program_counter += 2;
        }
    }

    //LDD (HL), A - 32
    else if (opcode == 0x32)
    {
        let mut mem_loc: u16 = registers.l_register as u16 | (registers.h_register as u16) << 8;
        system_data.mem_map[mem_loc as usize] = registers.accumulator;
        mem_loc -= 1;
        registers.l_register = (mem_loc & 0x0F) as u8;
        registers.h_register = ((mem_loc & 0xF0) >> 8) as u8;
        cycles = 2;
        registers.program_counter += 1;
    }
    //cb codes
    else if (opcode == 0xCB){
        let opcode_next :u8 = system_data.mem_map[(registers.program_counter + 1) as usize];
        //bit b, r
        if (opcode_next & 0xC0) == 0x40
        {
            cycles = 2;
            let test_bit: u8 = (opcode_next & 0x38) >> 3;
            if (opcode_next & 0x07) == 0x04
            {
                registers.flags = registers.flags & 0x10;

                if ((registers.h_register >> test_bit) & 0x01) == 0x00
                {
                    registers.flags = registers.flags | 0xA0;
                }
                else
                {
                    registers.flags = registers.flags | 0x20;
                }
            }
            else
            {
                cycles = 0;
                println!("No Opcode Found");
            }
            registers.program_counter += 2;
        }
        else
        {
            println!("No Opcode Found");
        }
    }
    else
    {
        println!("No Opcode Found");
    }

    return cycles;
}

pub fn init_registers() -> Registers
{
    return Registers
    {
        accumulator: 0,
        flags: 0,
        b_register:0,
        c_register:0,
        d_register:0,
        e_register:0,
        h_register:0,
        l_register:0,
        stack_pointer: 0,
        program_counter: 0,
    };
}<commit_msg>Added another load<commit_after>use system::SystemData;

pub struct Registers
{
    pub accumulator:u8,
    pub flags:u8,
    pub b_register:u8,
    pub c_register:u8,
    pub d_register:u8,
    pub e_register:u8,
    pub h_register:u8,
    pub l_register:u8,
    pub stack_pointer: u16,
    pub program_counter: u16,
}

// Returns clock cycles passed during opcode
pub fn parse_opcode(system_data: &mut SystemData, registers: &mut Registers) -> u8
{
    let mut cycles: u8 = 0;
    let opcode: u8 = system_data.mem_map[registers.program_counter as usize];
    println!("{:x}", opcode);

    //inc
    if (opcode & 0xC7) == 0x04
    {
        cycles = 1;
        if (opcode & 0x38) == 0x38{
            registers.accumulator += 1;
            registers.program_counter += 1;
        }
        // else if (opcode & 0x38)==
        // {

        // }
        else
        {
            cycles = 0;
            println!("No Opcode Found");
        }
    }
    //8bit ld group
    //ld r, n
    else if (opcode & 0xC7) == 0x06
    {
        cycles = 2;

        if(opcode & 0x38) == 0x38
        {
            registers.accumulator = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if(opcode & 0x38) == 0x00
        {
            registers.b_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if(opcode & 0x38) == 0x08
        {
            registers.c_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if(opcode & 0x38) == 0x10
        {
            registers.d_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if(opcode & 0x38) == 0x18
        {
            registers.e_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if(opcode & 0x38) == 0x20
        {
            registers.h_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if(opcode & 0x38) == 0x28
        {
            registers.l_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else
        {
            cycles = 0;
            println!("No Opcode Found");
        }
        registers.program_counter += 2;
    }
    //ld (FF00+C), A
    else if opcode == 0xE2
    {
        cycles = 2;
        system_data.mem_map[(0xFF00 + registers.c_register) as usize] = registers.accumulator;
        registers.program_counter += 1;
    }
    //16 bit ld group
    else if (opcode & 0xCF) == 0x01
    {
        cycles = 2;

        if (opcode & 0x30) == 0x30
        {
            registers.stack_pointer = system_data.mem_map[(registers.program_counter + 1) as usize] as u16 | (system_data.mem_map[(registers.program_counter + 2) as usize] as u16) << 8;
        }
        else if (opcode & 0x30) == 0x20
        {
            registers.h_register = system_data.mem_map[(registers.program_counter + 2) as usize];
            registers.l_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if (opcode & 0x30) == 0x10
        {
            registers.d_register = system_data.mem_map[(registers.program_counter + 2) as usize];
            registers.e_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else if (opcode & 0x30) == 0x00
        {
            registers.b_register = system_data.mem_map[(registers.program_counter + 2) as usize];
            registers.c_register = system_data.mem_map[(registers.program_counter + 1) as usize];
        }
        else
        {
            cycles = 0;
            println!("No Opcode Found");
        }

        registers.program_counter += 3;
    }
    //xor
    else if (opcode & 0xF8) == 0xA8
    {
        if (opcode & 0x07) == 0x07
        {
            registers.accumulator = registers.accumulator ^ registers.accumulator;
            registers.program_counter += 1;
            cycles = 1;
            registers.flags = 0x00;
            if  registers.accumulator ==  0 {
                registers.flags = registers.flags | 0x80;
            }
        }
        else
        {
            println!("No Opcode Found");
        }
    }
    else if (opcode == 0x20)
    {
        if (registers.flags & 0x80) != 0x80 {
            cycles = 3;
            let pc_dest: i8 = (system_data.mem_map[(registers.program_counter + 1) as usize] + 2) as i8;
            registers.program_counter = (registers.program_counter as i32 + pc_dest as i32) as u16;
        }
        else {
            cycles = 2;
            registers.program_counter += 2;
        }
    }

    //LDD (HL), A - 32
    else if (opcode == 0x32)
    {
        let mut mem_loc: u16 = registers.l_register as u16 | (registers.h_register as u16) << 8;
        system_data.mem_map[mem_loc as usize] = registers.accumulator;
        mem_loc -= 1;
        registers.l_register = (mem_loc & 0x0F) as u8;
        registers.h_register = ((mem_loc & 0xF0) >> 8) as u8;
        cycles = 2;
        registers.program_counter += 1;
    }
    //cb codes
    else if (opcode == 0xCB){
        let opcode_next :u8 = system_data.mem_map[(registers.program_counter + 1) as usize];
        //bit b, r
        if (opcode_next & 0xC0) == 0x40
        {
            cycles = 2;
            let test_bit: u8 = (opcode_next & 0x38) >> 3;
            if (opcode_next & 0x07) == 0x04
            {
                registers.flags = registers.flags & 0x10;

                if ((registers.h_register >> test_bit) & 0x01) == 0x00
                {
                    registers.flags = registers.flags | 0xA0;
                }
                else
                {
                    registers.flags = registers.flags | 0x20;
                }
            }
            else
            {
                cycles = 0;
                println!("No Opcode Found");
            }
            registers.program_counter += 2;
        }
        else
        {
            println!("No Opcode Found");
        }
    }
    else
    {
        println!("No Opcode Found");
    }

    return cycles;
}

pub fn init_registers() -> Registers
{
    return Registers
    {
        accumulator: 0,
        flags: 0,
        b_register:0,
        c_register:0,
        d_register:0,
        e_register:0,
        h_register:0,
        l_register:0,
        stack_pointer: 0,
        program_counter: 0,
    };
}<|endoftext|>


<commit_before>mod audio;
mod debuggerui;
mod gbaui;
mod glutil;
mod pyrite_window;

use anyhow::Context as _;
use debuggerui::DebuggerWindow;
use gbaui::GbaWindow;
use glutin::{
    dpi::LogicalSize,
    event::{Event, WindowEvent},
    event_loop::{ControlFlow, EventLoop, EventLoopWindowTarget},
    window::{WindowBuilder, WindowId},
    PossiblyCurrent, WindowedContext,
};
use pyrite::{config::Config, GbaHandle};
use pyrite_window::PyriteWindow;

struct Windows {
    gba_handle: GbaHandle,
    gba: GbaWindow,
    debugger: Option<DebuggerWindow>,
    config: std::sync::Arc<Config>,
}

impl Windows {
    fn new(
        config: std::sync::Arc<Config>,
        window: WindowedContext<PossiblyCurrent>,
        gba: GbaHandle,
    ) -> anyhow::Result<Windows> {
        Ok(Windows {
            config: config.clone(),
            gba_handle: gba.clone(),
            gba: GbaWindow::new(config, window, gba).context("error while creating GBA window")?,
            debugger: None,
        })
    }

    fn main_events_cleared(&mut self) {
        if self.gba.update() {
            self.gba.request_redraw();
        }

        if let Some(ref mut debugger) = self.debugger {
            if debugger.update() {
                debugger.request_redraw();
            }
        }
    }

    fn is_gba(&self, id: WindowId) -> bool {
        self.gba.window_id() == id
    }

    fn is_debugger(&self, id: WindowId) -> bool {
        self.debugger
            .as_ref()
            .filter(|d| d.window_id() == id)
            .is_some()
    }

    fn with_window<F>(&mut self, id: WindowId, f: F)
    where
        F: FnOnce(&mut dyn PyriteWindow),
    {
        if self.is_gba(id) {
            f(&mut self.gba);
        } else if self.is_debugger(id) {
            if let Some(ref mut debugger) = self.debugger {
                f(debugger)
            }
        }
    }

    fn create_debugger_window(&mut self, el: &EventLoopWindowTarget<()>) -> anyhow::Result<()> {
        if self.debugger.is_some() {
            return Ok(());
        }

        let window = WindowBuilder::new()
            .with_title("Pyrite Debugger")
            .with_inner_size(LogicalSize::new(640.0f32, 320.0));
        let window = unsafe {
            glutin::ContextBuilder::new()
                .with_vsync(self.config.graphics.vsync.unwrap_or(true))
                .build_windowed(window, el)
                .context("failed to create windowed context")?
                .make_current()
                .map_err(|err| anyhow::anyhow!("{:?}", err))
                .context("failed to make window current")?
        };
        self.debugger = Some(
            DebuggerWindow::new(self.gba_handle.clone(), window)
                .context("error while creating debugger window")?,
        );

        Ok(())
    }

    fn close_debugger(&mut self) {
        self.debugger = None;
    }
}

fn on_window_event(
    event: WindowEvent,
    el: &EventLoopWindowTarget<()>,
    id: WindowId,
    windows: &mut Windows,
    flow: &mut ControlFlow,
) -> anyhow::Result<()> {
    match event {
        WindowEvent::CloseRequested if windows.is_gba(id) => {
            windows.with_window(id, |window| window.process_window_event(event));
            *flow = ControlFlow::Exit;
        }

        WindowEvent::CloseRequested if windows.is_debugger(id) => {
            windows.with_window(id, |window| window.process_window_event(event));
            windows.close_debugger();
        }

        event => {
            windows.with_window(id, |window| window.process_window_event(event));

            if windows.is_gba(id) {
                if windows.gba.wants_exit() {
                    *flow = ControlFlow::Exit;
                }

                if windows.gba.wants_debugger() {
                    if let Err(err) = windows.create_debugger_window(el) {
                        log::error!("error while creating debugger window: {err:?}");
                    }
                }
            } else if windows.is_debugger(id)
                && windows.debugger.as_ref().map(|d| d.wants_close()) == Some(true)
            {
                windows.close_debugger();
            }
        }
    }
    Ok(())
}

fn on_event(
    windows: &mut Windows,
    event: Event<()>,
    el: &EventLoopWindowTarget<()>,
    flow: &mut ControlFlow,
) -> anyhow::Result<()> {
    *flow = ControlFlow::Wait;

    match event {
        Event::WindowEvent { event, window_id } => {
            on_window_event(event, el, window_id, windows, flow)?
        }
        Event::RedrawRequested(window_id) => {
            windows.with_window(window_id, |window| window.gl_render(flow));
        }
        Event::MainEventsCleared => windows.main_events_cleared(),
        _ => *flow = ControlFlow::Poll,
    }
    Ok(())
}

fn run(event_loop: EventLoop<()>) -> anyhow::Result<()> {
    let config = std::sync::Arc::new(
        pyrite::config::from_toml_path("pyrite.toml")
            .map_err(|err| {
                let err = anyhow::Error::from(err);
                log::error!("{:#}", err);
            })
            .unwrap_or_default(),
    );

    let gba = pyrite::GbaHandle::new();
    let rom = get_rom_from_args().context("error occurred retrieving ROM from args")?;
    let bios = config.gba.bios_path.as_ref().and_then(|path| {
        match std::fs::read(&path)
            .with_context(|| format!("failed to read path {}", path.display()))
        {
            Ok(data) => Some(data),
            Err(err) => {
                log::error!("error occurred while loading BIOS: {:?}", err);
                None
            }
        }
    });
    let boot_from_bios = config.gba.boot_from_bios.unwrap_or(true);
    gba.after_frame_wait(move |gba, _| {
        gba.set_gamepak(rom);
        gba.set_bios(bios);
        gba.reset(boot_from_bios);
    });
    let _stream = audio::run(gba.clone()).context("error while starting audio")?;

    let window = WindowBuilder::new()
        .with_title("Pyrite")
        .with_inner_size(LogicalSize::new(480.0f32, 320.0));
    let window = unsafe {
        glutin::ContextBuilder::new()
            .with_vsync(config.graphics.vsync.unwrap_or(true))
            .build_windowed(window, &event_loop)
            .context("failed to create windowed context")?
            .make_current()
            .map_err(|err| anyhow::anyhow!("{:?}", err))
            .context("failed to make window current")?
    };
    let mut windows = Windows::new(config, window, gba).context("error initializing windows")?;

    windows.gba_handle.set_paused(false);
    event_loop.run(move |event, el, control_flow| {
        if let Err(err) = on_event(&mut windows, event, el, control_flow) {
            log::error!("error occurred in event loop: {:?}", err);
            *control_flow = ControlFlow::Exit;
        }
    });
}

fn main() -> anyhow::Result<()> {
    pretty_env_logger::init();
    let event_loop = EventLoop::new();

    run(event_loop).context("error occurred while running main loop")?;
    unreachable!("run should never return unless there is an error");
}

fn get_rom_from_args() -> anyhow::Result<Vec<u8>> {
    let rom_path = std::env::args()
        .nth(1)
        .map(std::path::PathBuf::from)
        .ok_or_else(|| anyhow::anyhow!("expected ROM path as first argument"))?;
    std::fs::read(&rom_path)
        .with_context(|| format!("failed to read ROM path `{}`", rom_path.display()))
}
<commit_msg>Box the windows so that we don't overflow the stack.<commit_after>mod audio;
mod debuggerui;
mod gbaui;
mod glutil;
mod pyrite_window;

use anyhow::Context as _;
use debuggerui::DebuggerWindow;
use gbaui::GbaWindow;
use glutin::{
    dpi::LogicalSize,
    event::{Event, WindowEvent},
    event_loop::{ControlFlow, EventLoop, EventLoopWindowTarget},
    window::{WindowBuilder, WindowId},
    PossiblyCurrent, WindowedContext,
};
use pyrite::{config::Config, GbaHandle};
use pyrite_window::PyriteWindow;

struct Windows {
    gba_handle: GbaHandle,
    gba: Box<GbaWindow>,
    debugger: Option<Box<DebuggerWindow>>,
    config: std::sync::Arc<Config>,
}

impl Windows {
    fn new(
        config: std::sync::Arc<Config>,
        window: WindowedContext<PossiblyCurrent>,
        gba: GbaHandle,
    ) -> anyhow::Result<Windows> {
        Ok(Windows {
            config: config.clone(),
            gba_handle: gba.clone(),
            gba: Box::new(
                GbaWindow::new(config, window, gba).context("error while creating GBA window")?,
            ),
            debugger: None,
        })
    }

    fn main_events_cleared(&mut self) {
        if self.gba.update() {
            self.gba.request_redraw();
        }

        if let Some(ref mut debugger) = self.debugger {
            if debugger.update() {
                debugger.request_redraw();
            }
        }
    }

    fn is_gba(&self, id: WindowId) -> bool {
        self.gba.window_id() == id
    }

    fn is_debugger(&self, id: WindowId) -> bool {
        self.debugger
            .as_ref()
            .filter(|d| d.window_id() == id)
            .is_some()
    }

    fn with_window<F>(&mut self, id: WindowId, f: F)
    where
        F: FnOnce(&mut dyn PyriteWindow),
    {
        if self.is_gba(id) {
            f(&mut *self.gba);
        } else if self.is_debugger(id) {
            if let Some(ref mut debugger) = self.debugger {
                f(&mut **debugger)
            }
        }
    }

    fn create_debugger_window(&mut self, el: &EventLoopWindowTarget<()>) -> anyhow::Result<()> {
        if self.debugger.is_some() {
            return Ok(());
        }

        let window = WindowBuilder::new()
            .with_title("Pyrite Debugger")
            .with_inner_size(LogicalSize::new(640.0f32, 320.0));
        let window = unsafe {
            glutin::ContextBuilder::new()
                .with_vsync(self.config.graphics.vsync.unwrap_or(true))
                .build_windowed(window, el)
                .context("failed to create windowed context")?
                .make_current()
                .map_err(|err| anyhow::anyhow!("{:?}", err))
                .context("failed to make window current")?
        };
        self.debugger = Some(Box::new(
            DebuggerWindow::new(self.gba_handle.clone(), window)
                .context("error while creating debugger window")?,
        ));

        Ok(())
    }

    fn close_debugger(&mut self) {
        self.debugger = None;
    }
}

fn on_window_event(
    event: WindowEvent,
    el: &EventLoopWindowTarget<()>,
    id: WindowId,
    windows: &mut Windows,
    flow: &mut ControlFlow,
) -> anyhow::Result<()> {
    match event {
        WindowEvent::CloseRequested if windows.is_gba(id) => {
            windows.with_window(id, |window| window.process_window_event(event));
            *flow = ControlFlow::Exit;
        }

        WindowEvent::CloseRequested if windows.is_debugger(id) => {
            windows.with_window(id, |window| window.process_window_event(event));
            windows.close_debugger();
        }

        event => {
            windows.with_window(id, |window| window.process_window_event(event));

            if windows.is_gba(id) {
                if windows.gba.wants_exit() {
                    *flow = ControlFlow::Exit;
                }

                if windows.gba.wants_debugger() {
                    if let Err(err) = windows.create_debugger_window(el) {
                        log::error!("error while creating debugger window: {err:?}");
                    }
                }
            } else if windows.is_debugger(id)
                && windows.debugger.as_ref().map(|d| d.wants_close()) == Some(true)
            {
                windows.close_debugger();
            }
        }
    }
    Ok(())
}

fn on_event(
    windows: &mut Windows,
    event: Event<()>,
    el: &EventLoopWindowTarget<()>,
    flow: &mut ControlFlow,
) -> anyhow::Result<()> {
    *flow = ControlFlow::Wait;

    match event {
        Event::WindowEvent { event, window_id } => {
            on_window_event(event, el, window_id, windows, flow)?
        }
        Event::RedrawRequested(window_id) => {
            windows.with_window(window_id, |window| window.gl_render(flow));
        }
        Event::MainEventsCleared => windows.main_events_cleared(),
        _ => *flow = ControlFlow::Poll,
    }
    Ok(())
}

fn run(event_loop: EventLoop<()>) -> anyhow::Result<()> {
    let config = std::sync::Arc::new(
        pyrite::config::from_toml_path("pyrite.toml")
            .map_err(|err| {
                let err = anyhow::Error::from(err);
                log::error!("{:#}", err);
            })
            .unwrap_or_default(),
    );

    let gba = pyrite::GbaHandle::new();
    let rom = get_rom_from_args().context("error occurred retrieving ROM from args")?;
    let bios = config.gba.bios_path.as_ref().and_then(|path| {
        match std::fs::read(&path)
            .with_context(|| format!("failed to read path {}", path.display()))
        {
            Ok(data) => Some(data),
            Err(err) => {
                log::error!("error occurred while loading BIOS: {:?}", err);
                None
            }
        }
    });
    let boot_from_bios = config.gba.boot_from_bios.unwrap_or(true);
    gba.after_frame_wait(move |gba, _| {
        gba.set_gamepak(rom);
        gba.set_bios(bios);
        gba.reset(boot_from_bios);
    });
    let _stream = audio::run(gba.clone()).context("error while starting audio")?;

    let window = WindowBuilder::new()
        .with_title("Pyrite")
        .with_inner_size(LogicalSize::new(480.0f32, 320.0));
    let window = unsafe {
        glutin::ContextBuilder::new()
            .with_vsync(config.graphics.vsync.unwrap_or(true))
            .build_windowed(window, &event_loop)
            .context("failed to create windowed context")?
            .make_current()
            .map_err(|err| anyhow::anyhow!("{:?}", err))
            .context("failed to make window current")?
    };
    let mut windows = Windows::new(config, window, gba).context("error initializing windows")?;

    windows.gba_handle.set_paused(false);
    event_loop.run(move |event, el, control_flow| {
        if let Err(err) = on_event(&mut windows, event, el, control_flow) {
            log::error!("error occurred in event loop: {:?}", err);
            *control_flow = ControlFlow::Exit;
        }
    });
}

fn main() -> anyhow::Result<()> {
    pretty_env_logger::init();
    let event_loop = EventLoop::new();

    run(event_loop).context("error occurred while running main loop")?;
    unreachable!("run should never return unless there is an error");
}

fn get_rom_from_args() -> anyhow::Result<Vec<u8>> {
    let rom_path = std::env::args()
        .nth(1)
        .map(std::path::PathBuf::from)
        .ok_or_else(|| anyhow::anyhow!("expected ROM path as first argument"))?;
    std::fs::read(&rom_path)
        .with_context(|| format!("failed to read ROM path `{}`", rom_path.display()))
}
<|endoftext|>


<commit_before>use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::{in_macro, is_automatically_derived, is_default_equivalent, remove_blocks};
use rustc_hir::{
    def::{DefKind, Res},
    Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;

declare_clippy_lint! {
    /// ### What it does
    /// Detects manual `std::default::Default` implementations that are identical to a derived implementation.
    ///
    /// ### Why is this bad?
    /// It is less concise.
    ///
    /// ### Example
    /// ```rust
    /// struct Foo {
    ///     bar: bool
    /// }
    ///
    /// impl std::default::Default for Foo {
    ///     fn default() -> Self {
    ///         Self {
    ///             bar: false
    ///         }
    ///     }
    /// }
    /// ```
    ///
    /// Could be written as:
    ///
    /// ```rust
    /// #[derive(Default)]
    /// struct Foo {
    ///     bar: bool
    /// }
    /// ```
    ///
    /// ### Known problems
    /// Derive macros [sometimes use incorrect bounds](https://github.com/rust-lang/rust/issues/26925)
    /// in generic types and the user defined `impl` maybe is more generalized or
    /// specialized than what derive will produce. This lint can't detect the manual `impl`
    /// has exactly equal bounds, and therefore this lint is disabled for types with
    /// generic parameters.
    ///
    pub DERIVABLE_IMPLS,
    complexity,
    "manual implementation of the `Default` trait which is equal to a derive"
}

declare_lint_pass!(DerivableImpls => [DERIVABLE_IMPLS]);

fn is_path_self(e: &Expr<'_>) -> bool {
    if let ExprKind::Path(QPath::Resolved(_, p)) = e.kind {
        matches!(p.res, Res::SelfCtor(..) | Res::Def(DefKind::Ctor(..), _))
    } else {
        false
    }
}

impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
        if_chain! {
            if let ItemKind::Impl(Impl {
                of_trait: Some(ref trait_ref),
                items: [child],
                self_ty,
                ..
            }) = item.kind;
            if let attrs = cx.tcx.hir().attrs(item.hir_id());
            if !is_automatically_derived(attrs);
            if !in_macro(item.span);
            if let Some(def_id) = trait_ref.trait_def_id();
            if cx.tcx.is_diagnostic_item(sym::Default, def_id);
            if let impl_item_hir = child.id.hir_id();
            if let Some(Node::ImplItem(impl_item)) = cx.tcx.hir().find(impl_item_hir);
            if let ImplItemKind::Fn(_, b) = &impl_item.kind;
            if let Body { value: func_expr, .. } = cx.tcx.hir().body(*b);
            if let Some(adt_def) = cx.tcx.type_of(item.def_id).ty_adt_def();
            if !attrs.iter().any(|attr| attr.doc_str().is_some());
            if let child_attrs = cx.tcx.hir().attrs(impl_item_hir);
            if !child_attrs.iter().any(|attr| attr.doc_str().is_some());
            if !adt_def.is_enum();
            then {
                if let TyKind::Path(QPath::Resolved(_, p)) = self_ty.kind {
                    if let Some(PathSegment { args: Some(a), .. }) = p.segments.last() {
                        for arg in a.args {
                            if !matches!(arg, GenericArg::Lifetime(_)) {
                                return;
                            }
                        }
                    }
                }
                let should_emit = match remove_blocks(func_expr).kind {
                    ExprKind::Tup(fields) => fields.iter().all(|e| is_default_equivalent(cx, e)),
                    ExprKind::Call(callee, args)
                        if is_path_self(callee) => args.iter().all(|e| is_default_equivalent(cx, e)),
                    ExprKind::Struct(_, fields, _) => fields.iter().all(|ef| is_default_equivalent(cx, ef.expr)),
                    _ => false,
                };
                if should_emit {
                    let path_string = cx.tcx.def_path_str(adt_def.did);
                    span_lint_and_help(
                        cx,
                        DERIVABLE_IMPLS,
                        item.span,
                        "this `impl` can be derived",
                        None,
                        &format!("try annotating `{}` with `#[derive(Default)]`", path_string),
                    );
                }
            }
        }
    }
}
<commit_msg>Change not enum to is struct<commit_after>use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::{in_macro, is_automatically_derived, is_default_equivalent, remove_blocks};
use rustc_hir::{
    def::{DefKind, Res},
    Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;

declare_clippy_lint! {
    /// ### What it does
    /// Detects manual `std::default::Default` implementations that are identical to a derived implementation.
    ///
    /// ### Why is this bad?
    /// It is less concise.
    ///
    /// ### Example
    /// ```rust
    /// struct Foo {
    ///     bar: bool
    /// }
    ///
    /// impl std::default::Default for Foo {
    ///     fn default() -> Self {
    ///         Self {
    ///             bar: false
    ///         }
    ///     }
    /// }
    /// ```
    ///
    /// Could be written as:
    ///
    /// ```rust
    /// #[derive(Default)]
    /// struct Foo {
    ///     bar: bool
    /// }
    /// ```
    ///
    /// ### Known problems
    /// Derive macros [sometimes use incorrect bounds](https://github.com/rust-lang/rust/issues/26925)
    /// in generic types and the user defined `impl` maybe is more generalized or
    /// specialized than what derive will produce. This lint can't detect the manual `impl`
    /// has exactly equal bounds, and therefore this lint is disabled for types with
    /// generic parameters.
    ///
    pub DERIVABLE_IMPLS,
    complexity,
    "manual implementation of the `Default` trait which is equal to a derive"
}

declare_lint_pass!(DerivableImpls => [DERIVABLE_IMPLS]);

fn is_path_self(e: &Expr<'_>) -> bool {
    if let ExprKind::Path(QPath::Resolved(_, p)) = e.kind {
        matches!(p.res, Res::SelfCtor(..) | Res::Def(DefKind::Ctor(..), _))
    } else {
        false
    }
}

impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
        if_chain! {
            if let ItemKind::Impl(Impl {
                of_trait: Some(ref trait_ref),
                items: [child],
                self_ty,
                ..
            }) = item.kind;
            if let attrs = cx.tcx.hir().attrs(item.hir_id());
            if !is_automatically_derived(attrs);
            if !in_macro(item.span);
            if let Some(def_id) = trait_ref.trait_def_id();
            if cx.tcx.is_diagnostic_item(sym::Default, def_id);
            if let impl_item_hir = child.id.hir_id();
            if let Some(Node::ImplItem(impl_item)) = cx.tcx.hir().find(impl_item_hir);
            if let ImplItemKind::Fn(_, b) = &impl_item.kind;
            if let Body { value: func_expr, .. } = cx.tcx.hir().body(*b);
            if let Some(adt_def) = cx.tcx.type_of(item.def_id).ty_adt_def();
            if !attrs.iter().any(|attr| attr.doc_str().is_some());
            if let child_attrs = cx.tcx.hir().attrs(impl_item_hir);
            if !child_attrs.iter().any(|attr| attr.doc_str().is_some());
            if adt_def.is_struct();
            then {
                if let TyKind::Path(QPath::Resolved(_, p)) = self_ty.kind {
                    if let Some(PathSegment { args: Some(a), .. }) = p.segments.last() {
                        for arg in a.args {
                            if !matches!(arg, GenericArg::Lifetime(_)) {
                                return;
                            }
                        }
                    }
                }
                let should_emit = match remove_blocks(func_expr).kind {
                    ExprKind::Tup(fields) => fields.iter().all(|e| is_default_equivalent(cx, e)),
                    ExprKind::Call(callee, args)
                        if is_path_self(callee) => args.iter().all(|e| is_default_equivalent(cx, e)),
                    ExprKind::Struct(_, fields, _) => fields.iter().all(|ef| is_default_equivalent(cx, ef.expr)),
                    _ => false,
                };
                if should_emit {
                    let path_string = cx.tcx.def_path_str(adt_def.did);
                    span_lint_and_help(
                        cx,
                        DERIVABLE_IMPLS,
                        item.span,
                        "this `impl` can be derived",
                        None,
                        &format!("try annotating `{}` with `#[derive(Default)]`", path_string),
                    );
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Checks for needless address of operations (`&`)
//!
//! This lint is **warn** by default

use rustc::lint::*;
use rustc::hir::{BindingAnnotation, Expr, ExprAddrOf, MutImmutable, Pat, PatKind};
use rustc::ty;
use rustc::ty::adjustment::{Adjust, Adjustment};
use utils::{in_macro, span_lint};

/// **What it does:** Checks for address of operations (`&`) that are going to
/// be dereferenced immediately by the compiler.
///
/// **Why is this bad?** Suggests that the receiver of the expression borrows
/// the expression.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// let x: &i32 = &&&&&&5;
/// ```
declare_lint! {
    pub NEEDLESS_BORROW,
    Warn,
    "taking a reference that is going to be automatically dereferenced"
}

#[derive(Copy, Clone)]
pub struct NeedlessBorrow;

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

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrow {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
        if in_macro(e.span) {
            return;
        }
        if let ExprAddrOf(MutImmutable, ref inner) = e.node {
            if let ty::TyRef(..) = cx.tables.expr_ty(inner).sty {
                for adj3 in cx.tables.expr_adjustments(e).windows(3) {
                    if let [Adjustment {
                        kind: Adjust::Deref(_),
                        ..
                    }, Adjustment {
                        kind: Adjust::Deref(_),
                        ..
                    }, Adjustment {
                        kind: Adjust::Borrow(_),
                        ..
                    }] = *adj3
                    {
                        span_lint(
                            cx,
                            NEEDLESS_BORROW,
                            e.span,
                            "this expression borrows a reference that is immediately dereferenced by the \
                             compiler",
                        );
                    }
                }
            }
        }
    }
    fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat) {
        if in_macro(pat.span) {
            return;
        }
        if_let_chain! {[
            let PatKind::Binding(BindingAnnotation::Ref, _, _, _) = pat.node,
            let ty::TyRef(_, ref tam) = cx.tables.pat_ty(pat).sty,
            tam.mutbl == MutImmutable,
            let ty::TyRef(_, ref tam) = tam.ty.sty,
            // only lint immutable refs, because borrowed `&mut T` cannot be moved out
            tam.mutbl == MutImmutable,
        ], {
            span_lint(cx, NEEDLESS_BORROW, pat.span, "this pattern creates a reference to a reference")
        }}
    }
}
<commit_msg>Add suggestion to needless_borrow<commit_after>//! Checks for needless address of operations (`&`)
//!
//! This lint is **warn** by default

use rustc::lint::*;
use rustc::hir::{BindingAnnotation, Expr, ExprAddrOf, MutImmutable, Pat, PatKind};
use rustc::ty;
use rustc::ty::adjustment::{Adjust, Adjustment};
use utils::{in_macro, snippet_opt, span_lint_and_then};

/// **What it does:** Checks for address of operations (`&`) that are going to
/// be dereferenced immediately by the compiler.
///
/// **Why is this bad?** Suggests that the receiver of the expression borrows
/// the expression.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// let x: &i32 = &&&&&&5;
/// ```
declare_lint! {
    pub NEEDLESS_BORROW,
    Warn,
    "taking a reference that is going to be automatically dereferenced"
}

#[derive(Copy, Clone)]
pub struct NeedlessBorrow;

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

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrow {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
        if in_macro(e.span) {
            return;
        }
        if let ExprAddrOf(MutImmutable, ref inner) = e.node {
            if let ty::TyRef(..) = cx.tables.expr_ty(inner).sty {
                for adj3 in cx.tables.expr_adjustments(e).windows(3) {
                    if let [Adjustment {
                        kind: Adjust::Deref(_),
                        ..
                    }, Adjustment {
                        kind: Adjust::Deref(_),
                        ..
                    }, Adjustment {
                        kind: Adjust::Borrow(_),
                        ..
                    }] = *adj3
                    {
                        span_lint_and_then(
                            cx,
                            NEEDLESS_BORROW,
                            e.span,
                            "this expression borrows a reference that is immediately dereferenced \
                             by the compiler",
                            |db| {
                                if let Some(snippet) = snippet_opt(cx, inner.span) {
                                    db.span_suggestion(e.span, "change this to", snippet);
                                }
                            }
                        );
                    }
                }
            }
        }
    }
    fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat) {
        if in_macro(pat.span) {
            return;
        }
        if_let_chain! {[
            let PatKind::Binding(BindingAnnotation::Ref, _, name, _) = pat.node,
            let ty::TyRef(_, ref tam) = cx.tables.pat_ty(pat).sty,
            tam.mutbl == MutImmutable,
            let ty::TyRef(_, ref tam) = tam.ty.sty,
            // only lint immutable refs, because borrowed `&mut T` cannot be moved out
            tam.mutbl == MutImmutable,
        ], {
            span_lint_and_then(
                cx,
                NEEDLESS_BORROW,
                pat.span,
                "this pattern creates a reference to a reference",
                |db| {
                    if let Some(snippet) = snippet_opt(cx, name.span) {
                        db.span_suggestion(pat.span, "change this to", snippet);
                    }
                }
            )
        }}
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::borrow::Cow;
use std::marker::PhantomData;
use std::mem;
use std::ptr;
use std::sync::Arc;
use std::ffi::CStr;

use device::Device;
use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Contains SPIR-V code with one or more entry points.
///
/// Note that it is advised to wrap around a `ShaderModule` with a struct that is different for
/// each shader.
pub struct ShaderModule {
    device: Arc<Device>,
    module: vk::ShaderModule,
}

impl ShaderModule {
    /// Builds a new shader module from SPIR-V.
    ///
    /// # Safety
    ///
    /// - The SPIR-V code is not validated.
    /// - The SPIR-V code may require some features that are not enabled. This isn't checked by
    ///   this function either.
    ///
    pub unsafe fn new(device: &Arc<Device>, spirv: &[u8])
                      -> Result<Arc<ShaderModule>, OomError>
    {
        let vk = device.pointers();

        assert!((spirv.len() % 4) == 0);

        let module = {
            let infos = vk::ShaderModuleCreateInfo {
                sType: vk::STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,   // reserved
                codeSize: spirv.len(),
                pCode: spirv.as_ptr() as *const _,
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateShaderModule(device.internal_object(), &infos,
                                                    ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(ShaderModule {
            device: device.clone(),
            module: module,
        }))
    }

    pub unsafe fn vertex_shader_entry_point<'a, S, V, L>(&'a self, name: &'a CStr, layout: L,
                                                         attributes: Vec<(u32, Cow<'static, str>)>)
                                                         -> VertexShaderEntryPoint<'a, S, V, L>
    {
        VertexShaderEntryPoint {
            module: self,
            name: name,
            layout: layout,
            attributes: attributes,
            marker: PhantomData,
        }
    }

    /// Gets access to an entry point contained in this module.
    ///
    /// This is purely a *logical* operation. It returns a struct that *represents* the entry
    /// point but doesn't actually do anything.
    ///
    /// # Safety
    ///
    /// - The user must check that the entry point exists in the module, as this is not checked
    ///   by Vulkan.
    /// - Calling this function also determines the template parameters associated to the
    ///   `EntryPoint` struct. Therefore care must be taken that the values there are correct.
    ///
    pub unsafe fn fragment_shader_entry_point<'a, S, F, L>(&'a self, name: &'a CStr, layout: L)
                                                           -> FragmentShaderEntryPoint<'a, S, F, L>
    {
        FragmentShaderEntryPoint {
            module: self,
            name: name,
            layout: layout,
            marker: PhantomData,
        }
    }

    #[inline]
    pub unsafe fn compute_shader_entry_point<'a, S, L>(&'a self, name: &'a CStr, layout: L)
                                                       -> ComputeShaderEntryPoint<'a, S, L>
    {
        ComputeShaderEntryPoint {
            module: self,
            name: name,
            layout: layout,
            marker: PhantomData,
        }
    }
}

unsafe impl VulkanObject for ShaderModule {
    type Object = vk::ShaderModule;

    #[inline]
    fn internal_object(&self) -> vk::ShaderModule {
        self.module
    }
}

impl Drop for ShaderModule {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyShaderModule(self.device.internal_object(), self.module, ptr::null());
        }
    }
}

pub struct VertexShaderEntryPoint<'a, S, V, L> {
    module: &'a ShaderModule,
    name: &'a CStr,
    attributes: Vec<(u32, Cow<'static, str>)>,
    layout: L,
    marker: PhantomData<(S, V)>,
}

impl<'a, S, V, L> VertexShaderEntryPoint<'a, S, V, L> {
    #[inline]
    pub fn module(&self) -> &'a ShaderModule {
        self.module
    }

    #[inline]
    pub fn name(&self) -> &'a CStr {
        self.name
    }

    #[inline]
    pub fn layout(&self) -> &L {
        &self.layout
    }

    // TODO: change API
    #[inline]
    pub fn attributes(&self) -> &[(u32, Cow<'static, str>)] {
        &self.attributes
    }
}

pub struct ComputeShaderEntryPoint<'a, S, L> {
    module: &'a ShaderModule,
    name: &'a CStr,
    layout: L,
    marker: PhantomData<S>,
}

impl<'a, S, L> ComputeShaderEntryPoint<'a, S, L> {
    #[inline]
    pub fn module(&self) -> &'a ShaderModule {
        self.module
    }

    #[inline]
    pub fn name(&self) -> &'a CStr {
        self.name
    }

    #[inline]
    pub fn layout(&self) -> &L {
        &self.layout
    }
}

pub struct FragmentShaderEntryPoint<'a, S, F, L> {
    module: &'a ShaderModule,
    name: &'a CStr,
    layout: L,
    marker: PhantomData<(S, F)>,
}

impl<'a, S, F, L> FragmentShaderEntryPoint<'a, S, F, L> {
    #[inline]
    pub fn module(&self) -> &'a ShaderModule {
        self.module
    }

    #[inline]
    pub fn name(&self) -> &'a CStr {
        self.name
    }

    #[inline]
    pub fn layout(&self) -> &L {
        &self.layout
    }
}

pub unsafe trait ShaderInterfaceDef {
}

pub unsafe trait PossibleMatchShaderInterface<I>: ShaderInterfaceDef where I: ShaderInterfaceDef {
    fn matches(&self, other: &I) -> bool;
}

/// Trait to describe structs that contain specialization data for shaders.
///
/// It is implemented on `()` for shaders that don't have any specialization constant.
pub unsafe trait SpecializationConstants {
    /// Returns descriptors of the struct's layout.
    fn descriptors() -> &'static [SpecializationMapEntry];
}

unsafe impl SpecializationConstants for () {
    #[inline]
    fn descriptors() -> &'static [SpecializationMapEntry] {
        &[]
    }
}

/// Describes an indiviual constant to set in the shader. Also a field in the struct.
// Has the same memory representation as a `VkSpecializationMapEntry`.
#[repr(C)]
pub struct SpecializationMapEntry {
    /// Identifier of the constant in the shader that corresponds to this field.
    pub constant_id: u32,
    /// Offset within this struct for the data.
    pub offset: u32,
    /// Size of the data in bytes.
    pub size: usize,
}

/// Trait to describe structs that contain push constants for shaders.
///
/// It is implemented on `()` for shaders that don't have any push constant.
pub unsafe trait PushConstants {
    // TODO:
}

unsafe impl PushConstants for () {
}
<commit_msg>Add all shader entry points in the shader module<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::borrow::Cow;
use std::marker::PhantomData;
use std::mem;
use std::ptr;
use std::sync::Arc;
use std::ffi::CStr;

use device::Device;
use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Contains SPIR-V code with one or more entry points.
///
/// Note that it is advised to wrap around a `ShaderModule` with a struct that is different for
/// each shader.
pub struct ShaderModule {
    device: Arc<Device>,
    module: vk::ShaderModule,
}

impl ShaderModule {
    /// Builds a new shader module from SPIR-V.
    ///
    /// # Safety
    ///
    /// - The SPIR-V code is not validated.
    /// - The SPIR-V code may require some features that are not enabled. This isn't checked by
    ///   this function either.
    ///
    pub unsafe fn new(device: &Arc<Device>, spirv: &[u8])
                      -> Result<Arc<ShaderModule>, OomError>
    {
        let vk = device.pointers();

        assert!((spirv.len() % 4) == 0);

        let module = {
            let infos = vk::ShaderModuleCreateInfo {
                sType: vk::STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,   // reserved
                codeSize: spirv.len(),
                pCode: spirv.as_ptr() as *const _,
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateShaderModule(device.internal_object(), &infos,
                                                    ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(ShaderModule {
            device: device.clone(),
            module: module,
        }))
    }

    pub unsafe fn vertex_shader_entry_point<'a, S, V, L>(&'a self, name: &'a CStr, layout: L,
                                                         attributes: Vec<(u32, Cow<'static, str>)>)
                                                         -> VertexShaderEntryPoint<'a, S, V, L>
    {
        VertexShaderEntryPoint {
            module: self,
            name: name,
            layout: layout,
            attributes: attributes,
            marker: PhantomData,
        }
    }

    pub unsafe fn tess_control_shader_entry_point<'a, S, I, O, L>(&'a self, name: &'a CStr, layout: L)
                                                              -> TessControlShaderEntryPoint<'a, S, I, O, L>
    {
        TessControlShaderEntryPoint {
            module: self,
            name: name,
            layout: layout,
            marker: PhantomData,
        }
    }

    pub unsafe fn tess_evaluation_shader_entry_point<'a, S, I, O, L>(&'a self, name: &'a CStr, layout: L)
                                                                     -> TessEvaluationShaderEntryPoint<'a, S, I, O, L>
    {
        TessEvaluationShaderEntryPoint {
            module: self,
            name: name,
            layout: layout,
            marker: PhantomData,
        }
    }

    pub unsafe fn geometry_shader_entry_point<'a, S, I, O, L>(&'a self, name: &'a CStr, layout: L)
                                                              -> GeometryShaderEntryPoint<'a, S, I, O, L>
    {
        GeometryShaderEntryPoint {
            module: self,
            name: name,
            layout: layout,
            marker: PhantomData,
        }
    }

    /// Gets access to an entry point contained in this module.
    ///
    /// This is purely a *logical* operation. It returns a struct that *represents* the entry
    /// point but doesn't actually do anything.
    ///
    /// # Safety
    ///
    /// - The user must check that the entry point exists in the module, as this is not checked
    ///   by Vulkan.
    /// - Calling this function also determines the template parameters associated to the
    ///   `EntryPoint` struct. Therefore care must be taken that the values there are correct.
    ///
    pub unsafe fn fragment_shader_entry_point<'a, S, F, L>(&'a self, name: &'a CStr, layout: L)
                                                           -> FragmentShaderEntryPoint<'a, S, F, L>
    {
        FragmentShaderEntryPoint {
            module: self,
            name: name,
            layout: layout,
            marker: PhantomData,
        }
    }

    #[inline]
    pub unsafe fn compute_shader_entry_point<'a, S, L>(&'a self, name: &'a CStr, layout: L)
                                                       -> ComputeShaderEntryPoint<'a, S, L>
    {
        ComputeShaderEntryPoint {
            module: self,
            name: name,
            layout: layout,
            marker: PhantomData,
        }
    }
}

unsafe impl VulkanObject for ShaderModule {
    type Object = vk::ShaderModule;

    #[inline]
    fn internal_object(&self) -> vk::ShaderModule {
        self.module
    }
}

impl Drop for ShaderModule {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyShaderModule(self.device.internal_object(), self.module, ptr::null());
        }
    }
}

pub struct VertexShaderEntryPoint<'a, S, V, L> {
    module: &'a ShaderModule,
    name: &'a CStr,
    attributes: Vec<(u32, Cow<'static, str>)>,
    layout: L,
    marker: PhantomData<(S, V)>,
}

impl<'a, S, V, L> VertexShaderEntryPoint<'a, S, V, L> {
    #[inline]
    pub fn module(&self) -> &'a ShaderModule {
        self.module
    }

    #[inline]
    pub fn name(&self) -> &'a CStr {
        self.name
    }

    #[inline]
    pub fn layout(&self) -> &L {
        &self.layout
    }

    // TODO: change API
    #[inline]
    pub fn attributes(&self) -> &[(u32, Cow<'static, str>)] {
        &self.attributes
    }
}

pub struct TessControlShaderEntryPoint<'a, S, I, O, L> {
    module: &'a ShaderModule,
    name: &'a CStr,
    layout: L,
    marker: PhantomData<(S, I, O)>,
}

impl<'a, S, I, O, L> TessControlShaderEntryPoint<'a, S, I, O, L> {
    #[inline]
    pub fn module(&self) -> &'a ShaderModule {
        self.module
    }

    #[inline]
    pub fn name(&self) -> &'a CStr {
        self.name
    }

    #[inline]
    pub fn layout(&self) -> &L {
        &self.layout
    }
}

pub struct TessEvaluationShaderEntryPoint<'a, S, I, O, L> {
    module: &'a ShaderModule,
    name: &'a CStr,
    layout: L,
    marker: PhantomData<(S, I, O)>,
}

impl<'a, S, I, O, L> TessEvaluationShaderEntryPoint<'a, S, I, O, L> {
    #[inline]
    pub fn module(&self) -> &'a ShaderModule {
        self.module
    }

    #[inline]
    pub fn name(&self) -> &'a CStr {
        self.name
    }

    #[inline]
    pub fn layout(&self) -> &L {
        &self.layout
    }
}

pub struct GeometryShaderEntryPoint<'a, S, I, O, L> {
    module: &'a ShaderModule,
    name: &'a CStr,
    layout: L,
    marker: PhantomData<(S, I, O)>,
}

impl<'a, S, I, O, L> GeometryShaderEntryPoint<'a, S, I, O, L> {
    #[inline]
    pub fn module(&self) -> &'a ShaderModule {
        self.module
    }

    #[inline]
    pub fn name(&self) -> &'a CStr {
        self.name
    }

    #[inline]
    pub fn layout(&self) -> &L {
        &self.layout
    }
}

pub struct FragmentShaderEntryPoint<'a, S, F, L> {
    module: &'a ShaderModule,
    name: &'a CStr,
    layout: L,
    marker: PhantomData<(S, F)>,
}

impl<'a, S, F, L> FragmentShaderEntryPoint<'a, S, F, L> {
    #[inline]
    pub fn module(&self) -> &'a ShaderModule {
        self.module
    }

    #[inline]
    pub fn name(&self) -> &'a CStr {
        self.name
    }

    #[inline]
    pub fn layout(&self) -> &L {
        &self.layout
    }
}

pub struct ComputeShaderEntryPoint<'a, S, L> {
    module: &'a ShaderModule,
    name: &'a CStr,
    layout: L,
    marker: PhantomData<S>,
}

impl<'a, S, L> ComputeShaderEntryPoint<'a, S, L> {
    #[inline]
    pub fn module(&self) -> &'a ShaderModule {
        self.module
    }

    #[inline]
    pub fn name(&self) -> &'a CStr {
        self.name
    }

    #[inline]
    pub fn layout(&self) -> &L {
        &self.layout
    }
}

pub unsafe trait ShaderInterfaceDef {
}

pub unsafe trait PossibleMatchShaderInterface<I>: ShaderInterfaceDef where I: ShaderInterfaceDef {
    fn matches(&self, other: &I) -> bool;
}

/// Trait to describe structs that contain specialization data for shaders.
///
/// It is implemented on `()` for shaders that don't have any specialization constant.
pub unsafe trait SpecializationConstants {
    /// Returns descriptors of the struct's layout.
    fn descriptors() -> &'static [SpecializationMapEntry];
}

unsafe impl SpecializationConstants for () {
    #[inline]
    fn descriptors() -> &'static [SpecializationMapEntry] {
        &[]
    }
}

/// Describes an indiviual constant to set in the shader. Also a field in the struct.
// Has the same memory representation as a `VkSpecializationMapEntry`.
#[repr(C)]
pub struct SpecializationMapEntry {
    /// Identifier of the constant in the shader that corresponds to this field.
    pub constant_id: u32,
    /// Offset within this struct for the data.
    pub offset: u32,
    /// Size of the data in bytes.
    pub size: usize,
}

/// Trait to describe structs that contain push constants for shaders.
///
/// It is implemented on `()` for shaders that don't have any push constant.
pub unsafe trait PushConstants {
    // TODO:
}

unsafe impl PushConstants for () {
}
<|endoftext|>