#![cfg_attr(test, feature(test))]
#![warn(clippy::all, clippy::cargo, clippy::nursery, clippy::pedantic)]
#![allow(
clippy::cast_precision_loss,
clippy::cast_sign_loss,
clippy::cast_possible_truncation
)]
#![no_std]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct LevelInfo {
xp: u64,
level: u64,
percentage: u8,
}
impl LevelInfo {
#[must_use]
pub fn new(xp: u64) -> Self {
let level = {
let xp = xp as f64;
let mut testxp = 0.0;
let mut level = 0;
while xp >= testxp {
level += 1;
testxp = Self::xp_to_level(f64::from(level));
}
level - 1
};
let last_level_xp_requirement = Self::xp_to_level(f64::from(level));
let next_level_xp_requirement = Self::xp_to_level(f64::from(level + 1));
Self {
xp,
level: level as u64,
percentage: (((xp as f64 - last_level_xp_requirement)
/ (next_level_xp_requirement - last_level_xp_requirement))
* 100.0) as u8,
}
}
#[must_use]
#[inline]
pub const fn xp(&self) -> u64 {
self.xp
}
#[must_use]
#[inline]
pub const fn level(&self) -> u64 {
self.level
}
#[must_use]
#[inline]
pub const fn percentage(&self) -> u8 {
self.percentage
}
#[allow(clippy::suboptimal_flops)]
#[inline]
#[must_use]
pub fn xp_to_level(level: f64) -> f64 {
(5.0 / 6.0) * level * (2.0 * level * level + 27.0 * level + 91.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
extern crate test;
#[test]
fn level() {
let inf = LevelInfo::new(3255);
assert_eq!(inf.level(), 8);
}
#[test]
fn xp() {
let inf = LevelInfo::new(3255);
assert_eq!(inf.xp(), 3255);
}
#[test]
fn percentage() {
let inf = LevelInfo::new(3255);
assert_eq!(inf.percentage(), 43);
}
#[bench]
fn create_levelinfo(b: &mut test::Bencher) {
b.iter(|| {
for i in 1..1_000_000 {
test::black_box(LevelInfo::new(i));
}
})
}
}