github.com/rajeev159/opa@v0.45.0/types/decode.go (about)

     1  // Copyright 2020 The OPA Authors.  All rights reserved.
     2  // Use of this source code is governed by an Apache2
     3  // license that can be found in the LICENSE file.
     4  
     5  package types
     6  
     7  import (
     8  	"encoding/json"
     9  	"fmt"
    10  
    11  	"github.com/open-policy-agent/opa/util"
    12  )
    13  
    14  const (
    15  	typeNull     = "null"
    16  	typeBoolean  = "boolean"
    17  	typeNumber   = "number"
    18  	typeString   = "string"
    19  	typeArray    = "array"
    20  	typeSet      = "set"
    21  	typeObject   = "object"
    22  	typeAny      = "any"
    23  	typeFunction = "function"
    24  )
    25  
    26  // Unmarshal deserializes bs and returns the resulting type.
    27  func Unmarshal(bs []byte) (result Type, err error) {
    28  
    29  	var hint rawtype
    30  
    31  	if err = util.UnmarshalJSON(bs, &hint); err == nil {
    32  		switch hint.Type {
    33  		case typeNull:
    34  			result = NewNull()
    35  		case typeBoolean:
    36  			result = NewBoolean()
    37  		case typeNumber:
    38  			result = NewNumber()
    39  		case typeString:
    40  			result = NewString()
    41  		case typeArray:
    42  			var arr rawarray
    43  			if err = util.UnmarshalJSON(bs, &arr); err == nil {
    44  				var err error
    45  				var static []Type
    46  				var dynamic Type
    47  				if static, err = unmarshalSlice(arr.Static); err != nil {
    48  					return nil, err
    49  				}
    50  				if len(arr.Dynamic) != 0 {
    51  					if dynamic, err = Unmarshal(arr.Dynamic); err != nil {
    52  						return nil, err
    53  					}
    54  				}
    55  				result = NewArray(static, dynamic)
    56  			}
    57  		case typeObject:
    58  			var obj rawobject
    59  			if err = util.UnmarshalJSON(bs, &obj); err == nil {
    60  				var err error
    61  				var static []*StaticProperty
    62  				var dynamic *DynamicProperty
    63  				if static, err = unmarshalStaticPropertySlice(obj.Static); err != nil {
    64  					return nil, err
    65  				}
    66  				if dynamic, err = unmarshalDynamicProperty(obj.Dynamic); err != nil {
    67  					return nil, err
    68  				}
    69  				result = NewObject(static, dynamic)
    70  			}
    71  		case typeSet:
    72  			var set rawset
    73  			if err = util.UnmarshalJSON(bs, &set); err == nil {
    74  				var of Type
    75  				if of, err = Unmarshal(set.Of); err == nil {
    76  					result = NewSet(of)
    77  				}
    78  			}
    79  		case typeAny:
    80  			var any rawunion
    81  			if err = util.UnmarshalJSON(bs, &any); err == nil {
    82  				var of []Type
    83  				if of, err = unmarshalSlice(any.Of); err == nil {
    84  					result = NewAny(of...)
    85  				}
    86  			}
    87  		case typeFunction:
    88  			var decl rawdecl
    89  			if err = util.UnmarshalJSON(bs, &decl); err == nil {
    90  				args, err := unmarshalSlice(decl.Args)
    91  				if err != nil {
    92  					return nil, err
    93  				}
    94  				var ret Type
    95  				if len(decl.Result) > 0 {
    96  					ret, err = Unmarshal(decl.Result)
    97  					if err != nil {
    98  						return nil, err
    99  					}
   100  				}
   101  				if len(decl.Variadic) > 0 {
   102  					varargs, err := Unmarshal(decl.Variadic)
   103  					if err != nil {
   104  						return nil, err
   105  					}
   106  					result = NewVariadicFunction(args, varargs, ret)
   107  				} else {
   108  					result = NewFunction(args, ret)
   109  				}
   110  			}
   111  		default:
   112  			err = fmt.Errorf("unsupported type '%v'", hint.Type)
   113  		}
   114  	}
   115  
   116  	return result, err
   117  }
   118  
   119  type rawtype struct {
   120  	Type string `json:"type"`
   121  }
   122  
   123  type rawarray struct {
   124  	Static  []json.RawMessage `json:"static"`
   125  	Dynamic json.RawMessage   `json:"dynamic"`
   126  }
   127  
   128  type rawobject struct {
   129  	Static  []rawstaticproperty `json:"static"`
   130  	Dynamic rawdynamicproperty  `json:"dynamic"`
   131  }
   132  
   133  type rawstaticproperty struct {
   134  	Key   interface{}     `json:"key"`
   135  	Value json.RawMessage `json:"value"`
   136  }
   137  
   138  type rawdynamicproperty struct {
   139  	Key   json.RawMessage `json:"key"`
   140  	Value json.RawMessage `json:"value"`
   141  }
   142  
   143  type rawset struct {
   144  	Of json.RawMessage `json:"of"`
   145  }
   146  
   147  type rawunion struct {
   148  	Of []json.RawMessage `json:"of"`
   149  }
   150  
   151  type rawdecl struct {
   152  	Args     []json.RawMessage `json:"args"`
   153  	Result   json.RawMessage   `json:"result"`
   154  	Variadic json.RawMessage   `json:"variadic"`
   155  }
   156  
   157  func unmarshalSlice(elems []json.RawMessage) (result []Type, err error) {
   158  	result = make([]Type, len(elems))
   159  	for i := range elems {
   160  		if result[i], err = Unmarshal(elems[i]); err != nil {
   161  			return nil, err
   162  		}
   163  	}
   164  	return result, err
   165  }
   166  
   167  func unmarshalStaticPropertySlice(elems []rawstaticproperty) (result []*StaticProperty, err error) {
   168  	result = make([]*StaticProperty, len(elems))
   169  	for i := range elems {
   170  		value, err := Unmarshal(elems[i].Value)
   171  		if err != nil {
   172  			return nil, err
   173  		}
   174  		result[i] = NewStaticProperty(elems[i].Key, value)
   175  	}
   176  	return result, err
   177  }
   178  
   179  func unmarshalDynamicProperty(x rawdynamicproperty) (result *DynamicProperty, err error) {
   180  	if len(x.Key) == 0 {
   181  		return nil, nil
   182  	}
   183  	var key Type
   184  	if key, err = Unmarshal(x.Key); err == nil {
   185  		var value Type
   186  		if value, err = Unmarshal(x.Value); err == nil {
   187  			return NewDynamicProperty(key, value), nil
   188  		}
   189  	}
   190  	return nil, err
   191  }