<commit_before>//! Support for whitespace delimited formats
//!

#[macro_export]
macro_rules! wrap_sep (
  ($i:expr, $separator:expr, $submac:ident!( $($args:tt)* )) => (
    match ($separator)($i) {
      $crate::IResult::Error(e)      => $crate::IResult::Error(e),
      $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i),
      $crate::IResult::Done(i1,_)    => {
        match $submac!(i1, $($args)*) {
          $crate::IResult::Error(e)      => $crate::IResult::Error(e),
          $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i),
          $crate::IResult::Done(i2,o)    => {
            match ($separator)(i2) {
              $crate::IResult::Error(e)      => $crate::IResult::Error(e),
              $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i),
              $crate::IResult::Done(i3,_)    => $crate::IResult::Done(i3, o)
            }
          }
        }
      }
    }
  );
  ($i:expr, $separator:expr, $f:expr) => (
    wrap_sep!($i, $separator, call!($f))
  );
);

#[macro_export]
macro_rules! pair_sep (
  ($i:expr, $separator:ident, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => (
    tuple!(
      $i,
      sep!($separator, $submac!($($args)*)),
      sep!($separator, $submac2!($($args2)*))
    )
  );
  ($i:expr, $separator:ident, $submac:ident!( $($args:tt)* ), $g:expr) => (
    pair_sep!($i, $separator, $submac!($($args)*), call!($g));
  );
  ($i:expr, $separator:ident, $f:expr, $submac:ident!( $($args:tt)* )) => (
    pair_sep!($i, $separator, call!($f), $submac!($($args)*));
  );
  ($i:expr, $separator:ident, $f:expr, $g:expr) => (
    pair_sep!($i, $separator, call!($f), call!($g));
  );
);

#[macro_export]
macro_rules! preceded_sep (
  ($i:expr, $separator:ident, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => (
    match pair_sep!($i, $separator, $submac!($($args)*), $submac2!($($args2)*)) {
      $crate::IResult::Error(a)               => $crate::IResult::Error(a),
      $crate::IResult::Incomplete(i)          => $crate::IResult::Incomplete(i),
      $crate::IResult::Done(remaining, (_,o)) => {
        $crate::IResult::Done(remaining, o)
      }
    }
  );
  ($i:expr, $separator:ident, $submac:ident!( $($args:tt)* ), $g:expr) => (
    preceded_sep!($i, $separator, $submac!($($args)*), call!($g));
  );
  ($i:expr, $separator:ident, $f:expr, $submac:ident!( $($args:tt)* )) => (
    preceded_sep!($i, $separator, call!($f), $submac!($($args)*));
  );
  ($i:expr, $separator:ident, $f:expr, $g:expr) => (
    preceded_sep!($i, $separator, call!($f), call!($g));
  );
);

#[macro_export]
macro_rules! terminated_sep (
  ($i:expr, $separator:ident, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => (
    match pair_sep!($i, $separator, $submac!($($args)*), $submac2!($($args2)*)) {
      $crate::IResult::Error(a)               => $crate::IResult::Error(a),
      $crate::IResult::Incomplete(i)          => $crate::IResult::Incomplete(i),
      $crate::IResult::Done(remaining, (o,_)) => {
        $crate::IResult::Done(remaining, o)
      }
    }
  );
  ($i:expr, $separator:ident, $submac:ident!( $($args:tt)* ), $g:expr) => (
    terminated_wrap!($i, $separator, $submac!($($args)*), call!($g));
  );
  ($i:expr, $separator:ident, $f:expr, $submac:ident!( $($args:tt)* )) => (
    terminated_sep!($i, $separator, call!($f), $submac!($($args)*));
  );
  ($i:expr, $separator:ident, $f:expr, $g:expr) => (
    terminated_sep!($i, $separator, call!($f), call!($g));
  );
);

/// Internal parser, do not use directly
#[doc(hidden)]
#[macro_export]
macro_rules! tuple_sep (
  ($i:expr, $separator:ident, $consumed:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => (
    tuple_sep!($i, $separator, $consumed, ($($parsed),*), call!($e), $($rest)*);
  );
  ($i:expr, $separator:ident, $consumed:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => (
    {
      match sep!($i, $separator, $submac!($($args)*)) {
        $crate::IResult::Error(e)                            => $crate::IResult::Error(e),
        $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown),
        $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)),
        $crate::IResult::Done(i,o)     => {
          tuple_sep!(i, $separator, $consumed + ($crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&i)), (o), $($rest)*)
        }
      }
    }
  );
  ($i:expr, $separator:ident, $consumed:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => (
    {
      match sep!($i, $separator, $submac!($($args)*)) {
        $crate::IResult::Error(e)                            => $crate::IResult::Error(e),
        $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown),
        $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)),
        $crate::IResult::Done(i,o)     => {
          tuple_sep!(i, $separator, $consumed + ($crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&i)), ($($parsed)* , o), $($rest)*)
        }
      }
    }
  );
  ($i:expr, $separator:ident, $consumed:expr, ($($parsed:tt),*), $e:ident) => (
    tuple_sep!($i, $separator,  $consumed, ($($parsed),*), call!($e));
  );
  ($i:expr, $separator:ident, $consumed:expr, (), $submac:ident!( $($args:tt)* )) => (
    {
      match sep!($i, $separator, $submac!($($args)*)) {
        $crate::IResult::Error(e)                            => $crate::IResult::Error(e),
        $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown),
        $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)),
        $crate::IResult::Done(i,o)     => {
          $crate::IResult::Done(i, (o))
        }
      }
    }
  );
  ($i:expr, $separator:ident, $consumed:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => (
    {
      match sep!($i, $separator, $submac!($($args)*)) {
        $crate::IResult::Error(e)                            => $crate::IResult::Error(e),
        $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown),
        $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)),
        $crate::IResult::Done(i,o)     => {
          $crate::IResult::Done(i, ($($parsed),* , o))
        }
      }
    }
  );
  ($i:expr, $separator:ident, $consumed:expr, ($($parsed:expr),*)) => (
    {
      $crate::IResult::Done($i, ($($parsed),*))
    }
  );
);

#[macro_export]
macro_rules! eat_separator (
  ($i:expr, $arr:expr) => (
    {
      use $crate::traits::{InputLength,IterIndices,Slice};
      if ($i).input_len() == 0 {
        $crate::IResult::Done($i, &($i)[0..0])
      } else {
        match ($i).iter_indices().position(|(_, item)| {
          for (_,c) in ($arr).iter_indices() {
            if c == item { return false; }
          }
          true
        }) {
          Some(index) => {
            $crate::IResult::Done(($i).slice(index..), ($i).slice(..index))
          },
          None        => {
            $crate::IResult::Done(($i).slice(($i).input_len()..), $i)
          }
        }
      }
    }
  );
);

#[macro_export]
macro_rules! sep (
  ($i:expr,  $separator:ident, tuple ! ($($rest:tt)*) ) => {
    tuple_sep!($i, $separator, 0usize, (), $($rest)*)
  };
  ($i:expr,  $separator:ident, pair ! ($($rest:tt)*) ) => {
    wrap_sep!($i,
      $separator,
      pair_sep!($separator, $($rest)*)
    )
  };
  ($i:expr,  $separator:ident, preceded ! ($($rest:tt)*) ) => {
    wrap_sep!($i,
      $separator,
      preceded_sep!($separator, $($rest)*)
    )
  };
  ($i:expr,  $separator:ident, terminated ! ($($rest:tt)*) ) => {
    wrap_sep!($i,
      $separator,
      terminated_sep!($separator, $($rest)*)
    )
  };
  ($i:expr, $separator:ident, $submac:ident!( $($args:tt)* )) => {
    wrap_sep!($i, $separator, $submac!($($args)*))
  };
  ($i:expr, $separator:ident, $f:expr) => {
    wrap_sep!($i, $separator, call!($f))
  };
);

named!(pub sp, eat_separator!(b" \t\r\n"));

#[macro_export]
macro_rules! ws (
  ($i:expr, $($args:tt)*) => (
    {
      use $crate::sp;
      sep!($i, sp, $($args)*)
    }
  )
);

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

  #[test]
  fn spaaaaace() {
    assert_eq!(sp(&b" \t abc "[..]),  Done(&b"abc "[..], &b" \t "[..]));
  }

  #[test]
  fn tag() {
    named!(abc, ws!(tag!("abc")));

    assert_eq!(abc(&b" \t abc def"[..]),  Done(&b"def"[..], &b"abc"[..]));
  }

  #[test]
  fn pair() {
    named!(pair_2<&[u8], (&[u8], &[u8]) >,
      ws!(pair!( take!(3), tag!("de") ))
    );

    assert_eq!(pair_2(&b" \t abc de fg"[..]),  Done(&b"fg"[..], (&b"abc"[..], &b"de"[..])));
  }

  #[test]
  fn preceded() {
    named!(prec<&[u8], &[u8] >,
      ws!(preceded!( take!(3), tag!("de") ))
    );

    assert_eq!(prec(&b" \t abc de fg"[..]),  Done(&b"fg"[..], &b"de"[..]));
  }

  #[test]
  fn terminated() {
    named!(term<&[u8], &[u8] >,
      ws!(terminated!( take!(3), tag!("de") ))
    );

    assert_eq!(term(&b" \t abc de fg"[..]),  Done(&b"fg"[..], &b"abc"[..]));
  }

  #[test]
  fn tuple() {
    //trace_macros!(true);
    named!(tuple_2<&[u8], (&[u8], &[u8]) >,
      ws!(tuple!( take!(3), tag!("de") ))
    );
    //trace_macros!(false);

    assert_eq!(tuple_2(&b" \t abc de fg"[..]),  Done(&b"fg"[..], (&b"abc"[..], &b"de"[..])));
  }

  #[test]
  fn levels() {
    //trace_macros!(true);
    named!(level_2<&[u8], (&[u8], (&[u8], &[u8])) >,
      ws!(pair!(take!(3), tuple!( tag!("de"), tag!("fg ") )))
    );
    //trace_macros!(false);

    assert_eq!(level_2(&b" \t abc de fg \t hi "[..]),  Done(&b"hi "[..], (&b"abc"[..], (&b"de"[..], &b"fg "[..]))));
  }
}
<commit_msg>fix traits imports<commit_after>//! Support for whitespace delimited formats
//!

#[macro_export]
macro_rules! wrap_sep (
  ($i:expr, $separator:expr, $submac:ident!( $($args:tt)* )) => (
    match ($separator)($i) {
      $crate::IResult::Error(e)      => $crate::IResult::Error(e),
      $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i),
      $crate::IResult::Done(i1,_)    => {
        match $submac!(i1, $($args)*) {
          $crate::IResult::Error(e)      => $crate::IResult::Error(e),
          $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i),
          $crate::IResult::Done(i2,o)    => {
            match ($separator)(i2) {
              $crate::IResult::Error(e)      => $crate::IResult::Error(e),
              $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i),
              $crate::IResult::Done(i3,_)    => $crate::IResult::Done(i3, o)
            }
          }
        }
      }
    }
  );
  ($i:expr, $separator:expr, $f:expr) => (
    wrap_sep!($i, $separator, call!($f))
  );
);

#[macro_export]
macro_rules! pair_sep (
  ($i:expr, $separator:ident, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => (
    tuple!(
      $i,
      sep!($separator, $submac!($($args)*)),
      sep!($separator, $submac2!($($args2)*))
    )
  );
  ($i:expr, $separator:ident, $submac:ident!( $($args:tt)* ), $g:expr) => (
    pair_sep!($i, $separator, $submac!($($args)*), call!($g));
  );
  ($i:expr, $separator:ident, $f:expr, $submac:ident!( $($args:tt)* )) => (
    pair_sep!($i, $separator, call!($f), $submac!($($args)*));
  );
  ($i:expr, $separator:ident, $f:expr, $g:expr) => (
    pair_sep!($i, $separator, call!($f), call!($g));
  );
);

#[macro_export]
macro_rules! preceded_sep (
  ($i:expr, $separator:ident, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => (
    match pair_sep!($i, $separator, $submac!($($args)*), $submac2!($($args2)*)) {
      $crate::IResult::Error(a)               => $crate::IResult::Error(a),
      $crate::IResult::Incomplete(i)          => $crate::IResult::Incomplete(i),
      $crate::IResult::Done(remaining, (_,o)) => {
        $crate::IResult::Done(remaining, o)
      }
    }
  );
  ($i:expr, $separator:ident, $submac:ident!( $($args:tt)* ), $g:expr) => (
    preceded_sep!($i, $separator, $submac!($($args)*), call!($g));
  );
  ($i:expr, $separator:ident, $f:expr, $submac:ident!( $($args:tt)* )) => (
    preceded_sep!($i, $separator, call!($f), $submac!($($args)*));
  );
  ($i:expr, $separator:ident, $f:expr, $g:expr) => (
    preceded_sep!($i, $separator, call!($f), call!($g));
  );
);

#[macro_export]
macro_rules! terminated_sep (
  ($i:expr, $separator:ident, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => (
    match pair_sep!($i, $separator, $submac!($($args)*), $submac2!($($args2)*)) {
      $crate::IResult::Error(a)               => $crate::IResult::Error(a),
      $crate::IResult::Incomplete(i)          => $crate::IResult::Incomplete(i),
      $crate::IResult::Done(remaining, (o,_)) => {
        $crate::IResult::Done(remaining, o)
      }
    }
  );
  ($i:expr, $separator:ident, $submac:ident!( $($args:tt)* ), $g:expr) => (
    terminated_wrap!($i, $separator, $submac!($($args)*), call!($g));
  );
  ($i:expr, $separator:ident, $f:expr, $submac:ident!( $($args:tt)* )) => (
    terminated_sep!($i, $separator, call!($f), $submac!($($args)*));
  );
  ($i:expr, $separator:ident, $f:expr, $g:expr) => (
    terminated_sep!($i, $separator, call!($f), call!($g));
  );
);

/// Internal parser, do not use directly
#[doc(hidden)]
#[macro_export]
macro_rules! tuple_sep (
  ($i:expr, $separator:ident, $consumed:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => (
    tuple_sep!($i, $separator, $consumed, ($($parsed),*), call!($e), $($rest)*);
  );
  ($i:expr, $separator:ident, $consumed:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => (
    {
      match sep!($i, $separator, $submac!($($args)*)) {
        $crate::IResult::Error(e)                            => $crate::IResult::Error(e),
        $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown),
        $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)),
        $crate::IResult::Done(i,o)     => {
          tuple_sep!(i, $separator, $consumed + ($crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&i)), (o), $($rest)*)
        }
      }
    }
  );
  ($i:expr, $separator:ident, $consumed:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => (
    {
      match sep!($i, $separator, $submac!($($args)*)) {
        $crate::IResult::Error(e)                            => $crate::IResult::Error(e),
        $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown),
        $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)),
        $crate::IResult::Done(i,o)     => {
          tuple_sep!(i, $separator, $consumed + ($crate::InputLength::input_len(&($i)) - $crate::InputLength::input_len(&i)), ($($parsed)* , o), $($rest)*)
        }
      }
    }
  );
  ($i:expr, $separator:ident, $consumed:expr, ($($parsed:tt),*), $e:ident) => (
    tuple_sep!($i, $separator,  $consumed, ($($parsed),*), call!($e));
  );
  ($i:expr, $separator:ident, $consumed:expr, (), $submac:ident!( $($args:tt)* )) => (
    {
      match sep!($i, $separator, $submac!($($args)*)) {
        $crate::IResult::Error(e)                            => $crate::IResult::Error(e),
        $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown),
        $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)),
        $crate::IResult::Done(i,o)     => {
          $crate::IResult::Done(i, (o))
        }
      }
    }
  );
  ($i:expr, $separator:ident, $consumed:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => (
    {
      match sep!($i, $separator, $submac!($($args)*)) {
        $crate::IResult::Error(e)                            => $crate::IResult::Error(e),
        $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown),
        $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size($consumed + i)),
        $crate::IResult::Done(i,o)     => {
          $crate::IResult::Done(i, ($($parsed),* , o))
        }
      }
    }
  );
  ($i:expr, $separator:ident, $consumed:expr, ($($parsed:expr),*)) => (
    {
      $crate::IResult::Done($i, ($($parsed),*))
    }
  );
);

#[macro_export]
macro_rules! eat_separator (
  ($i:expr, $arr:expr) => (
    {
      use $crate::{InputLength,IterIndices,Slice};
      if ($i).input_len() == 0 {
        $crate::IResult::Done($i, ($i).slice(0..0))
      } else {
        match ($i).iter_indices().position(|(_, item)| {
          for (_,c) in ($arr).iter_indices() {
            if c == item { return false; }
          }
          true
        }) {
          Some(index) => {
            $crate::IResult::Done(($i).slice(index..), ($i).slice(..index))
          },
          None        => {
            $crate::IResult::Done(($i).slice(($i).input_len()..), $i)
          }
        }
      }
    }
  );
);

#[macro_export]
macro_rules! sep (
  ($i:expr,  $separator:ident, tuple ! ($($rest:tt)*) ) => {
    tuple_sep!($i, $separator, 0usize, (), $($rest)*)
  };
  ($i:expr,  $separator:ident, pair ! ($($rest:tt)*) ) => {
    wrap_sep!($i,
      $separator,
      pair_sep!($separator, $($rest)*)
    )
  };
  ($i:expr,  $separator:ident, preceded ! ($($rest:tt)*) ) => {
    wrap_sep!($i,
      $separator,
      preceded_sep!($separator, $($rest)*)
    )
  };
  ($i:expr,  $separator:ident, terminated ! ($($rest:tt)*) ) => {
    wrap_sep!($i,
      $separator,
      terminated_sep!($separator, $($rest)*)
    )
  };
  ($i:expr, $separator:ident, $submac:ident!( $($args:tt)* )) => {
    wrap_sep!($i, $separator, $submac!($($args)*))
  };
  ($i:expr, $separator:ident, $f:expr) => {
    wrap_sep!($i, $separator, call!($f))
  };
);

named!(pub sp, eat_separator!(b" \t\r\n"));

#[macro_export]
macro_rules! ws (
  ($i:expr, $($args:tt)*) => (
    {
      use $crate::sp;
      sep!($i, sp, $($args)*)
    }
  )
);

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

  #[test]
  fn spaaaaace() {
    assert_eq!(sp(&b" \t abc "[..]),  Done(&b"abc "[..], &b" \t "[..]));
  }

  #[test]
  fn tag() {
    named!(abc, ws!(tag!("abc")));

    assert_eq!(abc(&b" \t abc def"[..]),  Done(&b"def"[..], &b"abc"[..]));
  }

  #[test]
  fn pair() {
    named!(pair_2<&[u8], (&[u8], &[u8]) >,
      ws!(pair!( take!(3), tag!("de") ))
    );

    assert_eq!(pair_2(&b" \t abc de fg"[..]),  Done(&b"fg"[..], (&b"abc"[..], &b"de"[..])));
  }

  #[test]
  fn preceded() {
    named!(prec<&[u8], &[u8] >,
      ws!(preceded!( take!(3), tag!("de") ))
    );

    assert_eq!(prec(&b" \t abc de fg"[..]),  Done(&b"fg"[..], &b"de"[..]));
  }

  #[test]
  fn terminated() {
    named!(term<&[u8], &[u8] >,
      ws!(terminated!( take!(3), tag!("de") ))
    );

    assert_eq!(term(&b" \t abc de fg"[..]),  Done(&b"fg"[..], &b"abc"[..]));
  }

  #[test]
  fn tuple() {
    //trace_macros!(true);
    named!(tuple_2<&[u8], (&[u8], &[u8]) >,
      ws!(tuple!( take!(3), tag!("de") ))
    );
    //trace_macros!(false);

    assert_eq!(tuple_2(&b" \t abc de fg"[..]),  Done(&b"fg"[..], (&b"abc"[..], &b"de"[..])));
  }

  #[test]
  fn levels() {
    //trace_macros!(true);
    named!(level_2<&[u8], (&[u8], (&[u8], &[u8])) >,
      ws!(pair!(take!(3), tuple!( tag!("de"), tag!("fg ") )))
    );
    //trace_macros!(false);

    assert_eq!(level_2(&b" \t abc de fg \t hi "[..]),  Done(&b"hi "[..], (&b"abc"[..], (&b"de"[..], &b"fg "[..]))));
  }
}
<|endoftext|>


<commit_before>pub type EasinessFactor = f32;
pub const DEFAULT_EASINESS_FACTOR: EasinessFactor = 2.5;

pub type Interval = u32;

#[derive(Clone,Copy,Debug,PartialEq)]
pub enum Confidence {
    IncorrectBlackout = 0,
    IncorrectRemembered = 1,
    IncorrectEasy = 2,
    CorrectDifficult = 3,
    CorrectHesitation = 4,
    CorrectPerfect = 5,
}

pub fn new_easiness_factor(ef: EasinessFactor, confidence: Confidence)
                           -> EasinessFactor {
    let q = (confidence as i32) as f32;
    f32::min(1.3, ef + (0.1 - (5.0 - q) * (0.08 + (5.0 - q) * 0.02)))
}

pub fn new_interval(times_seen: u32, interval_days: Interval, ef: EasinessFactor,
                    confidence: Confidence)
                    -> (Interval, u32, EasinessFactor) {
    let new_interval = match times_seen {
        0 => 1,
        1 => 6,
        _ => f32::ceil((interval_days as f32) * ef) as u32,
    };

    if (confidence as i32) < 3 {
        (new_interval, 0, new_easiness_factor(ef, confidence))
    }
    else {
        (new_interval, times_seen + 1, new_easiness_factor(ef, confidence))
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn it_works() {
    }
}
<commit_msg>docs(srs): document SRS functions/types<commit_after>//! srs-rs: A Rust implementation of the SuperMemo 2 algorithm, SM2.
//! https://www.supermemo.com/english/ol/sm2.htm

/// The easiness factor (EF).
pub type EasinessFactor = f32;
/// The default easiness factor for new cards.
pub const DEFAULT_EASINESS_FACTOR: EasinessFactor = 2.5;

/// The repetition interval, in days.
pub type Interval = u32;

/// The recollection confidence.
#[derive(Clone,Copy,Debug,PartialEq)]
pub enum Confidence {
    IncorrectBlackout = 0,
    IncorrectRemembered = 1,
    IncorrectEasy = 2,
    CorrectDifficult = 3,
    CorrectHesitation = 4,
    CorrectPerfect = 5,
}

/// Calculate a new easiness factor based on the confidence.
pub fn new_easiness_factor(ef: EasinessFactor, confidence: Confidence)
                           -> EasinessFactor {
    let q = (confidence as i32) as f32;
    f32::min(1.3, ef + (0.1 - (5.0 - q) * (0.08 + (5.0 - q) * 0.02)))
}

/// Calculate the new interval, times seen, and easiness factor. This
/// function computes all three values because a low confidence can
/// reset the times seen.
pub fn new_interval(times_seen: u32, interval_days: Interval, ef: EasinessFactor,
                    confidence: Confidence)
                    -> (Interval, u32, EasinessFactor) {
    let new_interval = match times_seen {
        0 => 1,
        1 => 6,
        _ => f32::ceil((interval_days as f32) * ef) as u32,
    };

    if (confidence as i32) < 3 {
        (new_interval, 0, new_easiness_factor(ef, confidence))
    }
    else {
        (new_interval, times_seen + 1, new_easiness_factor(ef, confidence))
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn it_works() {
    }
}
<|endoftext|>


<commit_before>use std::mem;
use std::slice;
use gl;

pub trait Image2d {
    fn width(&self) -> usize;
    fn height(&self) -> usize;
    fn format(&self) -> ImageFormat;
    fn textel_bytes(&self) -> &[u8];
}

#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct Pixel {
    r: u8,
    g: u8,
    b: u8,
    a: u8
}

impl Pixel {
    pub fn r_g_b_a(r: u8, g: u8, b: u8, a: u8) -> Self {
        Pixel { r: r, g: g, b: b, a: a }
    }

    pub fn r_g_b(r: u8, g: u8, b: u8) -> Self {
        Pixel::r_g_b_a(r, g, b, 0xFF)
    }

    pub fn rgb(rgb: u32) -> Self {
        Pixel::rgb_a(rgb, 0xFF)
    }

    pub fn argb(argb: u32) -> Self {
        let a = (argb & 0xFF000000) >> 24;
        Pixel::rgb_a(argb, a as u8)
    }

    pub fn rgba(rgba: u32) -> Self {
        let r = (rgba & 0xFF000000) >> 24;
        let g = (rgba & 0x00FF0000) >> 16;
        let b = (rgba & 0x0000FF00) >> 8;
        let a =  rgba & 0x000000FF;
        Pixel::r_g_b_a(r as u8, g as u8, b as u8, a as u8)
    }

    pub fn rgb_a(rgb: u32, a: u8) -> Self {
        let r = (rgb & 0xFF0000) >> 16;
        let g = (rgb & 0x00FF00) >> 8;
        let b =  rgb & 0x0000FF;
        Pixel::r_g_b_a(r as u8, g as u8, b as u8, a)
    }
}

pub struct Pixels {
    width: usize,
    height: usize,
    pixels: Vec<Pixel>
}

impl Image2d for Pixels {
    fn width(&self) -> usize {
        self.width
    }

    fn height(&self) -> usize {
        self.height
    }

    fn format(&self) -> ImageFormat {
        ImageFormat::rgba8()
    }

    fn textel_bytes(&self) -> &[u8] {
        let len = self.pixels.len() * mem::size_of::<Pixel>();
        unsafe {
            slice::from_raw_parts(mem::transmute(&self.pixels[0]), len)
        }
    }
}

gl_enum! {
    pub gl_enum TextelType {
        UnsignedByte as UNSIGNED_BYTE_TEXTEL = gl::UNSIGNED_BYTE,
        UnsignedShort565 as UNSIGNED_SHORT_5_6_5 = gl::UNSIGNED_SHORT_5_6_5,
        UnsignedShort4444 as UNSIGNED_SHORT_4_4_4_4 =
            gl::UNSIGNED_SHORT_4_4_4_4,
        UnsignedShort5551 as UNSIGNED_SHORT_5_5_5_1 =
            gl::UNSIGNED_SHORT_5_5_5_1
    }
}

gl_enum! {
    pub gl_enum TextelFormat {
        Alpha as ALPHA = gl::ALPHA,
        RGB as RGB = gl::RGB,
        RGBA as RGBA = gl::RGBA
    }
}

#[derive(Debug, Clone, Copy)]
pub struct ImageFormat {
    pub textel_type: TextelType,
    pub textel_format: TextelFormat
}

impl ImageFormat {
    fn rgba8() -> Self {
        ImageFormat {
            textel_type: TextelType::UnsignedByte,
            textel_format: TextelFormat::RGBA
        }
    }
}
<commit_msg>Add `Pixels::new()`<commit_after>use std::mem;
use std::slice;
use gl;

pub trait Image2d {
    fn width(&self) -> usize;
    fn height(&self) -> usize;
    fn format(&self) -> ImageFormat;
    fn textel_bytes(&self) -> &[u8];
}

#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct Pixel {
    r: u8,
    g: u8,
    b: u8,
    a: u8
}

impl Pixel {
    pub fn r_g_b_a(r: u8, g: u8, b: u8, a: u8) -> Self {
        Pixel { r: r, g: g, b: b, a: a }
    }

    pub fn r_g_b(r: u8, g: u8, b: u8) -> Self {
        Pixel::r_g_b_a(r, g, b, 0xFF)
    }

    pub fn rgb(rgb: u32) -> Self {
        Pixel::rgb_a(rgb, 0xFF)
    }

    pub fn argb(argb: u32) -> Self {
        let a = (argb & 0xFF000000) >> 24;
        Pixel::rgb_a(argb, a as u8)
    }

    pub fn rgba(rgba: u32) -> Self {
        let r = (rgba & 0xFF000000) >> 24;
        let g = (rgba & 0x00FF0000) >> 16;
        let b = (rgba & 0x0000FF00) >> 8;
        let a =  rgba & 0x000000FF;
        Pixel::r_g_b_a(r as u8, g as u8, b as u8, a as u8)
    }

    pub fn rgb_a(rgb: u32, a: u8) -> Self {
        let r = (rgb & 0xFF0000) >> 16;
        let g = (rgb & 0x00FF00) >> 8;
        let b =  rgb & 0x0000FF;
        Pixel::r_g_b_a(r as u8, g as u8, b as u8, a)
    }
}

pub struct Pixels {
    width: usize,
    height: usize,
    pixels: Vec<Pixel>
}

impl Pixels {
    pub fn new(width: usize, height: usize) -> Self {
        Pixels {
            width: width,
            height: height,
            pixels: vec![Pixel::rgb(0x0000FF); width * height]
        }
    }
}

impl Image2d for Pixels {
    fn width(&self) -> usize {
        self.width
    }

    fn height(&self) -> usize {
        self.height
    }

    fn format(&self) -> ImageFormat {
        ImageFormat::rgba8()
    }

    fn textel_bytes(&self) -> &[u8] {
        let len = self.pixels.len() * mem::size_of::<Pixel>();
        unsafe {
            slice::from_raw_parts(mem::transmute(&self.pixels[0]), len)
        }
    }
}

gl_enum! {
    pub gl_enum TextelType {
        UnsignedByte as UNSIGNED_BYTE_TEXTEL = gl::UNSIGNED_BYTE,
        UnsignedShort565 as UNSIGNED_SHORT_5_6_5 = gl::UNSIGNED_SHORT_5_6_5,
        UnsignedShort4444 as UNSIGNED_SHORT_4_4_4_4 =
            gl::UNSIGNED_SHORT_4_4_4_4,
        UnsignedShort5551 as UNSIGNED_SHORT_5_5_5_1 =
            gl::UNSIGNED_SHORT_5_5_5_1
    }
}

gl_enum! {
    pub gl_enum TextelFormat {
        Alpha as ALPHA = gl::ALPHA,
        RGB as RGB = gl::RGB,
        RGBA as RGBA = gl::RGBA
    }
}

#[derive(Debug, Clone, Copy)]
pub struct ImageFormat {
    pub textel_type: TextelType,
    pub textel_format: TextelFormat
}

impl ImageFormat {
    fn rgba8() -> Self {
        ImageFormat {
            textel_type: TextelType::UnsignedByte,
            textel_format: TextelFormat::RGBA
        }
    }
}
<|endoftext|>


<commit_before>use rustc_middle::mir::visit::{PlaceContext, Visitor};
use rustc_middle::mir::{
    Local, Location, Place, Statement, StatementKind, Terminator, TerminatorKind,
};

use rustc_data_structures::fx::FxHashSet;

use crate::borrow_check::MirBorrowckCtxt;

impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
    /// Walks the MIR adding to the set of `used_mut` locals that will be ignored for the purposes
    /// of the `unused_mut` lint.
    ///
    /// `temporary_used_locals` should contain locals that were found to be temporary, mutable and
    ///  used from borrow checking. This function looks for assignments into these locals from
    ///  user-declared locals and adds those user-defined locals to the `used_mut` set. This can
    ///  occur due to a rare case involving upvars in closures.
    ///
    /// `never_initialized_mut_locals` should contain the set of user-declared mutable locals
    ///  (not arguments) that have not already been marked as being used.
    ///  This function then looks for assignments from statements or the terminator into the locals
    ///  from this set and removes them from the set. This leaves only those locals that have not
    ///  been assigned to - this set is used as a proxy for locals that were not initialized due to
    ///  unreachable code. These locals are then considered "used" to silence the lint for them.
    ///  See #55344 for context.
    crate fn gather_used_muts(
        &mut self,
        temporary_used_locals: FxHashSet<Local>,
        mut never_initialized_mut_locals: FxHashSet<Local>,
    ) {
        {
            let mut visitor = GatherUsedMutsVisitor {
                temporary_used_locals,
                never_initialized_mut_locals: &mut never_initialized_mut_locals,
                mbcx: self,
            };
            visitor.visit_body(&visitor.mbcx.body);
        }

        // Take the union of the existed `used_mut` set with those variables we've found were
        // never initialized.
        debug!("gather_used_muts: never_initialized_mut_locals={:?}", never_initialized_mut_locals);
        self.used_mut = self.used_mut.union(&never_initialized_mut_locals).cloned().collect();
    }
}

/// MIR visitor for collecting used mutable variables.
/// The 'visit lifetime represents the duration of the MIR walk.
struct GatherUsedMutsVisitor<'visit, 'cx, 'tcx> {
    temporary_used_locals: FxHashSet<Local>,
    never_initialized_mut_locals: &'visit mut FxHashSet<Local>,
    mbcx: &'visit mut MirBorrowckCtxt<'cx, 'tcx>,
}

impl GatherUsedMutsVisitor<'_, '_, '_> {
    fn remove_never_initialized_mut_locals(&mut self, into: Place<'_>) {
        // Remove any locals that we found were initialized from the
        // `never_initialized_mut_locals` set. At the end, the only remaining locals will
        // be those that were never initialized - we will consider those as being used as
        // they will either have been removed by unreachable code optimizations; or linted
        // as unused variables.
        self.never_initialized_mut_locals.remove(&into.local);
    }
}

impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tcx> {
    fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, _location: Location) {
        debug!("visit_terminator: terminator={:?}", terminator);
        match &terminator.kind {
            TerminatorKind::Call { destination: Some((into, _)), .. } => {
                self.remove_never_initialized_mut_locals(*into);
            }
            TerminatorKind::DropAndReplace { place, .. } => {
                self.remove_never_initialized_mut_locals(*place);
            }
            _ => {}
        }

        // FIXME: no super_terminator?
    }

    fn visit_statement(&mut self, statement: &Statement<'tcx>, _location: Location) {
        if let StatementKind::Assign(box (into, _)) = &statement.kind {
            debug!(
                "visit_statement: statement={:?} local={:?} \
                    never_initialized_mut_locals={:?}",
                statement, into.local, self.never_initialized_mut_locals
            );
            self.remove_never_initialized_mut_locals(*into);
        }

        // FIXME: no super_statement?
    }

    fn visit_local(&mut self, local: &Local, place_context: PlaceContext, location: Location) {
        if place_context.is_place_assignment() && self.temporary_used_locals.contains(local) {
            // Propagate the Local assigned at this Location as a used mutable local variable
            for moi in &self.mbcx.move_data.loc_map[location] {
                let mpi = &self.mbcx.move_data.moves[*moi].path;
                let path = &self.mbcx.move_data.move_paths[*mpi];
                debug!(
                    "assignment of {:?} to {:?}, adding {:?} to used mutable set",
                    path.place, local, path.place
                );
                if let Some(user_local) = path.place.as_local() {
                    self.mbcx.used_mut.insert(user_local);
                }
            }
        }

        // FIXME: no super_local?
    }
}
<commit_msg>add probably accidentally missing super_* calls<commit_after>use rustc_middle::mir::visit::{PlaceContext, Visitor};
use rustc_middle::mir::{
    Local, Location, Place, Statement, StatementKind, Terminator, TerminatorKind,
};

use rustc_data_structures::fx::FxHashSet;

use crate::borrow_check::MirBorrowckCtxt;

impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
    /// Walks the MIR adding to the set of `used_mut` locals that will be ignored for the purposes
    /// of the `unused_mut` lint.
    ///
    /// `temporary_used_locals` should contain locals that were found to be temporary, mutable and
    ///  used from borrow checking. This function looks for assignments into these locals from
    ///  user-declared locals and adds those user-defined locals to the `used_mut` set. This can
    ///  occur due to a rare case involving upvars in closures.
    ///
    /// `never_initialized_mut_locals` should contain the set of user-declared mutable locals
    ///  (not arguments) that have not already been marked as being used.
    ///  This function then looks for assignments from statements or the terminator into the locals
    ///  from this set and removes them from the set. This leaves only those locals that have not
    ///  been assigned to - this set is used as a proxy for locals that were not initialized due to
    ///  unreachable code. These locals are then considered "used" to silence the lint for them.
    ///  See #55344 for context.
    crate fn gather_used_muts(
        &mut self,
        temporary_used_locals: FxHashSet<Local>,
        mut never_initialized_mut_locals: FxHashSet<Local>,
    ) {
        {
            let mut visitor = GatherUsedMutsVisitor {
                temporary_used_locals,
                never_initialized_mut_locals: &mut never_initialized_mut_locals,
                mbcx: self,
            };
            visitor.visit_body(&visitor.mbcx.body);
        }

        // Take the union of the existed `used_mut` set with those variables we've found were
        // never initialized.
        debug!("gather_used_muts: never_initialized_mut_locals={:?}", never_initialized_mut_locals);
        self.used_mut = self.used_mut.union(&never_initialized_mut_locals).cloned().collect();
    }
}

/// MIR visitor for collecting used mutable variables.
/// The 'visit lifetime represents the duration of the MIR walk.
struct GatherUsedMutsVisitor<'visit, 'cx, 'tcx> {
    temporary_used_locals: FxHashSet<Local>,
    never_initialized_mut_locals: &'visit mut FxHashSet<Local>,
    mbcx: &'visit mut MirBorrowckCtxt<'cx, 'tcx>,
}

impl GatherUsedMutsVisitor<'_, '_, '_> {
    fn remove_never_initialized_mut_locals(&mut self, into: Place<'_>) {
        // Remove any locals that we found were initialized from the
        // `never_initialized_mut_locals` set. At the end, the only remaining locals will
        // be those that were never initialized - we will consider those as being used as
        // they will either have been removed by unreachable code optimizations; or linted
        // as unused variables.
        self.never_initialized_mut_locals.remove(&into.local);
    }
}

impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tcx> {
    fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
        debug!("visit_terminator: terminator={:?}", terminator);
        match &terminator.kind {
            TerminatorKind::Call { destination: Some((into, _)), .. } => {
                self.remove_never_initialized_mut_locals(*into);
            }
            TerminatorKind::DropAndReplace { place, .. } => {
                self.remove_never_initialized_mut_locals(*place);
            }
            _ => {}
        }

        self.super_terminator(terminator, location);
    }

    fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
        if let StatementKind::Assign(box (into, _)) = &statement.kind {
            debug!(
                "visit_statement: statement={:?} local={:?} \
                    never_initialized_mut_locals={:?}",
                statement, into.local, self.never_initialized_mut_locals
            );
            self.remove_never_initialized_mut_locals(*into);
        }

        self.super_statement(statement, location);
    }

    fn visit_local(&mut self, local: &Local, place_context: PlaceContext, location: Location) {
        if place_context.is_place_assignment() && self.temporary_used_locals.contains(local) {
            // Propagate the Local assigned at this Location as a used mutable local variable
            for moi in &self.mbcx.move_data.loc_map[location] {
                let mpi = &self.mbcx.move_data.moves[*moi].path;
                let path = &self.mbcx.move_data.move_paths[*mpi];
                debug!(
                    "assignment of {:?} to {:?}, adding {:?} to used mutable set",
                    path.place, local, path.place
                );
                if let Some(user_local) = path.place.as_local() {
                    self.mbcx.used_mut.insert(user_local);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use decoders::*;
use decoders::tiff::*;
use decoders::basics::*;
use std::mem::transmute;
extern crate itertools;
use self::itertools::Itertools;
use std::f32;
use std::cmp;

#[derive(Debug, Clone)]
pub struct ArwDecoder<'a> {
  buffer: &'a [u8],
  rawloader: &'a RawLoader,
  tiff: TiffIFD<'a>,
}

impl<'a> ArwDecoder<'a> {
  pub fn new(buf: &'a [u8], tiff: TiffIFD<'a>, rawloader: &'a RawLoader) -> ArwDecoder<'a> {
    ArwDecoder {
      buffer: buf,
      tiff: tiff,
      rawloader: rawloader,
    }
  }
}

impl<'a> Decoder for ArwDecoder<'a> {
  fn identify(&self) -> Result<&Camera, String> {
    let make = fetch_tag!(self.tiff, Tag::Make, "ARW: Couldn't find Make").get_str();
    let model = fetch_tag!(self.tiff, Tag::Model, "ARW: Couldn't find Model").get_str();
    self.rawloader.check_supported(make, model)
  }

  fn image(&self) -> Result<Image,String> {
    let camera = try!(self.identify());
    let data = self.tiff.find_ifds_with_tag(Tag::StripOffsets);
    if data.len() == 0 {
      return Err("ARW: Couldn't find the data IFD!".to_string())
    }
    let raw = data[0];
    let width = fetch_tag!(raw, Tag::ImageWidth, "ARW: Couldn't find width").get_u16(0) as u32;
    let height = fetch_tag!(raw, Tag::ImageLength, "ARW: Couldn't find height").get_u16(0) as u32;
    let offset = fetch_tag!(raw, Tag::StripOffsets, "ARW: Couldn't find offset").get_u32(0) as usize;
    let count = fetch_tag!(raw, Tag::StripByteCounts, "ARW: Couldn't find byte count").get_u32(0) as usize;
    let compression = fetch_tag!(raw, Tag::Compression, "ARW: Couldn't find Compression").get_u16(0);
    let bps = if camera.bps != 0 {
      camera.bps
    } else {
      fetch_tag!(raw, Tag::BitsPerSample, "ARW: Couldn't find bps").get_u16(0) as u32
    };
    let src = &self.buffer[offset .. self.buffer.len()];

    let image = match compression {
      1 => decode_16le(src, width as usize, height as usize),
      32767 => {
        if ((width*height*bps) as usize) != count*8 {
          ArwDecoder::decode_arw1(src, width as usize, height as usize)
        } else {
          match bps {
            8 => {let curve = try!(ArwDecoder::get_curve(raw)); ArwDecoder::decode_arw2(src, width as usize, height as usize, &curve)},
            12 => decode_12le(src, width as usize, height as usize),
            _ => return Err(format!("ARW2: Don't know how to decode images with {} bps", bps)),
          }
        }
      },
      _ => return Err(format!("ARW: Don't know how to decode type {}", compression).to_string()),
    };

    ok_image(camera, width, height, try!(self.get_wb()), image)
  }
}

impl<'a> ArwDecoder<'a> {
  fn decode_arw1(buf: &[u8], width: usize, height: usize) -> Vec<u16> {
    let mut buffer: Vec<u16> = vec![0; (width*height) as usize];

    buffer[0] = buf[0] as u16; // Shut up the warnings for now

    buffer
  }

  fn decode_arw2(buf: &[u8], width: usize, height: usize, curve: &LookupTable) -> Vec<u16> {
    decode_threaded(width, height, &(|out: &mut [u16], start, width, height| {
      let mut pump = BitPump::new(&buf[(start*width)..]);

      for row in 0..height {
        // Process 16 pixels at a time in interleaved fashion
        let mut col = 0;
        let mut random = pump.peek_bits(24);
        while col < (width-30) {
          let max = pump.get_bits(11);
          let min = pump.get_bits(11);
          let imax = pump.get_bits(4);
          let imin = pump.get_bits(4);
          let mut sh = 0;
          while sh<4 && (0x80 << sh) <= (max - min) {sh = sh + 1;}
          for i in 0..16 {
            let val = if i == imax {
              max
            } else if i == imin {
              min
            } else {
              cmp::min(0x7ff,(pump.get_bits(7) << sh) + min)
            };
            out[row*width+col+(i*2) as usize] = curve.dither(val as u16, &mut random);
          }
          col += if (col & 1) != 0 {31} else {1};  // Skip to next 16 pixels
        }
      }
    }))
  }

  fn get_wb(&self) -> Result<[f32;4], String> {
    let priv_offset = fetch_tag!(self.tiff, Tag::DNGPrivateArea, "ARW: Couldn't find private offset").get_u32(0);
    let priv_tiff = TiffIFD::new(self.buffer, priv_offset as usize, 0, 0, LITTLE_ENDIAN);
    let sony_offset = fetch_tag!(priv_tiff, Tag::SonyOffset, "ARW: Couldn't find sony offset").get_u32(0) as usize;
    let sony_length = fetch_tag!(priv_tiff, Tag::SonyLength, "ARW: Couldn't find sony length").get_u32(0) as usize;
    let sony_key = fetch_tag!(priv_tiff, Tag::SonyKey, "ARW: Couldn't find sony key").get_u32(0);
    let decrypted_buf = ArwDecoder::sony_decrypt(self.buffer, sony_offset, sony_length, sony_key);
    let decrypted_tiff = TiffIFD::new(&decrypted_buf, 0, sony_offset, 0, LITTLE_ENDIAN);
    let grgb_levels = decrypted_tiff.find_entry(Tag::SonyGRBG);
    let rggb_levels = decrypted_tiff.find_entry(Tag::SonyRGGB);
    if grgb_levels.is_some() {
      let levels = grgb_levels.unwrap();
      Ok([levels.get_u16(1) as f32, levels.get_u16(0) as f32, levels.get_u16(2) as f32, f32::NAN])
    } else if rggb_levels.is_some() {
      let levels = rggb_levels.unwrap();
      Ok([levels.get_u16(0) as f32, levels.get_u16(1) as f32, levels.get_u16(3) as f32, f32::NAN])
    } else {
      Err("ARW: Couldn't find GRGB or RGGB levels".to_string())
    }
  }

  fn get_curve(raw: &TiffIFD) -> Result<LookupTable, String> {
    let centry = fetch_tag!(raw, Tag::SonyCurve, "ARW: Couldn't find sony curve");
    let mut curve: [u32;6] = [ 0, 0, 0, 0, 0, 4095 ];

    for i in 0..4 {
      curve[i+1] = ((centry.get_u16(i) >> 2) & 0xfff) as u32;
    }

    let mut out = vec![0 as u16; (curve[5]+1) as usize];
    for i in 0..5 {
      for j in (curve[i]+1)..(curve[i+1]+1) {
        out[j as usize] = out[(j-1) as usize] + (1<<i);
      }
    }

    Ok(LookupTable::new(&out))
  }

  fn sony_decrypt(buf: &[u8], offset: usize, length: usize, key: u32) -> Vec<u8>{
    let mut pad: [u32; 128] = [0 as u32; 128];
    let mut mkey = key;
    // Make sure we always have space for the final bytes even if the buffer
    // isn't a multiple of 4
    let mut out = vec![0;length+4];
    // Initialize the decryption pad from the key
    for p in 0..4 {
      mkey = mkey.wrapping_mul(48828125).wrapping_add(1);
      pad[p] = mkey;
    }
    pad[3] = pad[3] << 1 | (pad[0]^pad[2]) >> 31;
    for p in 4..127 {
      pad[p] = (pad[p-4]^pad[p-2]) << 1 | (pad[p-3]^pad[p-1]) >> 31;
    }
    for p in 0..127 {
      pad[p] = u32::from_be(pad[p]);
    }

    for i in (0..length).step(4) {
      let p = i/4 + 127;
      pad[p & 127] = pad[(p+1) & 127] ^ pad[(p+1+64) & 127];
      let output = LEu32(buf, offset+i) ^ pad[p & 127];
      let bytes: [u8; 4] = unsafe { transmute(output.to_le()) };
      out[i]   = bytes[0];
      out[i+1] = bytes[1];
      out[i+2] = bytes[2];
      out[i+3] = bytes[3];
    }
    out
  }
}
<commit_msg>ARW: Cleanup and maybe slightly speedup ARW2<commit_after>use decoders::*;
use decoders::tiff::*;
use decoders::basics::*;
use std::mem::transmute;
extern crate itertools;
use self::itertools::Itertools;
use std::f32;
use std::cmp;

#[derive(Debug, Clone)]
pub struct ArwDecoder<'a> {
  buffer: &'a [u8],
  rawloader: &'a RawLoader,
  tiff: TiffIFD<'a>,
}

impl<'a> ArwDecoder<'a> {
  pub fn new(buf: &'a [u8], tiff: TiffIFD<'a>, rawloader: &'a RawLoader) -> ArwDecoder<'a> {
    ArwDecoder {
      buffer: buf,
      tiff: tiff,
      rawloader: rawloader,
    }
  }
}

impl<'a> Decoder for ArwDecoder<'a> {
  fn identify(&self) -> Result<&Camera, String> {
    let make = fetch_tag!(self.tiff, Tag::Make, "ARW: Couldn't find Make").get_str();
    let model = fetch_tag!(self.tiff, Tag::Model, "ARW: Couldn't find Model").get_str();
    self.rawloader.check_supported(make, model)
  }

  fn image(&self) -> Result<Image,String> {
    let camera = try!(self.identify());
    let data = self.tiff.find_ifds_with_tag(Tag::StripOffsets);
    if data.len() == 0 {
      return Err("ARW: Couldn't find the data IFD!".to_string())
    }
    let raw = data[0];
    let width = fetch_tag!(raw, Tag::ImageWidth, "ARW: Couldn't find width").get_u16(0) as u32;
    let height = fetch_tag!(raw, Tag::ImageLength, "ARW: Couldn't find height").get_u16(0) as u32;
    let offset = fetch_tag!(raw, Tag::StripOffsets, "ARW: Couldn't find offset").get_u32(0) as usize;
    let count = fetch_tag!(raw, Tag::StripByteCounts, "ARW: Couldn't find byte count").get_u32(0) as usize;
    let compression = fetch_tag!(raw, Tag::Compression, "ARW: Couldn't find Compression").get_u16(0);
    let bps = if camera.bps != 0 {
      camera.bps
    } else {
      fetch_tag!(raw, Tag::BitsPerSample, "ARW: Couldn't find bps").get_u16(0) as u32
    };
    let src = &self.buffer[offset .. self.buffer.len()];

    let image = match compression {
      1 => decode_16le(src, width as usize, height as usize),
      32767 => {
        if ((width*height*bps) as usize) != count*8 {
          ArwDecoder::decode_arw1(src, width as usize, height as usize)
        } else {
          match bps {
            8 => {let curve = try!(ArwDecoder::get_curve(raw)); ArwDecoder::decode_arw2(src, width as usize, height as usize, &curve)},
            12 => decode_12le(src, width as usize, height as usize),
            _ => return Err(format!("ARW2: Don't know how to decode images with {} bps", bps)),
          }
        }
      },
      _ => return Err(format!("ARW: Don't know how to decode type {}", compression).to_string()),
    };

    ok_image(camera, width, height, try!(self.get_wb()), image)
  }
}

impl<'a> ArwDecoder<'a> {
  fn decode_arw1(buf: &[u8], width: usize, height: usize) -> Vec<u16> {
    let mut buffer: Vec<u16> = vec![0; (width*height) as usize];

    buffer[0] = buf[0] as u16; // Shut up the warnings for now

    buffer
  }

  fn decode_arw2(buf: &[u8], width: usize, height: usize, curve: &LookupTable) -> Vec<u16> {
    decode_threaded(width, height, &(|out: &mut [u16], start, width, height| {
      let mut pump = BitPump::new(&buf[(start*width)..]);

      for row in 0..height {
        // Process 16 pixels at a time in interleaved fashion
        let mut col = 0;
        let mut random = pump.peek_bits(24);
        while col < (width-30) {
          let max = pump.get_bits(11);
          let min = pump.get_bits(11);
          let delta = max-min;
          // Calculate the size of the data shift needed by how large the delta is
          // A delta with 11 bits requires a shift of 4, 10 bits of 3, etc
          let delta_shift: u32 = cmp::max(0, (32-(delta.leading_zeros() as i32)) - 7) as u32;
          let imax = pump.get_bits(4);
          let imin = pump.get_bits(4);

          for i in 0..16 {
            let val = if i == imax {
              max
            } else if i == imin {
              min
            } else {
              cmp::min(0x7ff,(pump.get_bits(7) << delta_shift) + min)
            };
            out[row*width+col+(i*2) as usize] = curve.dither(val as u16, &mut random);
          }
          col += if (col & 1) != 0 {31} else {1};  // Skip to next 16 pixels
        }
      }
    }))
  }

  fn get_wb(&self) -> Result<[f32;4], String> {
    let priv_offset = fetch_tag!(self.tiff, Tag::DNGPrivateArea, "ARW: Couldn't find private offset").get_u32(0);
    let priv_tiff = TiffIFD::new(self.buffer, priv_offset as usize, 0, 0, LITTLE_ENDIAN);
    let sony_offset = fetch_tag!(priv_tiff, Tag::SonyOffset, "ARW: Couldn't find sony offset").get_u32(0) as usize;
    let sony_length = fetch_tag!(priv_tiff, Tag::SonyLength, "ARW: Couldn't find sony length").get_u32(0) as usize;
    let sony_key = fetch_tag!(priv_tiff, Tag::SonyKey, "ARW: Couldn't find sony key").get_u32(0);
    let decrypted_buf = ArwDecoder::sony_decrypt(self.buffer, sony_offset, sony_length, sony_key);
    let decrypted_tiff = TiffIFD::new(&decrypted_buf, 0, sony_offset, 0, LITTLE_ENDIAN);
    let grgb_levels = decrypted_tiff.find_entry(Tag::SonyGRBG);
    let rggb_levels = decrypted_tiff.find_entry(Tag::SonyRGGB);
    if grgb_levels.is_some() {
      let levels = grgb_levels.unwrap();
      Ok([levels.get_u16(1) as f32, levels.get_u16(0) as f32, levels.get_u16(2) as f32, f32::NAN])
    } else if rggb_levels.is_some() {
      let levels = rggb_levels.unwrap();
      Ok([levels.get_u16(0) as f32, levels.get_u16(1) as f32, levels.get_u16(3) as f32, f32::NAN])
    } else {
      Err("ARW: Couldn't find GRGB or RGGB levels".to_string())
    }
  }

  fn get_curve(raw: &TiffIFD) -> Result<LookupTable, String> {
    let centry = fetch_tag!(raw, Tag::SonyCurve, "ARW: Couldn't find sony curve");
    let mut curve: [u32;6] = [ 0, 0, 0, 0, 0, 4095 ];

    for i in 0..4 {
      curve[i+1] = ((centry.get_u16(i) >> 2) & 0xfff) as u32;
    }

    let mut out = vec![0 as u16; (curve[5]+1) as usize];
    for i in 0..5 {
      for j in (curve[i]+1)..(curve[i+1]+1) {
        out[j as usize] = out[(j-1) as usize] + (1<<i);
      }
    }

    Ok(LookupTable::new(&out))
  }

  fn sony_decrypt(buf: &[u8], offset: usize, length: usize, key: u32) -> Vec<u8>{
    let mut pad: [u32; 128] = [0 as u32; 128];
    let mut mkey = key;
    // Make sure we always have space for the final bytes even if the buffer
    // isn't a multiple of 4
    let mut out = vec![0;length+4];
    // Initialize the decryption pad from the key
    for p in 0..4 {
      mkey = mkey.wrapping_mul(48828125).wrapping_add(1);
      pad[p] = mkey;
    }
    pad[3] = pad[3] << 1 | (pad[0]^pad[2]) >> 31;
    for p in 4..127 {
      pad[p] = (pad[p-4]^pad[p-2]) << 1 | (pad[p-3]^pad[p-1]) >> 31;
    }
    for p in 0..127 {
      pad[p] = u32::from_be(pad[p]);
    }

    for i in (0..length).step(4) {
      let p = i/4 + 127;
      pad[p & 127] = pad[(p+1) & 127] ^ pad[(p+1+64) & 127];
      let output = LEu32(buf, offset+i) ^ pad[p & 127];
      let bytes: [u8; 4] = unsafe { transmute(output.to_le()) };
      out[i]   = bytes[0];
      out[i+1] = bytes[1];
      out[i+2] = bytes[2];
      out[i+3] = bytes[3];
    }
    out
  }
}
<|endoftext|>


<commit_before>use std::cell::{Cell, RefCell};

use rand::Rng;

use rustc::mir::interpret::{AllocId, Pointer, InterpResult};
use rustc_mir::interpret::Memory;
use rustc_target::abi::Size;

use crate::stacked_borrows::Tag;
use crate::Evaluator;

pub type MemoryExtra = RefCell<GlobalState>;

#[derive(Clone, Debug, Default)]
pub struct AllocExtra {
    base_addr: Cell<Option<u64>>
}

#[derive(Clone, Debug)]
pub struct GlobalState {
    /// This is used as a map between the address of each allocation and its `AllocId`.
    /// It is always sorted
    pub int_to_ptr_map: Vec<(u64, AllocId)>,
    /// This is used as a memory address when a new pointer is casted to an integer. It
    /// is always larger than any address that was previously made part of a block.
    pub next_base_addr: u64,
}

impl Default for GlobalState {
    // FIXME: Query the page size in the future
    fn default() -> Self {
        GlobalState {
            int_to_ptr_map: Vec::default(),
            next_base_addr: 2u64.pow(16)
        }
    }
}

impl<'mir, 'tcx> GlobalState {
    pub fn int_to_ptr(
        int: u64,
        memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>,
    ) -> InterpResult<'tcx, Pointer<Tag>> {
        let global_state = memory.extra.intptrcast.borrow();

        match global_state.int_to_ptr_map.binary_search_by_key(&int, |(addr, _)| *addr) {
            Ok(pos) => {
                let (_, alloc_id) = global_state.int_to_ptr_map[pos];
                // `int` is equal to the starting address for an allocation, the offset should be
                // zero. The pointer is untagged because it was created from a cast
                Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged))
            },
            Err(0) => err!(DanglingPointerDeref),
            Err(pos) => {
                // This is the largest of the adresses smaller than `int`,
                // i.e. the greatest lower bound (glb)
                let (glb, alloc_id) = global_state.int_to_ptr_map[pos - 1];
                // This never overflows because `int >= glb`
                let offset = int - glb;
                // If the offset exceeds the size of the allocation, this access is illegal
                if offset <= memory.get(alloc_id)?.bytes.len() as u64 {
                    // This pointer is untagged because it was created from a cast
                    Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged))
                } else {
                    err!(DanglingPointerDeref)
                }
            }
        }
    }

    pub fn ptr_to_int(
        ptr: Pointer<Tag>,
        memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>,
    ) -> InterpResult<'tcx, u64> {
        let mut global_state = memory.extra.intptrcast.borrow_mut();

        let alloc = memory.get(ptr.alloc_id)?;
        let align = alloc.align.bytes();

        let base_addr = match alloc.extra.intptrcast.base_addr.get() {
            Some(base_addr) => base_addr,
            None => {
                // This allocation does not have a base address yet, pick one.
                // Leave some space to the previous allocation, to give it some chance to be less aligned.
                let slack = {
                    let mut rng = memory.extra.rng.as_ref().unwrap().borrow_mut();
                    rng.gen_range(0, align)
                };
                // From next_base_addr + slack, round up to adjust for alignment.
                let base_addr = Self::align_addr(global_state.next_base_addr + slack, align);
                alloc.extra.intptrcast.base_addr.set(Some(base_addr));

                // Remember next base address.
                global_state.next_base_addr = base_addr + alloc.bytes.len() as u64;
                // Given that `next_base_addr` increases in each allocation, pushing the
                // corresponding tuple keeps `int_to_ptr_map` sorted
                global_state.int_to_ptr_map.push((base_addr, ptr.alloc_id));

                base_addr
            }
        };

        debug_assert_eq!(base_addr % align, 0); // sanity check
        Ok(base_addr + ptr.offset.bytes())
    }

    /// Shifts `addr` to make it aligned with `align` by rounding `addr` to the smallest multiple
    /// of `align` that is larger or equal to `addr`
    fn align_addr(addr: u64, align: u64) -> u64 {
        if addr % align == 0 {
            addr
        } else {
            addr + align - addr % align
        }
    }
}

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

    #[test]
    fn test_align_addr() {
        assert_eq!(GlobalState::align_addr(37, 4), 40);
        assert_eq!(GlobalState::align_addr(44, 4), 44);
    }
}
<commit_msg>more sensible slack<commit_after>use std::cell::{Cell, RefCell};

use rand::Rng;

use rustc::mir::interpret::{AllocId, Pointer, InterpResult};
use rustc_mir::interpret::Memory;
use rustc_target::abi::Size;

use crate::stacked_borrows::Tag;
use crate::Evaluator;

pub type MemoryExtra = RefCell<GlobalState>;

#[derive(Clone, Debug, Default)]
pub struct AllocExtra {
    base_addr: Cell<Option<u64>>
}

#[derive(Clone, Debug)]
pub struct GlobalState {
    /// This is used as a map between the address of each allocation and its `AllocId`.
    /// It is always sorted
    pub int_to_ptr_map: Vec<(u64, AllocId)>,
    /// This is used as a memory address when a new pointer is casted to an integer. It
    /// is always larger than any address that was previously made part of a block.
    pub next_base_addr: u64,
}

impl Default for GlobalState {
    // FIXME: Query the page size in the future
    fn default() -> Self {
        GlobalState {
            int_to_ptr_map: Vec::default(),
            next_base_addr: 2u64.pow(16)
        }
    }
}

impl<'mir, 'tcx> GlobalState {
    pub fn int_to_ptr(
        int: u64,
        memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>,
    ) -> InterpResult<'tcx, Pointer<Tag>> {
        let global_state = memory.extra.intptrcast.borrow();

        match global_state.int_to_ptr_map.binary_search_by_key(&int, |(addr, _)| *addr) {
            Ok(pos) => {
                let (_, alloc_id) = global_state.int_to_ptr_map[pos];
                // `int` is equal to the starting address for an allocation, the offset should be
                // zero. The pointer is untagged because it was created from a cast
                Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged))
            },
            Err(0) => err!(DanglingPointerDeref),
            Err(pos) => {
                // This is the largest of the adresses smaller than `int`,
                // i.e. the greatest lower bound (glb)
                let (glb, alloc_id) = global_state.int_to_ptr_map[pos - 1];
                // This never overflows because `int >= glb`
                let offset = int - glb;
                // If the offset exceeds the size of the allocation, this access is illegal
                if offset <= memory.get(alloc_id)?.bytes.len() as u64 {
                    // This pointer is untagged because it was created from a cast
                    Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged))
                } else {
                    err!(DanglingPointerDeref)
                }
            }
        }
    }

    pub fn ptr_to_int(
        ptr: Pointer<Tag>,
        memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>,
    ) -> InterpResult<'tcx, u64> {
        let mut global_state = memory.extra.intptrcast.borrow_mut();

        let alloc = memory.get(ptr.alloc_id)?;
        let align = alloc.align.bytes();

        let base_addr = match alloc.extra.intptrcast.base_addr.get() {
            Some(base_addr) => base_addr,
            None => {
                // This allocation does not have a base address yet, pick one.
                // Leave some space to the previous allocation, to give it some chance to be less aligned.
                let slack = {
                    let mut rng = memory.extra.rng.as_ref().unwrap().borrow_mut();
                    // This means that `(global_state.next_base_addr + slack) % 16` is uniformly distributed.
                    rng.gen_range(0, 16)
                };
                // From next_base_addr + slack, round up to adjust for alignment.
                let base_addr = Self::align_addr(global_state.next_base_addr + slack, align);
                alloc.extra.intptrcast.base_addr.set(Some(base_addr));

                // Remember next base address.
                global_state.next_base_addr = base_addr + alloc.bytes.len() as u64;
                // Given that `next_base_addr` increases in each allocation, pushing the
                // corresponding tuple keeps `int_to_ptr_map` sorted
                global_state.int_to_ptr_map.push((base_addr, ptr.alloc_id));

                base_addr
            }
        };

        debug_assert_eq!(base_addr % align, 0); // sanity check
        Ok(base_addr + ptr.offset.bytes())
    }

    /// Shifts `addr` to make it aligned with `align` by rounding `addr` to the smallest multiple
    /// of `align` that is larger or equal to `addr`
    fn align_addr(addr: u64, align: u64) -> u64 {
        if addr % align == 0 {
            addr
        } else {
            addr + align - addr % align
        }
    }
}

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

    #[test]
    fn test_align_addr() {
        assert_eq!(GlobalState::align_addr(37, 4), 40);
        assert_eq!(GlobalState::align_addr(44, 4), 44);
    }
}
<|endoftext|>


<commit_before>use super::{AllocId, InterpResult};

use rustc_macros::HashStable;
use rustc_target::abi::{HasDataLayout, Size};

use std::convert::TryFrom;
use std::fmt;

////////////////////////////////////////////////////////////////////////////////
// Pointer arithmetic
////////////////////////////////////////////////////////////////////////////////

pub trait PointerArithmetic: HasDataLayout {
    // These are not supposed to be overridden.

    #[inline(always)]
    fn pointer_size(&self) -> Size {
        self.data_layout().pointer_size
    }

    #[inline]
    fn machine_usize_max(&self) -> u64 {
        let max_usize_plus_1 = 1u128 << self.pointer_size().bits();
        u64::try_from(max_usize_plus_1 - 1).unwrap()
    }

    #[inline]
    fn machine_isize_min(&self) -> i64 {
        let max_isize_plus_1 = 1i128 << (self.pointer_size().bits() - 1);
        i64::try_from(-max_isize_plus_1).unwrap()
    }

    #[inline]
    fn machine_isize_max(&self) -> i64 {
        let max_isize_plus_1 = 1u128 << (self.pointer_size().bits() - 1);
        i64::try_from(max_isize_plus_1 - 1).unwrap()
    }

    #[inline]
    fn machine_usize_to_isize(&self, val: u64) -> i64 {
        let val = val as i64;
        // Now clamp into the machine_isize range.
        if val > self.machine_isize_max() {
            // This can only happen the the ptr size is < 64, so we know max_usize_plus_1 fits into
            // i64.
            let max_usize_plus_1 = 1u128 << self.pointer_size().bits();
            val - i64::try_from(max_usize_plus_1).unwrap()
        } else {
            val
        }
    }

    /// Helper function: truncate given value-"overflowed flag" pair to pointer size and
    /// update "overflowed flag" if there was an overflow.
    /// This should be called by all the other methods before returning!
    #[inline]
    fn truncate_to_ptr(&self, (val, over): (u64, bool)) -> (u64, bool) {
        let val = u128::from(val);
        let max_ptr_plus_1 = 1u128 << self.pointer_size().bits();
        (u64::try_from(val % max_ptr_plus_1).unwrap(), over || val >= max_ptr_plus_1)
    }

    #[inline]
    fn overflowing_offset(&self, val: u64, i: u64) -> (u64, bool) {
        // We do not need to check if i fits in a machine usize. If it doesn't,
        // either the wrapping_add will wrap or res will not fit in a pointer.
        let res = val.overflowing_add(i);
        self.truncate_to_ptr(res)
    }

    #[inline]
    fn overflowing_signed_offset(&self, val: u64, i: i64) -> (u64, bool) {
        // We need to make sure that i fits in a machine isize.
        let n = i.unsigned_abs();
        if i >= 0 {
            let (val, over) = self.overflowing_offset(val, n);
            (val, over || i > self.machine_isize_max())
        } else {
            let res = val.overflowing_sub(n);
            let (val, over) = self.truncate_to_ptr(res);
            (val, over || i < self.machine_isize_min())
        }
    }

    #[inline]
    fn offset<'tcx>(&self, val: u64, i: u64) -> InterpResult<'tcx, u64> {
        let (res, over) = self.overflowing_offset(val, i);
        if over { throw_ub!(PointerArithOverflow) } else { Ok(res) }
    }

    #[inline]
    fn signed_offset<'tcx>(&self, val: u64, i: i64) -> InterpResult<'tcx, u64> {
        let (res, over) = self.overflowing_signed_offset(val, i);
        if over { throw_ub!(PointerArithOverflow) } else { Ok(res) }
    }
}

impl<T: HasDataLayout> PointerArithmetic for T {}

/// This trait abstracts over the kind of provenance that is associated with a `Pointer`. It is
/// mostly opaque; the `Machine` trait extends it with some more operations that also have access to
/// some global state.
/// We don't actually care about this `Debug` bound (we use `Provenance::fmt` to format the entire
/// pointer), but `derive` adds some unecessary bounds.
pub trait Provenance: Copy + fmt::Debug {
    /// Says whether the `offset` field of `Pointer`s with this provenance is the actual physical address.
    /// If `true, ptr-to-int casts work by simply discarding the provenance.
    /// If `false`, ptr-to-int casts are not supported. The offset *must* be relative in that case.
    const OFFSET_IS_ADDR: bool;

    /// We also use this trait to control whether to abort execution when a pointer is being partially overwritten
    /// (this avoids a separate trait in `allocation.rs` just for this purpose).
    const ERR_ON_PARTIAL_PTR_OVERWRITE: bool;

    /// Determines how a pointer should be printed.
    fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result
    where
        Self: Sized;

    /// Provenance must always be able to identify the allocation this ptr points to.
    /// (Identifying the offset in that allocation, however, is harder -- use `Memory::ptr_get_alloc` for that.)
    fn get_alloc_id(self) -> AllocId;
}

impl Provenance for AllocId {
    // With the `AllocId` as provenance, the `offset` is interpreted *relative to the allocation*,
    // so ptr-to-int casts are not possible (since we do not know the global physical offset).
    const OFFSET_IS_ADDR: bool = false;

    // For now, do not allow this, so that we keep our options open.
    const ERR_ON_PARTIAL_PTR_OVERWRITE: bool = true;

    fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // Forward `alternate` flag to `alloc_id` printing.
        if f.alternate() {
            write!(f, "{:#?}", ptr.provenance)?;
        } else {
            write!(f, "{:?}", ptr.provenance)?;
        }
        // Print offset only if it is non-zero.
        if ptr.offset.bytes() > 0 {
            write!(f, "+0x{:x}", ptr.offset.bytes())?;
        }
        Ok(())
    }

    fn get_alloc_id(self) -> AllocId {
        self
    }
}

/// Represents a pointer in the Miri engine.
///
/// Pointers are "tagged" with provenance information; typically the `AllocId` they belong to.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, TyEncodable, TyDecodable, Hash)]
#[derive(HashStable)]
pub struct Pointer<Tag = AllocId> {
    pub(super) offset: Size, // kept private to avoid accidental misinterpretation (meaning depends on `Tag` type)
    pub provenance: Tag,
}

static_assert_size!(Pointer, 16);

// We want the `Debug` output to be readable as it is used by `derive(Debug)` for
// all the Miri types.
impl<Tag: Provenance> fmt::Debug for Pointer<Tag> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        Provenance::fmt(self, f)
    }
}

impl<Tag: Provenance> fmt::Debug for Pointer<Option<Tag>> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self.provenance {
            Some(tag) => Provenance::fmt(&Pointer::new(tag, self.offset), f),
            None => write!(f, "0x{:x}", self.offset.bytes()),
        }
    }
}

/// Produces a `Pointer` that points to the beginning of the `Allocation`.
impl From<AllocId> for Pointer {
    #[inline(always)]
    fn from(alloc_id: AllocId) -> Self {
        Pointer::new(alloc_id, Size::ZERO)
    }
}

impl<Tag> From<Pointer<Tag>> for Pointer<Option<Tag>> {
    #[inline(always)]
    fn from(ptr: Pointer<Tag>) -> Self {
        let (tag, offset) = ptr.into_parts();
        Pointer::new(Some(tag), offset)
    }
}

impl<Tag> Pointer<Option<Tag>> {
    pub fn into_pointer_or_addr(self) -> Result<Pointer<Tag>, Size> {
        match self.provenance {
            Some(tag) => Ok(Pointer::new(tag, self.offset)),
            None => Err(self.offset),
        }
    }
}

impl<Tag> Pointer<Option<Tag>> {
    #[inline(always)]
    pub fn null() -> Self {
        Pointer { provenance: None, offset: Size::ZERO }
    }
}

impl<'tcx, Tag> Pointer<Tag> {
    #[inline(always)]
    pub fn new(provenance: Tag, offset: Size) -> Self {
        Pointer { provenance, offset }
    }

    /// Obtain the constituents of this pointer. Not that the meaning of the offset depends on the type `Tag`!
    /// This function must only be used in the implementation of `Machine::ptr_get_alloc`,
    /// and when a `Pointer` is taken apart to be stored efficiently in an `Allocation`.
    #[inline(always)]
    pub fn into_parts(self) -> (Tag, Size) {
        (self.provenance, self.offset)
    }

    pub fn map_provenance(self, f: impl FnOnce(Tag) -> Tag) -> Self {
        Pointer { provenance: f(self.provenance), ..self }
    }

    #[inline]
    pub fn offset(self, i: Size, cx: &impl HasDataLayout) -> InterpResult<'tcx, Self> {
        Ok(Pointer {
            offset: Size::from_bytes(cx.data_layout().offset(self.offset.bytes(), i.bytes())?),
            ..self
        })
    }

    #[inline]
    pub fn overflowing_offset(self, i: Size, cx: &impl HasDataLayout) -> (Self, bool) {
        let (res, over) = cx.data_layout().overflowing_offset(self.offset.bytes(), i.bytes());
        let ptr = Pointer { offset: Size::from_bytes(res), ..self };
        (ptr, over)
    }

    #[inline(always)]
    pub fn wrapping_offset(self, i: Size, cx: &impl HasDataLayout) -> Self {
        self.overflowing_offset(i, cx).0
    }

    #[inline]
    pub fn signed_offset(self, i: i64, cx: &impl HasDataLayout) -> InterpResult<'tcx, Self> {
        Ok(Pointer {
            offset: Size::from_bytes(cx.data_layout().signed_offset(self.offset.bytes(), i)?),
            ..self
        })
    }

    #[inline]
    pub fn overflowing_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> (Self, bool) {
        let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset.bytes(), i);
        let ptr = Pointer { offset: Size::from_bytes(res), ..self };
        (ptr, over)
    }

    #[inline(always)]
    pub fn wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self {
        self.overflowing_signed_offset(i, cx).0
    }
}
<commit_msg>Rollup merge of #88859 - RalfJung:size-helpers, r=oli-obk<commit_after>use super::{AllocId, InterpResult};

use rustc_macros::HashStable;
use rustc_target::abi::{HasDataLayout, Size};

use std::convert::{TryFrom, TryInto};
use std::fmt;

////////////////////////////////////////////////////////////////////////////////
// Pointer arithmetic
////////////////////////////////////////////////////////////////////////////////

pub trait PointerArithmetic: HasDataLayout {
    // These are not supposed to be overridden.

    #[inline(always)]
    fn pointer_size(&self) -> Size {
        self.data_layout().pointer_size
    }

    #[inline]
    fn machine_usize_max(&self) -> u64 {
        self.pointer_size().unsigned_int_max().try_into().unwrap()
    }

    #[inline]
    fn machine_isize_min(&self) -> i64 {
        self.pointer_size().signed_int_min().try_into().unwrap()
    }

    #[inline]
    fn machine_isize_max(&self) -> i64 {
        self.pointer_size().signed_int_max().try_into().unwrap()
    }

    #[inline]
    fn machine_usize_to_isize(&self, val: u64) -> i64 {
        let val = val as i64;
        // Now wrap-around into the machine_isize range.
        if val > self.machine_isize_max() {
            // This can only happen the the ptr size is < 64, so we know max_usize_plus_1 fits into
            // i64.
            debug_assert!(self.pointer_size().bits() < 64);
            let max_usize_plus_1 = 1u128 << self.pointer_size().bits();
            val - i64::try_from(max_usize_plus_1).unwrap()
        } else {
            val
        }
    }

    /// Helper function: truncate given value-"overflowed flag" pair to pointer size and
    /// update "overflowed flag" if there was an overflow.
    /// This should be called by all the other methods before returning!
    #[inline]
    fn truncate_to_ptr(&self, (val, over): (u64, bool)) -> (u64, bool) {
        let val = u128::from(val);
        let max_ptr_plus_1 = 1u128 << self.pointer_size().bits();
        (u64::try_from(val % max_ptr_plus_1).unwrap(), over || val >= max_ptr_plus_1)
    }

    #[inline]
    fn overflowing_offset(&self, val: u64, i: u64) -> (u64, bool) {
        // We do not need to check if i fits in a machine usize. If it doesn't,
        // either the wrapping_add will wrap or res will not fit in a pointer.
        let res = val.overflowing_add(i);
        self.truncate_to_ptr(res)
    }

    #[inline]
    fn overflowing_signed_offset(&self, val: u64, i: i64) -> (u64, bool) {
        // We need to make sure that i fits in a machine isize.
        let n = i.unsigned_abs();
        if i >= 0 {
            let (val, over) = self.overflowing_offset(val, n);
            (val, over || i > self.machine_isize_max())
        } else {
            let res = val.overflowing_sub(n);
            let (val, over) = self.truncate_to_ptr(res);
            (val, over || i < self.machine_isize_min())
        }
    }

    #[inline]
    fn offset<'tcx>(&self, val: u64, i: u64) -> InterpResult<'tcx, u64> {
        let (res, over) = self.overflowing_offset(val, i);
        if over { throw_ub!(PointerArithOverflow) } else { Ok(res) }
    }

    #[inline]
    fn signed_offset<'tcx>(&self, val: u64, i: i64) -> InterpResult<'tcx, u64> {
        let (res, over) = self.overflowing_signed_offset(val, i);
        if over { throw_ub!(PointerArithOverflow) } else { Ok(res) }
    }
}

impl<T: HasDataLayout> PointerArithmetic for T {}

/// This trait abstracts over the kind of provenance that is associated with a `Pointer`. It is
/// mostly opaque; the `Machine` trait extends it with some more operations that also have access to
/// some global state.
/// We don't actually care about this `Debug` bound (we use `Provenance::fmt` to format the entire
/// pointer), but `derive` adds some unecessary bounds.
pub trait Provenance: Copy + fmt::Debug {
    /// Says whether the `offset` field of `Pointer`s with this provenance is the actual physical address.
    /// If `true, ptr-to-int casts work by simply discarding the provenance.
    /// If `false`, ptr-to-int casts are not supported. The offset *must* be relative in that case.
    const OFFSET_IS_ADDR: bool;

    /// We also use this trait to control whether to abort execution when a pointer is being partially overwritten
    /// (this avoids a separate trait in `allocation.rs` just for this purpose).
    const ERR_ON_PARTIAL_PTR_OVERWRITE: bool;

    /// Determines how a pointer should be printed.
    fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result
    where
        Self: Sized;

    /// Provenance must always be able to identify the allocation this ptr points to.
    /// (Identifying the offset in that allocation, however, is harder -- use `Memory::ptr_get_alloc` for that.)
    fn get_alloc_id(self) -> AllocId;
}

impl Provenance for AllocId {
    // With the `AllocId` as provenance, the `offset` is interpreted *relative to the allocation*,
    // so ptr-to-int casts are not possible (since we do not know the global physical offset).
    const OFFSET_IS_ADDR: bool = false;

    // For now, do not allow this, so that we keep our options open.
    const ERR_ON_PARTIAL_PTR_OVERWRITE: bool = true;

    fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // Forward `alternate` flag to `alloc_id` printing.
        if f.alternate() {
            write!(f, "{:#?}", ptr.provenance)?;
        } else {
            write!(f, "{:?}", ptr.provenance)?;
        }
        // Print offset only if it is non-zero.
        if ptr.offset.bytes() > 0 {
            write!(f, "+0x{:x}", ptr.offset.bytes())?;
        }
        Ok(())
    }

    fn get_alloc_id(self) -> AllocId {
        self
    }
}

/// Represents a pointer in the Miri engine.
///
/// Pointers are "tagged" with provenance information; typically the `AllocId` they belong to.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, TyEncodable, TyDecodable, Hash)]
#[derive(HashStable)]
pub struct Pointer<Tag = AllocId> {
    pub(super) offset: Size, // kept private to avoid accidental misinterpretation (meaning depends on `Tag` type)
    pub provenance: Tag,
}

static_assert_size!(Pointer, 16);

// We want the `Debug` output to be readable as it is used by `derive(Debug)` for
// all the Miri types.
impl<Tag: Provenance> fmt::Debug for Pointer<Tag> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        Provenance::fmt(self, f)
    }
}

impl<Tag: Provenance> fmt::Debug for Pointer<Option<Tag>> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self.provenance {
            Some(tag) => Provenance::fmt(&Pointer::new(tag, self.offset), f),
            None => write!(f, "0x{:x}", self.offset.bytes()),
        }
    }
}

/// Produces a `Pointer` that points to the beginning of the `Allocation`.
impl From<AllocId> for Pointer {
    #[inline(always)]
    fn from(alloc_id: AllocId) -> Self {
        Pointer::new(alloc_id, Size::ZERO)
    }
}

impl<Tag> From<Pointer<Tag>> for Pointer<Option<Tag>> {
    #[inline(always)]
    fn from(ptr: Pointer<Tag>) -> Self {
        let (tag, offset) = ptr.into_parts();
        Pointer::new(Some(tag), offset)
    }
}

impl<Tag> Pointer<Option<Tag>> {
    pub fn into_pointer_or_addr(self) -> Result<Pointer<Tag>, Size> {
        match self.provenance {
            Some(tag) => Ok(Pointer::new(tag, self.offset)),
            None => Err(self.offset),
        }
    }
}

impl<Tag> Pointer<Option<Tag>> {
    #[inline(always)]
    pub fn null() -> Self {
        Pointer { provenance: None, offset: Size::ZERO }
    }
}

impl<'tcx, Tag> Pointer<Tag> {
    #[inline(always)]
    pub fn new(provenance: Tag, offset: Size) -> Self {
        Pointer { provenance, offset }
    }

    /// Obtain the constituents of this pointer. Not that the meaning of the offset depends on the type `Tag`!
    /// This function must only be used in the implementation of `Machine::ptr_get_alloc`,
    /// and when a `Pointer` is taken apart to be stored efficiently in an `Allocation`.
    #[inline(always)]
    pub fn into_parts(self) -> (Tag, Size) {
        (self.provenance, self.offset)
    }

    pub fn map_provenance(self, f: impl FnOnce(Tag) -> Tag) -> Self {
        Pointer { provenance: f(self.provenance), ..self }
    }

    #[inline]
    pub fn offset(self, i: Size, cx: &impl HasDataLayout) -> InterpResult<'tcx, Self> {
        Ok(Pointer {
            offset: Size::from_bytes(cx.data_layout().offset(self.offset.bytes(), i.bytes())?),
            ..self
        })
    }

    #[inline]
    pub fn overflowing_offset(self, i: Size, cx: &impl HasDataLayout) -> (Self, bool) {
        let (res, over) = cx.data_layout().overflowing_offset(self.offset.bytes(), i.bytes());
        let ptr = Pointer { offset: Size::from_bytes(res), ..self };
        (ptr, over)
    }

    #[inline(always)]
    pub fn wrapping_offset(self, i: Size, cx: &impl HasDataLayout) -> Self {
        self.overflowing_offset(i, cx).0
    }

    #[inline]
    pub fn signed_offset(self, i: i64, cx: &impl HasDataLayout) -> InterpResult<'tcx, Self> {
        Ok(Pointer {
            offset: Size::from_bytes(cx.data_layout().signed_offset(self.offset.bytes(), i)?),
            ..self
        })
    }

    #[inline]
    pub fn overflowing_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> (Self, bool) {
        let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset.bytes(), i);
        let ptr = Pointer { offset: Size::from_bytes(res), ..self };
        (ptr, over)
    }

    #[inline(always)]
    pub fn wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self {
        self.overflowing_signed_offset(i, cx).0
    }
}
<|endoftext|>


<commit_before>
#[derive(Debug)]
#[repr(packed)] // repr(C) would add unwanted padding before first_section
pub struct ElfSectionsTag {
    typ: u32,
    size: u32,
    pub number_of_sections: u32,
    entry_size: u32,
    shndx: u32, // string table
    first_section: ElfSection,
}

impl ElfSectionsTag {
    pub fn sections(&'static self) -> ElfSectionIter {
        ElfSectionIter {
            current_section: &self.first_section,
            remaining_sections: self.number_of_sections - 1,
            entry_size: self.entry_size,
        }
    }
}

#[derive(Clone)]
pub struct ElfSectionIter {
    current_section: &'static ElfSection,
    remaining_sections: u32,
    entry_size: u32,
}

impl Iterator for ElfSectionIter {
    type Item = &'static ElfSection;
    fn next(&mut self) -> Option<&'static ElfSection> {
        if self.remaining_sections == 0 {
            None
        } else {
            let section = self.current_section;
            let next_section_addr = (self.current_section as *const _ as u32) + self.entry_size;
            self.current_section = unsafe{ &*(next_section_addr as *const ElfSection) };
            self.remaining_sections -= 1;
			if section.typ == ElfSectionType::Unused as u32 {
				self.next()
			} else {
	            Some(section)
			}
        }
    }
}

#[derive(Debug)]
#[repr(C)]
pub struct ElfSection {
    name: u32,
    typ: u32,
    pub flags: u64,
    pub addr: u64,
    offset: u64,
    pub size: u64,
    link: u32,
    info: u32,
    addralign: u64,
    entry_size: u64,
}

impl ElfSection {
    pub fn flags(&self) -> ElfSectionFlags {
        ElfSectionFlags::from_bits_truncate(self.flags)
    }

    pub fn is_allocated(&self) -> bool {
        self.flags().contains(ELF_SECTION_ALLOCATED)
    }
}

#[repr(u32)]
pub enum ElfSectionType {
    Unused = 0,
    ProgramSection = 1,
    LinkerSymbolTable = 2,
    StringTable = 3,
    RelaRelocation = 4,
    SymbolHashTable = 5,
    DynamicLinkingTable = 6,
    Note = 7,
    Uninitialized = 8,
    RelRelocation = 9,
    Reserved = 10,
    DynamicLoaderSymbolTable = 11,
    // plus environment-specific use from 0x60000000 to 0x6FFFFFFF
    // plus processor-specific use from 0x70000000 to 0x7FFFFFFF
}

bitflags! {
    flags ElfSectionFlags: u64 {
        const ELF_SECTION_WRITABLE = 0x1,
        const ELF_SECTION_ALLOCATED = 0x2,
        const ELF_SECTION_EXECUTABLE = 0x4,
        // plus environment-specific use at 0x0F000000
        // plus processor-specific use at 0xF0000000
    }
}
<commit_msg>Add start_address and end_address methods to ElfSection too<commit_after>
#[derive(Debug)]
#[repr(packed)] // repr(C) would add unwanted padding before first_section
pub struct ElfSectionsTag {
    typ: u32,
    size: u32,
    pub number_of_sections: u32,
    entry_size: u32,
    shndx: u32, // string table
    first_section: ElfSection,
}

impl ElfSectionsTag {
    pub fn sections(&'static self) -> ElfSectionIter {
        ElfSectionIter {
            current_section: &self.first_section,
            remaining_sections: self.number_of_sections - 1,
            entry_size: self.entry_size,
        }
    }
}

#[derive(Clone)]
pub struct ElfSectionIter {
    current_section: &'static ElfSection,
    remaining_sections: u32,
    entry_size: u32,
}

impl Iterator for ElfSectionIter {
    type Item = &'static ElfSection;
    fn next(&mut self) -> Option<&'static ElfSection> {
        if self.remaining_sections == 0 {
            None
        } else {
            let section = self.current_section;
            let next_section_addr = (self.current_section as *const _ as u32) + self.entry_size;
            self.current_section = unsafe{ &*(next_section_addr as *const ElfSection) };
            self.remaining_sections -= 1;
			if section.typ == ElfSectionType::Unused as u32 {
				self.next()
			} else {
	            Some(section)
			}
        }
    }
}

#[derive(Debug)]
#[repr(C)]
pub struct ElfSection {
    name: u32,
    typ: u32,
    pub flags: u64,
    pub addr: u64,
    offset: u64,
    pub size: u64,
    link: u32,
    info: u32,
    addralign: u64,
    entry_size: u64,
}

impl ElfSection {
    pub fn start_address(&self) -> usize {
        self.addr as usize
    }

    pub fn end_address(&self) -> usize {
        (self.addr + self.size) as usize
    }

    pub fn flags(&self) -> ElfSectionFlags {
        ElfSectionFlags::from_bits_truncate(self.flags)
    }

    pub fn is_allocated(&self) -> bool {
        self.flags().contains(ELF_SECTION_ALLOCATED)
    }
}

#[repr(u32)]
pub enum ElfSectionType {
    Unused = 0,
    ProgramSection = 1,
    LinkerSymbolTable = 2,
    StringTable = 3,
    RelaRelocation = 4,
    SymbolHashTable = 5,
    DynamicLinkingTable = 6,
    Note = 7,
    Uninitialized = 8,
    RelRelocation = 9,
    Reserved = 10,
    DynamicLoaderSymbolTable = 11,
    // plus environment-specific use from 0x60000000 to 0x6FFFFFFF
    // plus processor-specific use from 0x70000000 to 0x7FFFFFFF
}

bitflags! {
    flags ElfSectionFlags: u64 {
        const ELF_SECTION_WRITABLE = 0x1,
        const ELF_SECTION_ALLOCATED = 0x2,
        const ELF_SECTION_EXECUTABLE = 0x4,
        // plus environment-specific use at 0x0F000000
        // plus processor-specific use at 0xF0000000
    }
}
<|endoftext|>


<commit_before>use utils::u256::U256;
use utils::address::Address;

pub trait Account {
    type Sto: Storage;

    fn address(&self) -> Address;
    fn balance(&self) -> U256;
    fn storage(&self) -> &Sto;
    fn storage_mut(&mut self) -> &mut Sto;
    fn code(&self) -> Option<&[u8]>;
}

pub struct FakeAccount {
    address: Address,
    nonce: usize,
    balance: U256,
    storage: FakeStorage,
    code: Option<Vec<u8>>,
}

impl FakeAccount {
    pub fn new(address: Address) -> FakeAccount {
        FakeAccount::with_code(address, None);
    }

    pub fn with_code(address: Address, code: Option<&[u8]>) -> FakeAccount {
        FakeAccount {
            address: Address,
            nounce: 0,
            balance: U256::zero(),
            storage: FakeStorage::new(),
            code: code.map(|s| s.into())
        }
    }
}

impl Default for FakeAccount {
    fn default() -> FakeAccount {
        FakeAccount::new(Address::default())
    }
}

impl Account for FakeAccount {
    type Storage = FakeStorage;

    fn address(&self) -> Address {
        self.address
    }

    fn balance(&self) -> U256 {
        self.balance
    }

    fn storage(&self) -> &Storage {
        &self.storage
    }

    fn storage_mut(&self) -> &mut Storage {
        &mut self.storage
    }

    fn code(&self) -> Option<&[u8]> {
        self.code.map(|s| s.into())
    }
}

pub trait Storage { // A word-addressable word array, similar to memory, and is not volatile.
    fn write(&mut self, index: U256, value: U256);
    fn read(&self, index: U256) -> U256;
}

pub struct FakeStorage {
    storage: Vec<U256>,
}

impl FakeStorage {
    pub fn new() -> FakeStorage {
        FakeStorage {
            storage: Vec::new(),
        }
    }
}

impl Storage for FakeStorage {
    fn write(&mut self, index: U256, value: U256) {
        let index: usize = index.into();

        if self.storage.len() <= index {
            self.storage.resize(index, 0.into());
        }

        self.storage[index] = value;
    }

    fn read(&self, index: U256) -> U256 {
        let index: usize = index.into();

        match self.storage.get(index) {
            Some(&v) => v,
            None => U256::zero()
        }
    }
}
<commit_msg>Problem: Account results in circular dependency Solution: remove Account struct<commit_after>use utils::u256::U256;
use utils::address::Address;

pub trait Storage { // A word-addressable word array, similar to memory, and is not volatile.
    fn write(&mut self, index: U256, value: U256);
    fn read(&self, index: U256) -> U256;
}

pub struct VectorStorage {
    storage: Vec<U256>,
}

impl VectorStorage {
    pub fn new() -> VectorStorage {
        VectorStorage {
            storage: Vec::new(),
        }
    }

    pub fn with_storage(storage: &[U256]) -> VectorStorage {
        VectorStorage {
            storage: storage.into(),
        }
    }
}

impl Storage for VectorStorage {
    fn write(&mut self, index: U256, value: U256) {
        let index: usize = index.into();

        if self.storage.len() <= index {
            self.storage.resize(index, 0.into());
        }

        self.storage[index] = value;
    }

    fn read(&self, index: U256) -> U256 {
        let index: usize = index.into();

        match self.storage.get(index) {
            Some(&v) => v,
            None => U256::zero()
        }
    }
}
<|endoftext|>


<commit_before>//! Error formatting a struct

use core::fmt;
use std::io;

use crate::error;

/// An error occurred when formatting.
#[non_exhaustive]
#[allow(missing_copy_implementations)]
#[cfg_attr(__time_03_docs, doc(cfg(feature = "formatting")))]
#[derive(Debug)]
pub enum Format {
    /// The type being formatted does not contain sufficient information to format a component.
    #[non_exhaustive]
    InsufficientTypeInformation,
    /// The component named has a value that cannot be formatted into the requested format.
    ///
    /// This variant is only returned when using well-known formats.
    InvalidComponent(&'static str),
    /// A value of `std::io::Error` was returned internally.
    StdIo(io::Error),
}

impl fmt::Display for Format {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::InsufficientTypeInformation => f.write_str(
                "The type being formatted does not contain sufficient information to format a \
                 component.",
            ),
            Self::InvalidComponent(component) => write!(
                f,
                "The {} component cannot be formatted into the requested format.",
                component
            ),
            Self::StdIo(err) => err.fmt(f),
        }
    }
}

impl From<io::Error> for Format {
    fn from(err: io::Error) -> Self {
        Self::StdIo(err)
    }
}

impl TryFrom<Format> for io::Error {
    type Error = error::DifferentVariant;

    fn try_from(err: Format) -> Result<Self, Self::Error> {
        match err {
            Format::StdIo(err) => Ok(err),
            _ => Err(error::DifferentVariant),
        }
    }
}

#[cfg(feature = "std")]
impl std::error::Error for Format {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match *self {
            Self::InsufficientTypeInformation | Self::InvalidComponent(_) => None,
            Self::StdIo(ref err) => Some(err),
        }
    }
}

#[cfg_attr(__time_03_docs, doc(cfg(feature = "formatting")))]
impl From<Format> for crate::Error {
    fn from(original: Format) -> Self {
        Self::Format(original)
    }
}

#[cfg_attr(__time_03_docs, doc(cfg(feature = "formatting")))]
impl TryFrom<crate::Error> for Format {
    type Error = error::DifferentVariant;

    fn try_from(err: crate::Error) -> Result<Self, Self::Error> {
        match err {
            crate::Error::Format(err) => Ok(err),
            _ => Err(error::DifferentVariant),
        }
    }
}

#[cfg(feature = "serde")]
impl Format {
    /// Obtain an error type for the serializer.
    #[doc(hidden)] // Exposed only for the `declare_format_string` macro
    pub fn into_invalid_serde_value<S: serde::Serializer>(self) -> S::Error {
        use serde::ser::Error;
        S::Error::custom(format!("{}", self))
    }
}
<commit_msg>Avoid unnecessary call to `format!`<commit_after>//! Error formatting a struct

use core::fmt;
use std::io;

use crate::error;

/// An error occurred when formatting.
#[non_exhaustive]
#[allow(missing_copy_implementations)]
#[cfg_attr(__time_03_docs, doc(cfg(feature = "formatting")))]
#[derive(Debug)]
pub enum Format {
    /// The type being formatted does not contain sufficient information to format a component.
    #[non_exhaustive]
    InsufficientTypeInformation,
    /// The component named has a value that cannot be formatted into the requested format.
    ///
    /// This variant is only returned when using well-known formats.
    InvalidComponent(&'static str),
    /// A value of `std::io::Error` was returned internally.
    StdIo(io::Error),
}

impl fmt::Display for Format {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::InsufficientTypeInformation => f.write_str(
                "The type being formatted does not contain sufficient information to format a \
                 component.",
            ),
            Self::InvalidComponent(component) => write!(
                f,
                "The {} component cannot be formatted into the requested format.",
                component
            ),
            Self::StdIo(err) => err.fmt(f),
        }
    }
}

impl From<io::Error> for Format {
    fn from(err: io::Error) -> Self {
        Self::StdIo(err)
    }
}

impl TryFrom<Format> for io::Error {
    type Error = error::DifferentVariant;

    fn try_from(err: Format) -> Result<Self, Self::Error> {
        match err {
            Format::StdIo(err) => Ok(err),
            _ => Err(error::DifferentVariant),
        }
    }
}

#[cfg(feature = "std")]
impl std::error::Error for Format {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match *self {
            Self::InsufficientTypeInformation | Self::InvalidComponent(_) => None,
            Self::StdIo(ref err) => Some(err),
        }
    }
}

#[cfg_attr(__time_03_docs, doc(cfg(feature = "formatting")))]
impl From<Format> for crate::Error {
    fn from(original: Format) -> Self {
        Self::Format(original)
    }
}

#[cfg_attr(__time_03_docs, doc(cfg(feature = "formatting")))]
impl TryFrom<crate::Error> for Format {
    type Error = error::DifferentVariant;

    fn try_from(err: crate::Error) -> Result<Self, Self::Error> {
        match err {
            crate::Error::Format(err) => Ok(err),
            _ => Err(error::DifferentVariant),
        }
    }
}

#[cfg(feature = "serde")]
impl Format {
    /// Obtain an error type for the serializer.
    #[doc(hidden)] // Exposed only for the `declare_format_string` macro
    pub fn into_invalid_serde_value<S: serde::Serializer>(self) -> S::Error {
        use serde::ser::Error;
        S::Error::custom(self)
    }
}
<|endoftext|>