1// Copyright 2021 CUE Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package pbinternal
16
17import (
18 "strings"
19 "unicode"
20 "unicode/utf8"
21
22 "cuelang.org/go/cue"
23)
24
25type CompositeType int
26
27const (
28 Normal CompositeType = iota
29 List
30 Map
31)
32
33type ValueType int
34
35const (
36 Unknown ValueType = iota
37 Message
38 Int
39 Float
40 String
41 Bytes
42 Bool
43)
44
45type Info struct {
46 Name string
47 CUEName string
48 Attr cue.Attribute
49 Value cue.Value
50
51 CompositeType CompositeType
52 ValueType ValueType
53 Type string
54
55 IsEnum bool
56
57 // For maps only
58 KeyType ValueType // only for maps
59 KeyTypeString string
60}
61
62func FromIter(i *cue.Iterator) (info Info, err error) {
63 return FromValue(i.Selector().Unquoted(), i.Value())
64}
65
66func FromValue(name string, v cue.Value) (info Info, err error) {
67 a := v.Attribute("protobuf")
68
69 info.Name = name
70 info.CUEName = name
71
72 if a.Err() == nil {
73 info.Attr = a
74
75 s, ok, err := a.Lookup(1, "name")
76 if err != nil {
77 return info, err
78 }
79 if ok {
80 info.Name = strings.TrimSpace(s)
81 }
82
83 info.Type, err = a.String(1)
84 if err != nil {
85 return info, err
86 }
87 }
88
89 switch v.IncompleteKind() {
90 case cue.ListKind:
91 info.CompositeType = List
92 if e := v.LookupPath(cue.MakePath(cue.AnyIndex)); e.Exists() {
93 v = e
94 } else {
95 for i, _ := v.List(); i.Next(); {
96 v = i.Value()
97 break
98 }
99 }
100
101 case cue.StructKind:
102 if strings.HasPrefix(info.Type, "map[") {
103 a := strings.SplitN(info.Type[len("map["):], "]", 2)
104 info.KeyTypeString = strings.TrimSpace(a[0])
105 switch info.KeyTypeString {
106 case "string":
107 info.KeyType = String
108 case "bytes":
109 info.KeyType = Bytes
110 case "double", "float":
111 info.KeyType = Float
112 case "bool":
113 info.KeyType = Bool
114 default:
115 info.KeyType = Int // Assuming
116 }
117 info.CompositeType = Map
118 v = v.LookupPath(cue.MakePath(cue.AnyString))
119 }
120 }
121
122 info.Value = v
123
124 switch v.IncompleteKind() {
125 case cue.StructKind:
126 info.ValueType = Message
127
128 case cue.StringKind:
129 info.ValueType = String
130
131 case cue.BytesKind:
132 info.ValueType = Bytes
133
134 case cue.BoolKind:
135 info.ValueType = Bool
136
137 case cue.IntKind:
138 info.ValueType = Int
139 r, _ := utf8.DecodeRuneInString(info.Type)
140 info.IsEnum = unicode.In(r, unicode.Upper)
141
142 case cue.FloatKind, cue.NumberKind:
143 info.ValueType = Float
144 }
145
146 return info, nil
147}