use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct LocaleFlags(pub u32);
impl LocaleFlags {
pub const NONE: Self = Self(0);
pub const EN_US: Self = Self(0x2);
pub const KO_KR: Self = Self(0x4);
pub const FR_FR: Self = Self(0x10);
pub const DE_DE: Self = Self(0x20);
pub const ZH_CN: Self = Self(0x40);
pub const ES_ES: Self = Self(0x80);
pub const ZH_TW: Self = Self(0x100);
pub const EN_GB: Self = Self(0x200);
pub const EN_CN: Self = Self(0x400);
pub const EN_TW: Self = Self(0x800);
pub const ES_MX: Self = Self(0x1000);
pub const RU_RU: Self = Self(0x2000);
pub const PT_BR: Self = Self(0x4000);
pub const IT_IT: Self = Self(0x8000);
pub const PT_PT: Self = Self(0x10000);
pub const ALL: Self = Self(0xFFFFFFFF);
pub fn contains(self, other: Self) -> bool {
(self.0 & other.0) != 0
}
pub fn matches(self, filter: Self) -> bool {
filter.0 == 0 || (self.0 & filter.0) != 0
}
}
impl fmt::Display for LocaleFlags {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.0 == 0 {
return write!(f, "None");
}
if self.0 == 0xFFFFFFFF {
return write!(f, "All");
}
const NAMES: &[(u32, &str)] = &[
(0x2, "enUS"),
(0x4, "koKR"),
(0x10, "frFR"),
(0x20, "deDE"),
(0x40, "zhCN"),
(0x80, "esES"),
(0x100, "zhTW"),
(0x200, "enGB"),
(0x400, "enCN"),
(0x800, "enTW"),
(0x1000, "esMX"),
(0x2000, "ruRU"),
(0x4000, "ptBR"),
(0x8000, "itIT"),
(0x10000, "ptPT"),
];
let mut first = true;
for &(bit, name) in NAMES {
if (self.0 & bit) != 0 {
if !first {
write!(f, "|")?;
}
write!(f, "{}", name)?;
first = false;
}
}
if first {
write!(f, "0x{:X}", self.0)?;
}
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ContentFlags(pub u32);
impl ContentFlags {
pub const NONE: Self = Self(0);
pub const HIGH_RES_TEXTURE: Self = Self(0x1);
pub const INSTALL: Self = Self(0x4);
pub const LOAD_ON_WINDOWS: Self = Self(0x8);
pub const LOAD_ON_MACOS: Self = Self(0x10);
pub const X86_32: Self = Self(0x20);
pub const X86_64: Self = Self(0x40);
pub const LOW_VIOLENCE: Self = Self(0x80);
pub const DO_NOT_LOAD: Self = Self(0x100);
pub const UPDATE_PLUGIN: Self = Self(0x800);
pub const ARM64: Self = Self(0x8000);
pub const ENCRYPTED: Self = Self(0x8000000);
pub const NO_NAME_HASH: Self = Self(0x10000000);
pub const UNCOMMON_RES: Self = Self(0x20000000);
pub const BUNDLE: Self = Self(0x40000000);
pub const NO_COMPRESSION: Self = Self(0x80000000);
pub fn has(self, flag: Self) -> bool {
(self.0 & flag.0) != 0
}
pub fn has_no_name_hash(self) -> bool {
self.has(Self::NO_NAME_HASH)
}
}
impl fmt::Display for ContentFlags {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.0 == 0 {
return write!(f, "None");
}
const NAMES: &[(u32, &str)] = &[
(0x1, "HighResTexture"),
(0x4, "Install"),
(0x8, "LoadOnWindows"),
(0x10, "LoadOnMacOS"),
(0x20, "x86_32"),
(0x40, "x86_64"),
(0x80, "LowViolence"),
(0x100, "DoNotLoad"),
(0x800, "UpdatePlugin"),
(0x8000, "ARM64"),
(0x8000000, "Encrypted"),
(0x10000000, "NoNameHash"),
(0x20000000, "UncommonRes"),
(0x40000000, "Bundle"),
(0x80000000, "NoCompression"),
];
let mut first = true;
for &(bit, name) in NAMES {
if (self.0 & bit) != 0 {
if !first {
write!(f, "|")?;
}
write!(f, "{}", name)?;
first = false;
}
}
if first {
write!(f, "0x{:X}", self.0)?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn locale_enus() {
assert_eq!(LocaleFlags::EN_US.0, 0x2);
}
#[test]
fn locale_dede() {
assert_eq!(LocaleFlags::DE_DE.0, 0x20);
}
#[test]
fn locale_contains() {
let flags = LocaleFlags(0x2 | 0x200); assert!(flags.contains(LocaleFlags::EN_US));
assert!(flags.contains(LocaleFlags::EN_GB));
assert!(!flags.contains(LocaleFlags::DE_DE));
}
#[test]
fn locale_matches_filter() {
let flags = LocaleFlags(0x2); assert!(flags.matches(LocaleFlags::EN_US));
assert!(!flags.matches(LocaleFlags::DE_DE));
assert!(flags.matches(LocaleFlags::ALL)); }
#[test]
fn locale_matches_none_filter() {
let flags = LocaleFlags(0x2);
assert!(flags.matches(LocaleFlags::NONE));
}
#[test]
fn content_no_name_hash() {
let flags = ContentFlags(0x10000000);
assert!(flags.has_no_name_hash());
}
#[test]
fn content_flags_combined() {
let flags = ContentFlags(0x8 | 0x40); assert!(flags.has(ContentFlags::LOAD_ON_WINDOWS));
assert!(flags.has(ContentFlags::X86_64));
assert!(!flags.has(ContentFlags::LOAD_ON_MACOS));
}
#[test]
fn content_flags_none_has_nothing() {
let flags = ContentFlags::NONE;
assert!(!flags.has(ContentFlags::LOAD_ON_WINDOWS));
assert!(!flags.has_no_name_hash());
}
#[test]
fn locale_display_single() {
assert_eq!(format!("{}", LocaleFlags::EN_US), "enUS");
}
#[test]
fn locale_display_combined() {
let flags = LocaleFlags(0x2 | 0x20); assert_eq!(format!("{}", flags), "enUS|deDE");
}
#[test]
fn locale_display_none() {
assert_eq!(format!("{}", LocaleFlags::NONE), "None");
}
#[test]
fn locale_display_all() {
assert_eq!(format!("{}", LocaleFlags::ALL), "All");
}
#[test]
fn content_display_single() {
assert_eq!(
format!("{}", ContentFlags::LOAD_ON_WINDOWS),
"LoadOnWindows"
);
}
#[test]
fn content_display_combined() {
let flags = ContentFlags(0x8 | 0x10000000); assert_eq!(format!("{}", flags), "LoadOnWindows|NoNameHash");
}
#[test]
fn content_display_none() {
assert_eq!(format!("{}", ContentFlags::NONE), "None");
}
}