Tizen_4.0 base
[platform/upstream/docker-engine.git] / vendor / github.com / godbus / dbus / variant.go
1 package dbus
2
3 import (
4         "bytes"
5         "fmt"
6         "reflect"
7         "sort"
8         "strconv"
9 )
10
11 // Variant represents the D-Bus variant type.
12 type Variant struct {
13         sig   Signature
14         value interface{}
15 }
16
17 // MakeVariant converts the given value to a Variant. It panics if v cannot be
18 // represented as a D-Bus type.
19 func MakeVariant(v interface{}) Variant {
20         return Variant{SignatureOf(v), v}
21 }
22
23 // ParseVariant parses the given string as a variant as described at
24 // https://developer.gnome.org/glib/unstable/gvariant-text.html. If sig is not
25 // empty, it is taken to be the expected signature for the variant.
26 func ParseVariant(s string, sig Signature) (Variant, error) {
27         tokens := varLex(s)
28         p := &varParser{tokens: tokens}
29         n, err := varMakeNode(p)
30         if err != nil {
31                 return Variant{}, err
32         }
33         if sig.str == "" {
34                 sig, err = varInfer(n)
35                 if err != nil {
36                         return Variant{}, err
37                 }
38         }
39         v, err := n.Value(sig)
40         if err != nil {
41                 return Variant{}, err
42         }
43         return MakeVariant(v), nil
44 }
45
46 // format returns a formatted version of v and whether this string can be parsed
47 // unambigously.
48 func (v Variant) format() (string, bool) {
49         switch v.sig.str[0] {
50         case 'b', 'i':
51                 return fmt.Sprint(v.value), true
52         case 'n', 'q', 'u', 'x', 't', 'd', 'h':
53                 return fmt.Sprint(v.value), false
54         case 's':
55                 return strconv.Quote(v.value.(string)), true
56         case 'o':
57                 return strconv.Quote(string(v.value.(ObjectPath))), false
58         case 'g':
59                 return strconv.Quote(v.value.(Signature).str), false
60         case 'v':
61                 s, unamb := v.value.(Variant).format()
62                 if !unamb {
63                         return "<@" + v.value.(Variant).sig.str + " " + s + ">", true
64                 }
65                 return "<" + s + ">", true
66         case 'y':
67                 return fmt.Sprintf("%#x", v.value.(byte)), false
68         }
69         rv := reflect.ValueOf(v.value)
70         switch rv.Kind() {
71         case reflect.Slice:
72                 if rv.Len() == 0 {
73                         return "[]", false
74                 }
75                 unamb := true
76                 buf := bytes.NewBuffer([]byte("["))
77                 for i := 0; i < rv.Len(); i++ {
78                         // TODO: slooow
79                         s, b := MakeVariant(rv.Index(i).Interface()).format()
80                         unamb = unamb && b
81                         buf.WriteString(s)
82                         if i != rv.Len()-1 {
83                                 buf.WriteString(", ")
84                         }
85                 }
86                 buf.WriteByte(']')
87                 return buf.String(), unamb
88         case reflect.Map:
89                 if rv.Len() == 0 {
90                         return "{}", false
91                 }
92                 unamb := true
93                 var buf bytes.Buffer
94                 kvs := make([]string, rv.Len())
95                 for i, k := range rv.MapKeys() {
96                         s, b := MakeVariant(k.Interface()).format()
97                         unamb = unamb && b
98                         buf.Reset()
99                         buf.WriteString(s)
100                         buf.WriteString(": ")
101                         s, b = MakeVariant(rv.MapIndex(k).Interface()).format()
102                         unamb = unamb && b
103                         buf.WriteString(s)
104                         kvs[i] = buf.String()
105                 }
106                 buf.Reset()
107                 buf.WriteByte('{')
108                 sort.Strings(kvs)
109                 for i, kv := range kvs {
110                         if i > 0 {
111                                 buf.WriteString(", ")
112                         }
113                         buf.WriteString(kv)
114                 }
115                 buf.WriteByte('}')
116                 return buf.String(), unamb
117         }
118         return `"INVALID"`, true
119 }
120
121 // Signature returns the D-Bus signature of the underlying value of v.
122 func (v Variant) Signature() Signature {
123         return v.sig
124 }
125
126 // String returns the string representation of the underlying value of v as
127 // described at https://developer.gnome.org/glib/unstable/gvariant-text.html.
128 func (v Variant) String() string {
129         s, unamb := v.format()
130         if !unamb {
131                 return "@" + v.sig.str + " " + s
132         }
133         return s
134 }
135
136 // Value returns the underlying value of v.
137 func (v Variant) Value() interface{} {
138         return v.value
139 }