aboutsummaryrefslogtreecommitdiff
path: root/v_windows/v/vlib/x/json2/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'v_windows/v/vlib/x/json2/README.md')
-rw-r--r--v_windows/v/vlib/x/json2/README.md175
1 files changed, 175 insertions, 0 deletions
diff --git a/v_windows/v/vlib/x/json2/README.md b/v_windows/v/vlib/x/json2/README.md
new file mode 100644
index 0000000..fcefbff
--- /dev/null
+++ b/v_windows/v/vlib/x/json2/README.md
@@ -0,0 +1,175 @@
+> The name `json2` was chosen to avoid any unwanted potential conflicts with the
+> existing codegen tailored for the main `json` module which is powered by CJSON.
+
+`x.json2` is an experimental JSON parser written from scratch on V.
+
+## Usage
+```v oksyntax
+import x.json2
+import net.http
+
+fn main() {
+ // Decoding
+ resp := http.get('https://example.com') ?
+
+ // raw decode
+ raw_person := json2.raw_decode(resp.text) ?
+
+ // Casting `Any` type / Navigating
+ person := raw_person.as_map()
+ name := person['name'].str() // Bob
+ age := person['age'].int() // 19
+ pi := person['pi'].f64() // 3.14....
+
+ // Constructing an `Any` type
+ mut me := map[string]json2.Any{}
+ me['name'] = 'Bob'
+ me['age'] = 18
+
+ mut arr := []json2.Any{}
+ arr << 'rock'
+ arr << 'papers'
+ arr << json2.null
+ arr << 12
+
+ me['interests'] = arr
+
+ mut pets := map[string]json2.Any{}
+ pets['Sam'] = 'Maltese Shitzu'
+ me['pets'] = pets
+
+ // Stringify to JSON
+ println(me.str())
+ //{
+ // "name":"Bob",
+ // "age":18,
+ // "interests":["rock","papers","scissors",null,12],
+ // "pets":{"Sam":"Maltese"}
+ //}
+
+ // Encode a struct/type to JSON
+ encoded_json := json2.encode<Person>(person2)
+}
+```
+## Using `decode<T>` and `encode<T>`
+> Codegen for this feature is still WIP.
+> You need to manually define the methods before using the module to structs.
+
+In order to use the `decode<T>` and `encode<T>` function, you need to explicitly define
+two methods: `from_json` and `to_json`. `from_json` accepts a `json2.Any` argument
+and inside of it you need to map the fields you're going to put into the type.
+As for `to_json` method, you just need to map the values into `json2.Any`
+and turn it into a string.
+
+```v ignore
+struct Person {
+mut:
+ name string
+ age int = 20
+ pets []string
+}
+
+fn (mut p Person) from_json(f json2.Any) {
+ obj := f.as_map()
+ for k, v in obj {
+ match k {
+ 'name' { p.name = v.str() }
+ 'age' { p.age = v.int() }
+ 'pets' { p.pets = v.arr().map(it.str()) }
+ else {}
+ }
+ }
+}
+
+fn (p Person) to_json() string {
+ mut obj := map[string]json2.Any
+ obj['name'] = p.name
+ obj['age'] = p.age
+ obj['pets'] = p.pets
+ return obj.str()
+}
+
+fn main() {
+ resp := os.read_file('./person.json')?
+ person := json2.decode<Person>(resp)?
+ println(person) // Person{name: 'Bob', age: 28, pets: ['Floof']}
+ person_json := json2.encode<Person>(person)
+ println(person_json) // {"name": "Bob", "age": 28, "pets": ["Floof"]}
+}
+```
+
+## Using struct tags
+`x.json2` can access and use the struct field tags similar to the
+`json` module by using the comp-time `$for` for structs.
+
+```v ignore
+fn (mut p Person) from_json(f json2.Any) {
+ mp := an.as_map()
+ mut js_field_name := ''
+ $for field in Person.fields {
+ js_field_name = field.name
+
+ for attr in field.attrs {
+ if attr.starts_with('json:') {
+ js_field_name = attr.all_after('json:').trim_left(' ')
+ break
+ }
+ }
+
+ match field.name {
+ 'name' { p.name = mp[js_field_name].str() }
+ 'age' { u.age = mp[js_field_name].int() }
+ 'pets' { u.pets = mp[js_field_name].arr().map(it.str()) }
+ else {}
+ }
+ }
+}
+```
+
+### Null Values
+`x.json2` has a separate `null` type for differentiating an undefined value and a null value.
+To verify that the field you're accessing is a `null`, use `<typ> is json2.Null`.
+
+```v ignore
+fn (mut p Person) from_json(f json2.Any) {
+ obj := f.as_map()
+ if obj['age'] is json2.Null {
+ // use a default value
+ p.age = 10
+ }
+}
+```
+
+### Custom field names
+Aside from using struct tags, you can also just simply cast the base field into a map (`as_map()`)
+and access the field you wish to put into the struct/type.
+
+```v ignore
+fn (mut p Person) from_json(f json2.Any) {
+ obj := f.as_map()
+ p.name = obj['nickname'].str()
+}
+```
+
+```v oksyntax
+fn (mut p Person) to_json() string {
+ obj := f.as_map()
+ obj['nickname'] = p.name
+ return obj.str()
+}
+```
+
+### Undefined Values
+Getting undefined values has the same behavior as regular V types.
+If you're casting a base field into `map[string]json2.Any` and fetch an undefined entry/value,
+it simply returns empty. As for the `[]json2.Any`, it returns an index error.
+
+## Casting a value to an incompatible type
+`x.json2` provides methods for turning `Any` types into usable types.
+The following list shows the possible outputs when casting a value to an incompatible type.
+
+1. Casting non-array values as array (`arr()`) will return an array with the value as the content.
+2. Casting non-map values as map (`as_map()`) will return a map with the value as the content.
+3. Casting non-string values to string (`str()`) will return the
+JSON string representation of the value.
+4. Casting non-numeric values to int/float (`int()`/`i64()`/`f32()`/`f64()`) will return zero.