14 Commits

Author SHA1 Message Date
ge
1a0d5c8ca7 ci: update docs CI 2025-12-26 02:39:57 +03:00
ge
8e41fdc40a mod: bump version 2025-12-26 02:37:51 +03:00
ge
bc5f194a50 all: optimizations & docs fixes 2025-12-26 02:36:59 +03:00
ge
a35f385574 remove Makefile 2025-05-29 23:59:12 +03:00
ge
21faadcfc7 makefile: fix 2025-04-22 20:03:50 +03:00
ge
d744ebf9f2 cmd: rename dataunit to datasize 2025-04-22 19:58:46 +03:00
ge
13897bf625 ci: add tests CI 2025-04-22 19:56:58 +03:00
ge
13767d8c0c all: stop using src/ dir 2025-04-22 19:51:49 +03:00
ge
72bef1ea47 doc: add .vdocignore
Some checks failed
CI / build (push) Has been cancelled
CI / deploy (push) Has been cancelled
2025-03-29 20:45:24 +03:00
gechandesu
e89bf7dbc1 ci: Add docs website
Some checks failed
CI / build (push) Has been cancelled
CI / deploy (push) Has been cancelled
2025-03-29 20:41:58 +03:00
ge
53a0d77ecb bump version 2025-01-13 20:55:02 +03:00
ge
f4fe18ed49 fix example 2025-01-13 20:54:32 +03:00
ge
8dc59e114c add cmd/dataunit, example 2025-01-13 20:34:25 +03:00
ge
9206200515 breaking: replace bytes with byte, upd parser, etc 2025-01-13 19:32:42 +03:00
11 changed files with 289 additions and 105 deletions

48
.github/workflows/docs.yaml vendored Normal file
View File

@@ -0,0 +1,48 @@
name: Docs
on:
push:
branches: [ "master" ]
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup V
run: |
wget -qO /tmp/v.zip https://github.com/vlang/v/releases/latest/download/v_linux.zip
unzip -q /tmp/v.zip -d /tmp
echo /tmp/v >> "$GITHUB_PATH"
- name: Build docs
run: |
v doc -f html -m .
pushd _docs
ln -vs ${{ github.event.repository.name }}.html index.html
ls -alFh
popd
- name: Upload static files as artifact
id: deployment
uses: actions/upload-pages-artifact@v3
with:
path: _docs/
deploy:
needs: build
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
permissions:
contents: read
pages: write
id-token: write

24
.github/workflows/test.yaml vendored Normal file
View File

@@ -0,0 +1,24 @@
name: Tests
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
workflow_dispatch:
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup V
run: |
wget -qO /tmp/v.zip https://github.com/vlang/v/releases/latest/download/v_linux.zip
unzip -q /tmp/v.zip -d /tmp
echo /tmp/v >> "$GITHUB_PATH"
- name: Run tests
run: |
v -stats test .

2
.gitignore vendored
View File

@@ -1,6 +1,6 @@
# Binaries for programs and plugins # Binaries for programs and plugins
main main
dataunit /dataunit
*.exe *.exe
*.exe~ *.exe~
*.so *.so

2
.vdocignore Normal file
View File

@@ -0,0 +1,2 @@
examples/
cmd/

View File

@@ -1,23 +0,0 @@
SRC_DIR ?= src
DOC_DIR ?= doc
TESTS_DIR ?= .
all: test
test:
v test $(TESTS_DIR)
doc:
v doc -f html -m ./$(SRC_DIR) -o $(DOC_DIR)
serve: clean doc
v -e "import net.http.file; file.serve(folder: '$(DOC_DIR)')"
build:
v -path "$$(realpath $$PWD/../)|@vlib|@vmodules" \
-prod -skip-unused -parallel-cc -cflags -static -cflags -s -d no_segfault_handler \
cmd/dataunit.v -o dataunit
clean:
rm -r $(DOC_DIR) || true
rm dataunit || true

View File

@@ -1,9 +1,9 @@
## Data size units converter # Data Unit Converter
Installation: Installation:
``` ```
v install --git https://github.com/gechandesu/dataunits v install https://github.com/gechandesu/dataunits
``` ```
Example: Example:
@@ -12,13 +12,16 @@ Example:
import dataunits import dataunits
fn main() { fn main() {
// convert via convert fn
kilobytes := dataunits.convert(500, dataunits.mbit, dataunits.kb) kilobytes := dataunits.convert(500, dataunits.mbit, dataunits.kb)
println(kilobytes) // 62500.0 println(kilobytes) // 62500.0
// convert via DataSize method (the arguments order matters)
mebibytes := (dataunits.gib * 15).mib() mebibytes := (dataunits.gib * 15).mib()
println(mebibytes) // 15360.0 println(mebibytes) // 15360.0
bytes := dataunits.DataSize(2000 * dataunits.gib).bytes() // convert via DataSize method with explicit type cast
bytes := dataunits.DataSize(2000 * dataunits.gib).byte()
println(bytes) // 2.147483648e+12 == 2147483648000 println(bytes) // 2.147483648e+12 == 2147483648000
} }
``` ```

View File

@@ -23,17 +23,12 @@
// For more information, please refer to <https://unlicense.org/> // For more information, please refer to <https://unlicense.org/>
/*
dataunit - a simple CLI tool for data units convertion.
*/
module main module main
import os import os
import flag import flag
import dataunits import dataunits
@[name: 'dataunit']
struct FlagConfig { struct FlagConfig {
help bool help bool
from string @[short: f] from string @[short: f]
@@ -55,7 +50,7 @@ fn main() {
} }
if flags.help { if flags.help {
println('convert the value between data size units.') println('convert the value between data size units.')
println('usage: dataunit -f <unit> -t <unit> <value>') println('usage: datasize -f <unit> -t <unit> <value>')
println('options:') println('options:')
println(' -help print this help message and exit') println(' -help print this help message and exit')
println(' -f, -from source data unit') println(' -f, -from source data unit')
@@ -70,11 +65,11 @@ fn main() {
eprintln('no value passed, see -help for info') eprintln('no value passed, see -help for info')
exit(2) exit(2)
} }
src := dataunits.from_string(flags.from, ci: true) or { src := dataunits.from_string(flags.from, case_insensitive: true) or {
eprintln('invalid source unit: ${err}') eprintln('invalid source unit: ${err}')
exit(1) exit(1)
} }
dst := dataunits.from_string(flags.to, ci: true) or { dst := dataunits.from_string(flags.to, case_insensitive: true) or {
eprintln('invalid destination unit: ${err}') eprintln('invalid destination unit: ${err}')
exit(1) exit(1)
} }

View File

@@ -1,10 +1,10 @@
// This is free and unencumbered software released into the public domain. // This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or // Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled // distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any // binary, for any purpose, commercial or non-commercial, and by any
// means. // means.
//
// In jurisdictions that recognize copyright laws, the author or authors // In jurisdictions that recognize copyright laws, the author or authors
// of this software dedicate any and all copyright interest in the // of this software dedicate any and all copyright interest in the
// software to the public domain. We make this dedication for the benefit // 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 // successors. We intend this dedication to be an overt act of
// relinquishment in perpetuity of all present and future rights to this // relinquishment in perpetuity of all present and future rights to this
// software under copyright law. // software under copyright law.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
@@ -20,13 +20,11 @@
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // 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 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
//
// For more information, please refer to <https://unlicense.org/> // For more information, please refer to <https://unlicense.org/>
module dataunits module dataunits
import maps
pub type DataSize = f64 pub type DataSize = f64
pub fn (d DataSize) bit() f64 { pub fn (d DataSize) bit() f64 {
@@ -37,8 +35,8 @@ pub fn (d DataSize) nibble() f64 {
return f64(d / nibble) return f64(d / nibble)
} }
pub fn (d DataSize) bytes() f64 { pub fn (d DataSize) byte() f64 {
return f64(d / bytes) return f64(d / byte)
} }
pub fn (d DataSize) kb() f64 { pub fn (d DataSize) kb() f64 {
@@ -171,9 +169,9 @@ pub fn (d DataSize) yibit() f64 {
pub const bit = DataSize(1) pub const bit = DataSize(1)
pub const nibble = bit * 4 pub const nibble = bit * 4
pub const bytes = bit * 8 pub const byte = bit * 8
pub const kb = bytes * 1000 pub const kb = byte * 1000
pub const mb = kb * 1000 pub const mb = kb * 1000
pub const gb = mb * 1000 pub const gb = mb * 1000
pub const tb = gb * 1000 pub const tb = gb * 1000
@@ -182,7 +180,7 @@ pub const eb = pb * 1000
pub const zb = eb * 1000 pub const zb = eb * 1000
pub const yb = zb * 1000 pub const yb = zb * 1000
pub const kib = bytes * 1024 pub const kib = byte * 1024
pub const mib = kib * 1024 pub const mib = kib * 1024
pub const gib = mib * 1024 pub const gib = mib * 1024
pub const tib = gib * 1024 pub const tib = gib * 1024
@@ -209,10 +207,10 @@ pub const eibit = pibit * 1024
pub const zibit = eibit * 1024 pub const zibit = eibit * 1024
pub const yibit = zibit * 1024 pub const yibit = zibit * 1024
const units = { const str_unit = {
'bit': bit 'bit': bit
'nibble': nibble 'nibble': nibble
'bytes': bytes 'byte': byte
'kB': kb 'kB': kb
'MB': mb 'MB': mb
'GB': gb 'GB': gb
@@ -247,8 +245,46 @@ const units = {
'Yibit': yibit '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 = { pub const prefixes = {
// Metric size (1000^N) // Metric size (N * 1000)
'kilo': 'k' 'kilo': 'k'
'mega': 'M' 'mega': 'M'
'giga': 'G' 'giga': 'G'
@@ -257,7 +293,7 @@ pub const prefixes = {
'exa': 'E' 'exa': 'E'
'zetta': 'Z' 'zetta': 'Z'
'yotta': 'Y' 'yotta': 'Y'
// Binary size (1024^N) // Binary size (N * 1024)
'kibi': 'Ki' 'kibi': 'Ki'
'mebi': 'Mi' 'mebi': 'Mi'
'gibi': 'Gi' 'gibi': 'Gi'
@@ -268,9 +304,19 @@ pub const prefixes = {
'yobi': 'Yi' '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. // convert returns the value converted between the *from* and *to* units.
// Example: // Example:
// ``` // ```v
// assert dataunits.convert(500, dataunits.mbit, dataunits.kb) == 62500 // assert dataunits.convert(500, dataunits.mbit, dataunits.kb) == 62500
// ```` // ````
pub fn convert(value f64, from DataSize, to DataSize) f64 { pub fn convert(value f64, from DataSize, to DataSize) f64 {
@@ -281,92 +327,93 @@ pub fn convert(value f64, from DataSize, to DataSize) f64 {
} }
// from_string parses input and returns the actual DataSize. // from_string parses input and returns the actual DataSize.
// Note: Case insensitivity makes unit abbreviations such as `Mb` (megabit) and `MB` (megabyte) // Note: Case insensitivity makes unit abbreviations such as 'Mb' (megabit) and 'MB' (megabyte)
// ambiguous. Use `bit` suffix for bit units. The `b` suffix will be accepted as byte unit. // ambiguous. Use 'bit' suffix for values in bits. The 'b' suffix will be accepted as byte unit.
// Example: // Example:
// ``` // ```v
// assert dataunits.from_string('GiB')! == dataunits.gib // assert dataunits.from_string('GiB')! == dataunits.gib
// assert dataunits.from_string('M')! == dataunits.mib // assert dataunits.from_string('M')! == dataunits.mb
// assert dataunits.from_string('M', bits: true, metric: true)! == dataunits.mbit // assert dataunits.from_string('M', in_bits: true)! == dataunits.mbit
// assert dataunits.from_string('ZeTtAbYtEs', ci: true)! == dataunits.zb // assert dataunits.from_string('ZeTtAbYtEs', case_insensitive: true)! == dataunits.zb
// ``` // ```
pub fn from_string(input string, params ParseParams) !DataSize { pub fn from_string(input string, params ParseParams) !DataSize {
if !input.is_pure_ascii() { 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.ci { if params.case_insensitive {
for key, value in units { for key, value in str_unit {
if key.to_lower_ascii() == unit { if key.to_lower_ascii() == unit.to_lower_ascii() {
return value 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 := '' mut unit := ''
match true { match true {
input.to_lower_ascii() in ['byte', 'bytes'] { input.to_lower_ascii() in ['byte', 'bytes'] {
return 'bytes' return 'byte'
} }
input.to_lower_ascii() in ['bit', 'bits'] { input.to_lower_ascii() in ['bit', 'bits'] {
return 'bit' return 'bit'
} }
input.len == 1 { input.len == 1 {
if params.metric { if params.binary_size {
unit = input
} else {
unit = input.to_upper_ascii() + 'i' unit = input.to_upper_ascii() + 'i'
} else {
unit = input
} }
if params.bits { if params.in_bits {
unit += 'bit' unit += 'bit'
} else { } else {
unit += 'B' unit += 'B'
} }
return unit return unit
} }
input.len == 2 && input[1] == u8(`b`) && params.ci == false { input.len == 2 && input[1] == u8(`i`) {
if input[0] != u8(`k`) { if params.in_bits {
return input[..1] + 'bit' return input + 'bit'
} }
return input[..1].to_upper_ascii() + 'bit' return input + 'B'
}
input.len == 3 && input.ends_with('ib') && params.case_insensitive == false {
// Mib -> Mibit
return input[..2] + 'bit'
}
input.len == 2 && input[1] == u8(`b`) && params.case_insensitive == false {
// Mb -> Mbit
return input[..1] + 'bit'
} }
else { else {
unit = input unit = input
} }
} }
if params.ci { if params.case_insensitive {
unit = unit.to_lower_ascii() unit = unit.to_lower_ascii()
} }
if unit.len == 5 && unit.ends_with('ibit') { if unit.len == 5 && unit.ends_with('ibit') {
// prevent Gibit --> Git transform // prevent Gibit --> Git transform
return unit return unit
} }
unit = unit.replace_each(maps.flat_map[string, string, string](prefixes, |k, v| [ unit = unit.all_before('s').replace_each(prefixes_array)
k,
v,
]))
unit = unit.replace_each(['bytes', 'B', 'byte', 'B']).replace_once('bits', 'bit')
return unit return unit
} }
@[params] @[params]
pub struct ParseParams { pub struct ParseParams {
pub: pub:
ci bool // if true parse string in case insensitive mode // if true parse string in case insensitive mode
bits bool // if true interpret single letter abbreviations as bit, otherwise as byte case_insensitive bool
metric bool // if ture apply single letter as metric prefix (power of ten), otherwise as binary // if true accept input such 'M', 'Gi' as bits, otherwise as bytes
in_bits bool
// if true accept single letter prefix as binary (power of two), otherwise as metric prefix
binary_size bool
} }
// to_string returns a string representation of data size unit in short form // to_string returns a string representation of data unit in short form e.g. kB, Mbit, GiB, etc.
// e.g. kB, Mbit, GiB, etc.
pub fn to_string(input DataSize) !string { pub fn to_string(input DataSize) !string {
for key, value in units { return unit_str[input] or { error('invalid input data unit') }
if value == input {
return key
}
}
return error('invalid input data size unit')
} }

36
examples/parse_units.v Normal file
View File

@@ -0,0 +1,36 @@
import os
import regex
import dataunits
struct Memory {
value f64
unit dataunits.DataSize
}
fn (m Memory) str() string {
return '${m.value} ${dataunits.to_string(m.unit) or { '' }}'
}
fn (m Memory) mib() f64 {
return dataunits.convert(m.value, m.unit, dataunits.mib)
}
fn Memory.from_string(s string) !Memory {
mut re := regex.regex_opt(r'^(\d+)([a-zA-Z]+)$')!
re.match_string(s)
if re.groups.len != 2 {
return error("unable to parse string '${s}'")
}
value := re.get_group_by_id(s, 0).f64()
unit := dataunits.from_string(re.get_group_by_id(s, 1))!
return Memory{value, unit}
}
fn main() {
mem := Memory.from_string(os.input('Enter memory value (e.g. 10Gi): ')) or {
eprintln('Error: ${err}')
exit(1)
}
println('Input: ${mem}')
println('Memory size: ${mem.mib()} MiB')
}

View File

@@ -1,31 +1,83 @@
import dataunits import dataunits
fn test_convert() { fn test_convert() {
assert (dataunits.nibble * 4).bytes() == 2 assert (dataunits.nibble * 4).byte() == 2
assert (dataunits.bit * 8).bit() == 8 assert (dataunits.bit * 8).bit() == 8
assert (dataunits.bit * 8).bytes() == 1 assert (dataunits.bit * 8).byte() == 1
assert (dataunits.gib * 10).mib() == 10240 assert (dataunits.gib * 10).mib() == 10240
assert (dataunits.gib * 5000).bytes() == i64(5368709120000) assert (dataunits.gib * 5000).byte() == f64(5368709120000)
assert (dataunits.mbit * 500).kb() == 62500 assert (dataunits.mbit * 500).kb() == 62500
assert dataunits.convert(500, dataunits.mbit, dataunits.kb) == 62500 assert dataunits.convert(500, dataunits.mbit, dataunits.kb) == 62500
assert dataunits.DataSize(4000 * dataunits.gib).bytes() == f64(4294967296000) assert dataunits.DataSize(4000 * dataunits.gib).byte() == f64(4294967296000)
} }
fn test_from_string() { fn test_from_string() {
assert dataunits.from_string('GiB')! == dataunits.gib assert dataunits.from_string('GiB')! == dataunits.gib
assert dataunits.from_string('M')! == dataunits.mib assert dataunits.from_string('M')! == dataunits.mb
assert dataunits.from_string('m', ci: true)! == dataunits.mib assert dataunits.from_string('m', case_insensitive: true)! == dataunits.mb
assert dataunits.from_string('M', bits: true, metric: true)! == dataunits.mbit assert dataunits.from_string('M', binary_size: true)! == dataunits.mib
assert dataunits.from_string('ZeTtAbYtEs', ci: true)! == dataunits.zb assert dataunits.from_string('M', in_bits: true)! == dataunits.mbit
assert dataunits.from_string('bytes')! == dataunits.bytes assert dataunits.from_string('ZeTtAbYtEs', case_insensitive: true)! == dataunits.zb
assert dataunits.from_string('byte')! == dataunits.bytes assert dataunits.from_string('bytes')! == dataunits.byte
assert dataunits.from_string('byte')! == dataunits.byte
assert dataunits.from_string('megabytes')! == dataunits.mb assert dataunits.from_string('megabytes')! == dataunits.mb
assert dataunits.from_string('megabyte')! == dataunits.mb assert dataunits.from_string('megabyte')! == dataunits.mb
assert dataunits.from_string('exbibit')! == dataunits.eibit assert dataunits.from_string('exbibit')! == dataunits.eibit
assert dataunits.from_string('Mb')! == dataunits.mbit assert dataunits.from_string('Mb')! == dataunits.mbit
assert dataunits.from_string('MB')! == dataunits.mb assert dataunits.from_string('MB')! == dataunits.mb
assert dataunits.from_string('Mb', ci: true)! == dataunits.mb assert dataunits.from_string('Mb', case_insensitive: true)! == dataunits.mb
assert dataunits.from_string('Gibit')! == dataunits.gibit assert dataunits.from_string('Gibit')! == dataunits.gibit
assert dataunits.from_string('gibit', ci: true)! == dataunits.gibit assert dataunits.from_string('gibit', case_insensitive: true)! == dataunits.gibit
assert dataunits.from_string('Gib', ci: true)! == dataunits.gib assert dataunits.from_string('gIBiT', case_insensitive: true)! == dataunits.gibit
assert dataunits.from_string('Gib', case_insensitive: true)! == dataunits.gib
assert dataunits.from_string('Gib')! == dataunits.gibit
assert dataunits.from_string('k')! == dataunits.kb
assert dataunits.from_string('kB')! == dataunits.kb
assert dataunits.from_string('kb')! == dataunits.kbit
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
}
} }

4
v.mod
View File

@@ -1,7 +1,7 @@
Module { Module {
name: 'dataunits' name: 'dataunits'
description: 'Data units converter' description: 'Data unit converter'
version: '0.0.1' version: '0.1.0'
license: 'Unlicense' license: 'Unlicense'
dependencies: [] dependencies: []
} }