Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add IsArray and IsPureArray checking config is an array #47

Merged
merged 1 commit into from
Jul 26, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]

### Added
- Add `(*Config).IsArray` and `(*Config).IsDict`. #44

### Changed

Expand Down
4 changes: 2 additions & 2 deletions getset.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ func convertErr(opts *options, v value, err error, to string) Error {
// of elements in list
func (c *Config) CountField(name string, opts ...Option) (int, error) {
if name == "" {
return len(c.fields.arr) + len(c.fields.fields), nil
return len(c.fields.array()) + len(c.fields.dict()), nil
}

if v, ok := c.fields.fields[name]; ok {
if v, ok := c.fields.get(name); ok {
return v.Len(makeOptions(opts))
}
return -1, raiseMissing(c, name)
Expand Down
5 changes: 5 additions & 0 deletions getset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ func TestSetGetPrimitives(t *testing.T) {
c.SetFloat("float", -1, 2.3)
c.SetString("str", -1, "abc")

assert.True(t, c.IsDict())
assert.False(t, c.IsArray())

assert.True(t, c.HasField("bool"))
assert.True(t, c.HasField("int"))
assert.True(t, c.HasField("uint"))
Expand Down Expand Up @@ -127,6 +130,8 @@ func TestSetGetArray(t *testing.T) {

a, err := c.Child("a", -1)
assert.NoError(t, err)
assert.True(t, a.IsArray())
assert.False(t, a.IsDict())

l, err = a.CountField("")
assert.NoError(t, err)
Expand Down
12 changes: 6 additions & 6 deletions merge.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,27 @@ func (c *Config) Merge(from interface{}, options ...Option) error {
}

func mergeConfig(opts *options, to, from *Config) Error {
for k, v := range from.fields.fields {
for k, v := range from.fields.dict() {
ctx := context{
parent: cfgSub{to},
field: k,
}

old, ok := to.fields.fields[k]
old, ok := to.fields.get(k)
if !ok {
to.fields.fields[k] = v.cpy(ctx)
to.fields.set(k, v.cpy(ctx))
continue
}

subOld, err := old.toConfig(opts)
if err != nil {
to.fields.fields[k] = v.cpy(ctx)
to.fields.set(k, v.cpy(ctx))
continue
}

subFrom, err := v.toConfig(opts)
if err != nil {
to.fields.fields[k] = v.cpy(ctx)
to.fields.set(k, v.cpy(ctx))
continue
}

Expand Down Expand Up @@ -223,7 +223,7 @@ func normalizeArray(
out = append(out, tmp)
}

cfg.fields.arr = out
cfg.fields.a = out
return val, nil
}

Expand Down
19 changes: 7 additions & 12 deletions path.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ func (n namedField) GetValue(opts *options, elem value) (value, Error) {
return nil, raiseExpectedObject(opts, elem)
}

return cfg.fields.fields[n.name], nil
v, _ := cfg.fields.get(n.name)
return v, nil
}

func (i idxField) GetValue(opts *options, elem value) (value, Error) {
Expand All @@ -136,11 +137,11 @@ func (i idxField) GetValue(opts *options, elem value) (value, Error) {
return nil, raiseExpectedObject(opts, elem)
}

if i.i >= len(cfg.fields.arr) {
arr := cfg.fields.array()
if i.i >= len(arr) {
return nil, raiseMissing(cfg, i.String())
}

return cfg.fields.arr[i.i], nil
return arr[i.i], nil
}

func (p cfgPath) SetValue(cfg *Config, opt *options, val value) Error {
Expand Down Expand Up @@ -188,7 +189,7 @@ func (n namedField) SetValue(opts *options, elem value, v value) Error {
return raiseExpectedObject(opts, elem)
}

sub.c.fields.fields[n.name] = v
sub.c.fields.set(n.name, v)
v.SetContext(context{parent: elem, field: n.name})
return nil
}
Expand All @@ -199,13 +200,7 @@ func (i idxField) SetValue(opts *options, elem value, v value) Error {
return raiseExpectedObject(opts, elem)
}

if i.i >= len(sub.c.fields.arr) {
tmp := make([]value, i.i+1)
copy(tmp, sub.c.fields.arr)
sub.c.fields.arr = tmp
}

sub.c.fields.arr[i.i] = v
sub.c.fields.setAt(i.i, v)
v.SetContext(context{parent: elem, field: i.String()})
return nil
}
9 changes: 5 additions & 4 deletions reify.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,15 @@ func reifyMap(opts *options, to reflect.Value, from *Config) Error {
return raiseKeyInvalidTypeUnpack(to.Type(), from)
}

if len(from.fields.fields) == 0 {
fields := from.fields.dict()
if len(fields) == 0 {
return nil
}

if to.IsNil() {
to.Set(reflect.MakeMap(to.Type()))
}
for k, value := range from.fields.fields {
for k, value := range fields {
key := reflect.ValueOf(k)

old := to.MapIndex(key)
Expand Down Expand Up @@ -398,7 +399,7 @@ func reifyDoArray(

func castArr(opts *options, v value) ([]value, Error) {
if sub, ok := v.(cfgSub); ok {
return sub.c.fields.arr, nil
return sub.c.fields.array(), nil
}
if ref, ok := v.(*cfgRef); ok {
unrefed, err := ref.resolve(opts)
Expand All @@ -407,7 +408,7 @@ func castArr(opts *options, v value) ([]value, Error) {
}

if sub, ok := unrefed.(cfgSub); ok {
return sub.c.fields.arr, nil
return sub.c.fields.array(), nil
}
}

Expand Down
33 changes: 19 additions & 14 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ func (cfgSub) toFloat(*options) (float64, error) { return 0, ErrTypeMismatch
func (c cfgSub) toConfig(*options) (*Config, error) { return c.c, nil }

func (c cfgSub) Len(*options) (int, error) {
arr := c.c.fields.arr
arr := c.c.fields.array()
if arr != nil {
return len(arr), nil
}
Expand All @@ -282,18 +282,23 @@ func (c cfgSub) cpy(ctx context) value {
c: &Config{ctx: ctx, metadata: c.c.metadata},
}

fields := &fields{
fields: map[string]value{},
arr: make([]value, len(c.c.fields.arr)),
}
dict := c.c.fields.dict()
arr := c.c.fields.array()
fields := &fields{}

for name, f := range c.c.fields.fields {
for name, f := range dict {
ctx := f.Context()
fields.fields[name] = f.cpy(context{field: ctx.field, parent: newC})
v := f.cpy(context{field: ctx.field, parent: newC})
fields.set(name, v)
}
for i, f := range c.c.fields.arr {
ctx := f.Context()
fields.arr[i] = f.cpy(context{field: ctx.field, parent: newC})

if arr != nil {
fields.a = make([]value, len(arr))
for i, f := range arr {
ctx := f.Context()
v := f.cpy(context{field: ctx.field, parent: newC})
fields.setAt(i, v)
}
}

newC.c.fields = fields
Expand All @@ -312,15 +317,15 @@ func (c cfgSub) SetContext(ctx context) {
}

func (c cfgSub) reify(opts *options) (interface{}, error) {
fields := c.c.fields.fields
arr := c.c.fields.arr
fields := c.c.fields.dict()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

c.c. :-)

arr := c.c.fields.array()

switch {
case len(fields) == 0 && len(arr) == 0:
return nil, nil
case len(fields) > 0 && len(arr) == 0:
m := make(map[string]interface{})
for k, v := range c.c.fields.fields {
for k, v := range fields {
var err error
if m[k], err = v.reify(opts); err != nil {
return nil, err
Expand All @@ -338,7 +343,7 @@ func (c cfgSub) reify(opts *options) (interface{}, error) {
return m, nil
default:
m := make(map[string]interface{})
for k, v := range c.c.fields.fields {
for k, v := range fields {
var err error
if m[k], err = v.reify(opts); err != nil {
return nil, err
Expand Down
54 changes: 49 additions & 5 deletions ucfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ type fieldOptions struct {
}

type fields struct {
fields map[string]value
arr []value
d map[string]value
a []value
}

// Meta holds additional meta data per config value
Expand Down Expand Up @@ -54,7 +54,7 @@ var (

func New() *Config {
return &Config{
fields: &fields{map[string]value{}, nil},
fields: &fields{nil, nil},
}
}

Expand All @@ -66,16 +66,24 @@ func NewFrom(from interface{}, opts ...Option) (*Config, error) {
return c, nil
}

func (c *Config) IsDict() bool {
return c.fields.dict() != nil
}

func (c *Config) IsArray() bool {
return c.fields.array() != nil
}

func (c *Config) GetFields() []string {
var names []string
for k := range c.fields.fields {
for k := range c.fields.dict() {
names = append(names, k)
}
return names
}

func (c *Config) HasField(name string) bool {
_, ok := c.fields.fields[name]
_, ok := c.fields.get(name)
return ok
}

Expand All @@ -102,3 +110,39 @@ func (c *Config) Parent() *Config {
}
}
}

func (f *fields) get(name string) (value, bool) {
if f.d == nil {
return nil, false
}
v, found := f.d[name]
return v, found
}

func (f *fields) dict() map[string]value {
return f.d
}

func (f *fields) array() []value {
return f.a
}

func (f *fields) set(name string, v value) {
if f.d == nil {
f.d = map[string]value{}
}
f.d[name] = v
}

func (f *fields) add(v value) {
f.a = append(f.a, v)
}

func (f *fields) setAt(idx int, v value) {
if idx >= len(f.a) {
tmp := make([]value, idx+1)
copy(tmp, f.a)
f.a = tmp
}
f.a[idx] = v
}