variant.go 3.2 KB

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