github.com/anonymouse64/snapd@v0.0.0-20210824153203-04c4c42d842d/interfaces/utils/utils.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2018 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package utils
    21  
    22  import (
    23  	"encoding/json"
    24  )
    25  
    26  // NormalizeInterfaceAttributes normalises types of an attribute values.
    27  // The following transformations are applied: int -> int64, float32 -> float64.
    28  // The normalisation proceeds recursively through maps and slices.
    29  func NormalizeInterfaceAttributes(value interface{}) interface{} {
    30  	// Normalize ints/floats using their 64-bit variants.
    31  	switch v := value.(type) {
    32  	case int:
    33  		return int64(v)
    34  	case float32:
    35  		return float64(v)
    36  	case []interface{}:
    37  		vc := make([]interface{}, len(v))
    38  		for i, el := range v {
    39  			vc[i] = NormalizeInterfaceAttributes(el)
    40  		}
    41  		return vc
    42  	case map[string]interface{}:
    43  		vc := make(map[string]interface{}, len(v))
    44  		for key, item := range v {
    45  			vc[key] = NormalizeInterfaceAttributes(item)
    46  		}
    47  		return vc
    48  	case json.Number:
    49  		jsonval := value.(json.Number)
    50  		if asInt, err := jsonval.Int64(); err == nil {
    51  			return asInt
    52  		}
    53  		asFloat, _ := jsonval.Float64()
    54  		return asFloat
    55  	}
    56  	return value
    57  }
    58  
    59  // CopyAttributes makes a deep copy of the attributes map.
    60  func CopyAttributes(value map[string]interface{}) map[string]interface{} {
    61  	return copyRecursive(value).(map[string]interface{})
    62  }
    63  
    64  func copyRecursive(value interface{}) interface{} {
    65  	// note: ensure all the mutable types (or types that need a conversion)
    66  	// are handled here.
    67  	switch v := value.(type) {
    68  	case []interface{}:
    69  		arr := make([]interface{}, len(v))
    70  		for i, el := range v {
    71  			arr[i] = copyRecursive(el)
    72  		}
    73  		return arr
    74  	case map[string]interface{}:
    75  		mp := make(map[string]interface{}, len(v))
    76  		for key, item := range v {
    77  			mp[key] = copyRecursive(item)
    78  		}
    79  		return mp
    80  	}
    81  	return value
    82  }