Skip to content

Commit

Permalink
feat: Add unmarshal_to to modify an existing object
Browse files Browse the repository at this point in the history
  • Loading branch information
prantlf committed Aug 15, 2023
1 parent e421b4a commit 3aad9ec
Show file tree
Hide file tree
Showing 16 changed files with 264 additions and 32 deletions.
27 changes: 24 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,33 @@ on:
pull_request:

jobs:
test:

linux:
runs-on: ubuntu-latest
steps:
- name: Checkout Sources
uses: actions/checkout@v3
- name: Setup V
uses: prantlf/setup-v-action@v1
- name: Test
run: v test .
- name: Build and Test
run: make

macos:
runs-on: macos-latest
steps:
- name: Checkout Sources
uses: actions/checkout@v3
- name: Setup V
uses: prantlf/setup-v-action@v1
- name: Build and Test
run: make

windows:
runs-on: windows-latest
steps:
- name: Checkout Sources
uses: actions/checkout@v3
- name: Setup V
uses: prantlf/setup-v-action@v1
- name: Build
run: make
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
.DS_Store
unmarshal_test
unmarshal_test.dSYM
*_test
*.dSYM
7 changes: 3 additions & 4 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
{
"files.exclude": {
"**/.git": true,
"**/.DS_Store": true
},
"search.exclude": {
"**/node_modules": true
"**/.DS_Store": true,
"**/*_test": true,
"**/*.dSYM": true
}
}
14 changes: 14 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
all: check test

check:
v fmt -w .
v vet .

test:
NO_COLOR=1 v test .

clean:
rm -rf src/*_test src/*.dSYM

version:
npx conventional-changelog-cli -p angular -i CHANGELOG.md -s
45 changes: 37 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,20 +61,20 @@ Parses an input string in the YAML format to an `Any` value. See [jany] for more
input := r'
answer: 42
'
any := parse_text(input)
any := parse_text(input)!
```

### parse_file(path string) !Any

Loads the contents of a text file in the YAML format and parses it to an `Any` value. See [jany] for more information about the `Any` type.

```go
any := parse_file('config.yaml')
any := parse_file('config.yaml')!
```

### unmarshal_text[T](input string, opts UnmarshalOpts) !T
### unmarshal_text[T](input string, opts &UnmarshalOpts) !T

Unmarshals an input string in the YAML format to an instance of `T`. See [jany] for more information about the `Any` type and the `UnmarshalOpts` struct.
Unmarshals an input string in the YAML format to a new instance of `T`. See [jany] for more information about the `Any` type and the `UnmarshalOpts` struct.

```go
struct Config {
Expand All @@ -84,19 +84,48 @@ struct Config {
input := r'
answer: 42
'
config := unmarshal_text[Config](input)
config := unmarshal_text[Config](input, UnmarshalOpts{})!
```

### unmarshal_file[T](path string, opts UnmarshalOpts) !T
### unmarshal_text_to[T](input string, mut obj T, opts &UnmarshalOpts) !

Loads the contents of a text file in the YAML format and unmarshals it to an instance of `T`. See [jany] for more information about the `Any` type and the `UnmarshalOpts` struct.
Unmarshals an input string in the YAML format to an existing instance of `T`. See [jany] for more information about the `Any` type and the `UnmarshalOpts` struct.

```go
struct Config {
answer int
}

config := unmarshal_file[Config]('config.yaml')
input := r'
answer: 42
'
mut config := Config{}
config := unmarshal_text_to(input, mut config, UnmarshalOpts{})!
```

### unmarshal_file[T](path string, opts &UnmarshalOpts) !T

Loads the contents of a text file in the YAML format and unmarshals it to a new instance of `T`. See [jany] for more information about the `Any` type and the `UnmarshalOpts` struct.

```go
struct Config {
answer int
}

config := unmarshal_file[Config]('config.yaml', UnmarshalOpts{})!
```

### unmarshal_file_to[T](path string, mut obj T, opts UnmarshalOpts) !

Loads the contents of a text file in the YAML format and unmarshals it to an existing instance of `T`. See [jany] for more information about the `Any` type and the `UnmarshalOpts` struct.

```go
struct Config {
answer int
}

mut config := Config{}
config := unmarshal_file_to('config.yaml', mut config, UnmarshalOpts{})!
```

## Performance
Expand Down
76 changes: 76 additions & 0 deletions bench/bench-float.vsh
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#!/usr/bin/env -S v -prod run

import benchmark
import rand
import strconv
import time

fn C.strtod(charptr, &charptr) f64
fn C.strtol(charptr, &charptr, int) int

fn strtod(s string) !f64 {
end := unsafe { nil }
C.errno = 0
n := C.strtod(s.str, &end)
if C.errno != 0 {
return error('out of range')
}
if unsafe { s.str + s.len != end } {
return error('not a number')
}
return n
}

fn strtol(s string) !int {
end := unsafe { nil }
C.errno = 0
n := C.strtol(s.str, &end, 10)
if C.errno != 0 {
return error('out of range')
}
if unsafe { s.str + s.len != end } {
return error('not a number')
}
return n
}

fn str_to_num(s string) !f64 {
if s.contains_any('.eE') {
return strtod(s)!
}
return f64(strconv.atoi(s) or { strtod(s)! })
}

rand.seed([u32(time.now().unix), 0])

sample_size := 1500
mut strings := []string{}
for _ in 0 .. sample_size {
n := rand.int_in_range(0, 10000000) or { 0 }
strings << '${n}'
d := rand.int_in_range(0, 10000000) or { 0 }
f := rand.int_in_range(0, 10000000) or { 0 }
strings << '${d}.${f}'
}

mut b := benchmark.start()

for s in strings {
_ := strconv.atof64(s)!
}
b.measure('parsing floats')

for s in strings {
_ := strtod(s)!
}
b.measure('parsing floats with C')

for s in strings {
_ := f64(strconv.atoi(s) or { strtod(s)! })
}
b.measure('parsing integers and floats')

for s in strings {
_ := str_to_num(s)!
}
b.measure('parsing integers and floats with check')
80 changes: 80 additions & 0 deletions bench/bench-int.vsh
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#!/usr/bin/env -S v -prod run

import benchmark
import rand
import strconv
import time

fn C.strtod(charptr, &charptr) f64
fn C.strtol(charptr, &charptr, int) int

fn strtod(s string) !f64 {
C.errno = 0
n := C.strtod(s.str, 0)
if C.errno != 0 {
return error('range overflow')
}
return n
}

fn strtol(s string) !int {
C.errno = 0
n := C.strtol(s.str, 0, 10)
if C.errno != 0 {
return error('range overflow')
}
return n
}

rand.seed([u32(time.now().unix), 0])

sample_size := 3000
mut strings := []string{}
for _ in 0 .. sample_size {
n := rand.int_in_range(0, 10000000) or { 0 }
strings << '${n}'
}

mut b := benchmark.start()
for s in strings {
_ := f64(strconv.atoi(s)!)
}
b.measure('parsing integers')

for s in strings {
C.errno = 0
_ := f64(C.strtol(s.str, 0, 10))
if C.errno != 0 {
panic('range overflow')
}
}
b.measure('parsing integers with C')

for s in strings {
_ := f64(strtol(s)!)
}
b.measure('parsing integers with C wrapped')

for s in strings {
_ := strconv.atof64(s)!
}
b.measure('parsing floats')

for s in strings {
_ := strconv.atof_quick(s)
}
b.measure('parsing floats quickly')

for s in strings {
C.errno = 0
_ := C.strtod(s.str, 0)
if C.errno != 0 {
panic('range overflow')
}
}
b.measure('parsing floats with C')

for s in strings {
_ := strtod(s)!
}
b.measure('parsing floats with C wrapped')
4 changes: 2 additions & 2 deletions parse_bench.vsh → bench/parse_bench.vsh
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import prantlf.yaml

const repeats = 20

json_in := os.read_file('vlang.io.har.json')!
yaml_in := os.read_file('vlang.io.har.yaml')!
json_in := os.read_file('src/testdata/vlang.io.har.json')!
yaml_in := os.read_file('src/testdata/vlang.io.har.yaml')!

opts := json.ParseOpts{}

Expand Down
1 change: 1 addition & 0 deletions errors.v → src/errors.v
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module yaml

import prantlf.jany { Any }

[noinit]
pub struct YamlError {
Error
message string
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
25 changes: 25 additions & 0 deletions src/unmarshal.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module yaml

import prantlf.jany { UnmarshalOpts }

pub fn unmarshal_text[T](input string, opts &UnmarshalOpts) !T {
mut obj := T{}
unmarshal_text_to[T](input, mut obj, opts)!
return obj
}

pub fn unmarshal_text_to[T](input string, mut obj T, opts &UnmarshalOpts) ! {
a := parse_text(input)!
jany.unmarshal_to[T](a, mut obj, opts)!
}

pub fn unmarshal_file[T](path string, opts &UnmarshalOpts) !T {
mut obj := T{}
unmarshal_file_to[T](path, mut obj, opts)!
return obj
}

pub fn unmarshal_file_to[T](path string, mut obj T, opts &UnmarshalOpts) ! {
a := parse_file(path)!
jany.unmarshal_to[T](a, mut obj, opts)!
}
File renamed without changes.
File renamed without changes.
13 changes: 0 additions & 13 deletions unmarshal.v

This file was deleted.

0 comments on commit 3aad9ec

Please sign in to comment.