Skip to content

Commit

Permalink
Adding support for maps (#5)
Browse files Browse the repository at this point in the history
Works with any key or value type and provides access to these types.

Added keys() and get_key() respectively.
  • Loading branch information
elliotchance authored Jul 24, 2021
1 parent 459c0f3 commit 277c379
Show file tree
Hide file tree
Showing 6 changed files with 303 additions and 60 deletions.
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ avoided.
- [Values](#values)
- [Types](#types)
- [Arrays](#arrays)
- [Maps](#maps)

Installation
------------
Expand Down Expand Up @@ -93,3 +94,29 @@ fn main() {
println(v.get_index(5)) // V panic: array index 5 is out of bounds (len = 3)
}
```

Maps
----

```v
import elliotchance.reflect
fn main() {
mut m := map[string]int{}
m['a'] = 5
m['b'] = 7
m['c'] = 9
v := reflect.map_of(m)
println(v.typ) // "map[string]int"
println(v.typ.kind) // "map"
println(v.typ.key.kind) // "string"
println(v.typ.elem.kind) // "int"
println(v.len()) // 3
println(v.keys()) // ['a', 'b', 'c']
println(v.get_key(reflect.value_of('b')).get_int()) // 7
println(v.get_key(reflect.value_of('d'))) // V panic: key not found: d
println(v.get_key(reflect.value_of(123))) // V panic: value must be string but is int
}
```
2 changes: 2 additions & 0 deletions kind.v
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub enum Kind {
is_f32
is_f64
is_array
is_map
}

pub fn (k Kind) str() string {
Expand All @@ -36,5 +37,6 @@ pub fn (k Kind) str() string {
.is_f32 { 'f32' }
.is_f64 { 'f64' }
.is_array { 'array' }
.is_map { 'map' }
}
}
23 changes: 21 additions & 2 deletions type.v
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@ module reflect
pub struct Type {
pub:
kind Kind
// elem only applies for arrays.
// elem is the element type for arrays and the value type for maps.
elem &Type
// key is only used for describing the map key type.
key &Type
}

pub fn (t Type) str() string {
match t.kind {
.is_array {
return '[]' + (*t.elem).str()
return '[]${*t.elem}'
}
.is_map {
return 'map[${*t.key}]${*t.elem}'
}
else {
return t.kind.str()
Expand All @@ -24,6 +29,7 @@ pub fn none_type() &Type {
return &Type{
kind: Kind.is_none
elem: 0
key: 0
}
}

Expand All @@ -34,6 +40,18 @@ pub fn parse_type(t string) ?Type {
return Type{
kind: Kind.is_array
elem: &elem
key: none_type()
}
}

if t.starts_with('map[') {
parts := t[4..].split(']')
key := parse_type(parts[0]) ?
elem := parse_type(parts[1]) ?
return Type{
kind: Kind.is_map
elem: &elem
key: &key
}
}

Expand All @@ -55,5 +73,6 @@ pub fn parse_type(t string) ?Type {
else { Kind.is_none }
}
elem: none_type()
key: none_type()
}
}
42 changes: 21 additions & 21 deletions type_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,35 @@ struct ParseTypeTest {
typ string
expected_kind Kind
expected_elem Type
expected_key Type
}

fn test_parse_type() ? {
tests := [
ParseTypeTest{'bool', Kind.is_bool, none_type()},
ParseTypeTest{'string', Kind.is_string, none_type()},
ParseTypeTest{'i8', Kind.is_i8, none_type()},
ParseTypeTest{'i16', Kind.is_i16, none_type()},
ParseTypeTest{'int', Kind.is_int, none_type()},
ParseTypeTest{'i64', Kind.is_i64, none_type()},
ParseTypeTest{'byte', Kind.is_byte, none_type()},
ParseTypeTest{'u16', Kind.is_u16, none_type()},
ParseTypeTest{'u32', Kind.is_u32, none_type()},
ParseTypeTest{'u64', Kind.is_u64, none_type()},
ParseTypeTest{'rune', Kind.is_rune, none_type()},
ParseTypeTest{'f32', Kind.is_f32, none_type()},
ParseTypeTest{'f64', Kind.is_f64, none_type()},
ParseTypeTest{'[]int', Kind.is_array, &Type{
kind: Kind.is_int
elem: none_type()
}},
ParseTypeTest{'[]f64', Kind.is_array, &Type{
kind: Kind.is_f64
elem: none_type()
}},
ParseTypeTest{'bool', Kind.is_bool, none_type(), none_type()},
ParseTypeTest{'string', Kind.is_string, none_type(), none_type()},
ParseTypeTest{'i8', Kind.is_i8, none_type(), none_type()},
ParseTypeTest{'i16', Kind.is_i16, none_type(), none_type()},
ParseTypeTest{'int', Kind.is_int, none_type(), none_type()},
ParseTypeTest{'i64', Kind.is_i64, none_type(), none_type()},
ParseTypeTest{'byte', Kind.is_byte, none_type(), none_type()},
ParseTypeTest{'u16', Kind.is_u16, none_type(), none_type()},
ParseTypeTest{'u32', Kind.is_u32, none_type(), none_type()},
ParseTypeTest{'u64', Kind.is_u64, none_type(), none_type()},
ParseTypeTest{'rune', Kind.is_rune, none_type(), none_type()},
ParseTypeTest{'f32', Kind.is_f32, none_type(), none_type()},
ParseTypeTest{'f64', Kind.is_f64, none_type(), none_type()},
ParseTypeTest{'[]int', Kind.is_array, &Type{Kind.is_int, none_type(), none_type()}, none_type()},
ParseTypeTest{'[]f64', Kind.is_array, &Type{Kind.is_f64, none_type(), none_type()}, none_type()},
ParseTypeTest{'map[string]int', Kind.is_map, &Type{Kind.is_int, none_type(), none_type()}, &Type{Kind.is_string, none_type(), none_type()}},
ParseTypeTest{'map[f64]string', Kind.is_map, &Type{Kind.is_string, none_type(), none_type()}, &Type{Kind.is_f64, none_type(), none_type()}},
]
for test in tests {
println(test.typ)
typ := parse_type(test.typ) ?
assert typ.kind == test.expected_kind
assert (*typ.elem).str() == test.expected_elem.str()
assert (*typ.key).str() == test.expected_key.str()
assert typ.str() == test.typ
}
}
Loading

0 comments on commit 277c379

Please sign in to comment.