namespace Spectre.Console; internal struct FileSize { public double Bytes { get; } public FileSizeUnit Unit { get; } public string Suffix => GetSuffix(); public FileSize(double bytes) { Bytes = bytes; Unit = Detect(bytes); } public FileSize(double bytes, FileSizeUnit unit) { Bytes = bytes; Unit = unit; } public string Format(CultureInfo? culture = null) { var @base = GetBase(Unit); if (@base == 0) { @base = 1; } var bytes = Bytes / @base; return Unit == FileSizeUnit.Byte ? ((int)bytes).ToString(culture ?? CultureInfo.InvariantCulture) : bytes.ToString("F1", culture ?? CultureInfo.InvariantCulture); } public override string ToString() { return ToString(suffix: true, CultureInfo.InvariantCulture); } public string ToString(bool suffix = true, CultureInfo? culture = null) { if (suffix) { return $"{Format(culture)} {Suffix}"; } return Format(culture); } private string GetSuffix() { return (Bytes, Unit) switch { (_, FileSizeUnit.KiloByte) => "KB", (_, FileSizeUnit.MegaByte) => "MB", (_, FileSizeUnit.GigaByte) => "GB", (_, FileSizeUnit.TeraByte) => "TB", (_, FileSizeUnit.PetaByte) => "PB", (_, FileSizeUnit.ExaByte) => "EB", (_, FileSizeUnit.ZettaByte) => "ZB", (_, FileSizeUnit.YottaByte) => "YB", (1, _) => "byte", (_, _) => "bytes", }; } private static FileSizeUnit Detect(double bytes) { foreach (var unit in (FileSizeUnit[])Enum.GetValues(typeof(FileSizeUnit))) { if (bytes < (GetBase(unit) * 1024)) { return unit; } } return FileSizeUnit.Byte; } private static double GetBase(FileSizeUnit unit) { return Math.Pow(1024, (int)unit); } }