From bc5f194a504bf09d3823f2967e8120b66bdb9b32 Mon Sep 17 00:00:00 2001 From: ge Date: Fri, 26 Dec 2025 02:36:59 +0300 Subject: [PATCH] all: optimizations & docs fixes --- README.md | 4 +- dataunits.v | 97 +++++++++++++++++++++++++++++------------- tests/dataunits_test.v | 46 +++++++++++++++++++- 3 files changed, 114 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 5c8dec6..ab647f6 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -## Data size units converter +# Data Unit Converter Installation: ``` -v install --git https://github.com/gechandesu/dataunits +v install https://github.com/gechandesu/dataunits ``` Example: diff --git a/dataunits.v b/dataunits.v index 2d25b7b..cc2ed62 100644 --- a/dataunits.v +++ b/dataunits.v @@ -1,10 +1,10 @@ // This is free and unencumbered software released into the public domain. - +// // Anyone is free to copy, modify, publish, use, compile, sell, or // distribute this software, either in source code form or as a compiled // binary, for any purpose, commercial or non-commercial, and by any // means. - +// // In jurisdictions that recognize copyright laws, the author or authors // of this software dedicate any and all copyright interest in the // software to the public domain. We make this dedication for the benefit @@ -12,7 +12,7 @@ // successors. We intend this dedication to be an overt act of // relinquishment in perpetuity of all present and future rights to this // software under copyright law. - +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. @@ -20,13 +20,11 @@ // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. - +// // For more information, please refer to module dataunits -import maps - pub type DataSize = f64 pub fn (d DataSize) bit() f64 { @@ -209,7 +207,7 @@ pub const eibit = pibit * 1024 pub const zibit = eibit * 1024 pub const yibit = zibit * 1024 -const units = { +const str_unit = { 'bit': bit 'nibble': nibble 'byte': byte @@ -247,8 +245,46 @@ const units = { 'Yibit': yibit } +const unit_str = { + bit: 'bit' + nibble: 'nibble' + byte: 'byte' + kb: 'kB' + mb: 'MB' + gb: 'GB' + tb: 'TB' + pb: 'PB' + eb: 'EB' + zb: 'ZB' + yb: 'YB' + kib: 'KiB' + mib: 'MiB' + gib: 'GiB' + tib: 'TiB' + pib: 'PiB' + eib: 'EiB' + zib: 'ZiB' + yib: 'YiB' + kbit: 'kbit' + mbit: 'Mbit' + gbit: 'Gbit' + tbit: 'Tbit' + pbit: 'Pbit' + ebit: 'Ebit' + zbit: 'Zbit' + ybit: 'Ybit' + kibit: 'Kibit' + mibit: 'Mibit' + gibit: 'Gibit' + tibit: 'Tibit' + pibit: 'Pibit' + eibit: 'Eibit' + zibit: 'Zibit' + yibit: 'Yibit' +} + pub const prefixes = { - // Metric size (1000^N) + // Metric size (N * 1000) 'kilo': 'k' 'mega': 'M' 'giga': 'G' @@ -257,7 +293,7 @@ pub const prefixes = { 'exa': 'E' 'zetta': 'Z' 'yotta': 'Y' - // Binary size (1024^N) + // Binary size (N * 1024) 'kibi': 'Ki' 'mebi': 'Mi' 'gibi': 'Gi' @@ -268,9 +304,19 @@ pub const prefixes = { 'yobi': 'Yi' } +// vfmt off +const prefixes_array = [ + 'byte', 'B', + 'kilo', 'k', 'mega', 'M', 'giga', 'G', 'tera', 'T', + 'peta', 'P', 'exa', 'E', 'zetta', 'Z', 'yotta', 'Y', + 'kibi', 'Ki', 'mebi', 'Mi', 'gibi', 'Gi', 'tebi', 'Ti', + 'pebi', 'Pi', 'exbi', 'Ei', 'zebi', 'Zi', 'yobi', 'Yi' +] +// vfmt on + // convert returns the value converted between the *from* and *to* units. // Example: -// ``` +// ```v // assert dataunits.convert(500, dataunits.mbit, dataunits.kb) == 62500 // ```` pub fn convert(value f64, from DataSize, to DataSize) f64 { @@ -281,10 +327,10 @@ pub fn convert(value f64, from DataSize, to DataSize) f64 { } // from_string parses input and returns the actual DataSize. -// Note: Case insensitivity makes unit abbreviations such as `Mb` (megabit) and `MB` (megabyte) -// ambiguous. Use `bit` suffix for values in bits. The `b` suffix will be accepted as byte unit. +// Note: Case insensitivity makes unit abbreviations such as 'Mb' (megabit) and 'MB' (megabyte) +// ambiguous. Use 'bit' suffix for values in bits. The 'b' suffix will be accepted as byte unit. // Example: -// ``` +// ```v // assert dataunits.from_string('GiB')! == dataunits.gib // assert dataunits.from_string('M')! == dataunits.mb // assert dataunits.from_string('M', in_bits: true)! == dataunits.mbit @@ -292,20 +338,20 @@ pub fn convert(value f64, from DataSize, to DataSize) f64 { // ``` pub fn from_string(input string, params ParseParams) !DataSize { if !input.is_pure_ascii() { - return error('${input} non-ASCII characters is not allowed in data size unit') + return error('${input} non-ASCII characters is not allowed in data unit') } - unit := parse_unit_str(input, params) + unit := parse_str(input, params) if params.case_insensitive { - for key, value in units { + for key, value in str_unit { if key.to_lower_ascii() == unit.to_lower_ascii() { return value } } } - return units[unit] or { error('${input} is not a valid data size unit') } + return str_unit[unit] or { error('${input} is not a valid data unit') } } -fn parse_unit_str(input string, params ParseParams) string { +fn parse_str(input string, params ParseParams) string { mut unit := '' match true { input.to_lower_ascii() in ['byte', 'bytes'] { @@ -352,10 +398,7 @@ fn parse_unit_str(input string, params ParseParams) string { // prevent Gibit --> Git transform return unit } - // transform full names to short ones: megabits --> mbit, etc. - prefixes_array := maps.flat_map[string, string, string](prefixes, |k, v| [k, v]) - unit = unit.replace_each(prefixes_array) - unit = unit.replace_each(['bytes', 'B', 'byte', 'B']).replace_once('bits', 'bit') + unit = unit.all_before('s').replace_each(prefixes_array) return unit } @@ -370,13 +413,7 @@ pub: binary_size bool } -// to_string returns a string representation of data size unit in short form -// e.g. kB, Mbit, GiB, etc. +// to_string returns a string representation of data unit in short form e.g. kB, Mbit, GiB, etc. pub fn to_string(input DataSize) !string { - for key, value in units { - if value == input { - return key - } - } - return error('invalid input data size unit') + return unit_str[input] or { error('invalid input data unit') } } diff --git a/tests/dataunits_test.v b/tests/dataunits_test.v index 3fe0fef..34d9056 100644 --- a/tests/dataunits_test.v +++ b/tests/dataunits_test.v @@ -5,7 +5,7 @@ fn test_convert() { assert (dataunits.bit * 8).bit() == 8 assert (dataunits.bit * 8).byte() == 1 assert (dataunits.gib * 10).mib() == 10240 - assert (dataunits.gib * 5000).byte() == i64(5368709120000) + assert (dataunits.gib * 5000).byte() == f64(5368709120000) assert (dataunits.mbit * 500).kb() == 62500 assert dataunits.convert(500, dataunits.mbit, dataunits.kb) == 62500 assert dataunits.DataSize(4000 * dataunits.gib).byte() == f64(4294967296000) @@ -37,3 +37,47 @@ fn test_from_string() { assert dataunits.from_string('Ki')! == dataunits.kib assert dataunits.from_string('Gi')! == dataunits.gib } + +const units = [ + dataunits.bit, + dataunits.nibble, + dataunits.byte, + dataunits.kb, + dataunits.mb, + dataunits.gb, + dataunits.tb, + dataunits.pb, + dataunits.eb, + dataunits.zb, + dataunits.yb, + dataunits.kib, + dataunits.mib, + dataunits.gib, + dataunits.tib, + dataunits.pib, + dataunits.eib, + dataunits.zib, + dataunits.yib, + dataunits.kbit, + dataunits.mbit, + dataunits.gbit, + dataunits.tbit, + dataunits.pbit, + dataunits.ebit, + dataunits.zbit, + dataunits.ybit, + dataunits.kibit, + dataunits.mibit, + dataunits.gibit, + dataunits.tibit, + dataunits.pibit, + dataunits.eibit, + dataunits.zibit, + dataunits.yibit, +] + +fn test_from_string_to_string() { + for unit in units { + assert dataunits.from_string(dataunits.to_string(unit)!)! == unit + } +}