1// Copyright 2014 Google Inc. All rights reserved.
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 proptools
16
17import (
18	"reflect"
19	"strings"
20	"unicode"
21	"unicode/utf8"
22)
23
24// PropertyNameForField converts the name of a field in property struct to the property name that
25// might appear in a Blueprints file.  Since the property struct fields must always be exported
26// to be accessed with reflection and the canonical Blueprints style is lowercased names, it
27// lower cases the first rune in the field name unless the field name contains an uppercase rune
28// after the first rune (which is always uppercase), and no lowercase runes.
29func PropertyNameForField(fieldName string) string {
30	r, size := utf8.DecodeRuneInString(fieldName)
31	propertyName := string(unicode.ToLower(r))
32	if size == len(fieldName) {
33		return propertyName
34	}
35	if strings.IndexFunc(fieldName[size:], unicode.IsLower) == -1 &&
36		strings.IndexFunc(fieldName[size:], unicode.IsUpper) != -1 {
37		return fieldName
38	}
39	if len(fieldName) > size {
40		propertyName += fieldName[size:]
41	}
42	return propertyName
43}
44
45// FieldNameForProperty converts the name of a property that might appear in a Blueprints file to
46// the name of a field in property struct by uppercasing the first rune.
47func FieldNameForProperty(propertyName string) string {
48	r, size := utf8.DecodeRuneInString(propertyName)
49	fieldName := string(unicode.ToUpper(r))
50	if len(propertyName) > size {
51		fieldName += propertyName[size:]
52	}
53	return fieldName
54}
55
56// Clear takes a pointer to a field and clears the value pointed to by the pointer with zero value.
57func Clear[T any](ptr *T) {
58	var zeroValue T
59	*ptr = zeroValue
60}
61
62// BoolPtr returns a pointer to a new bool containing the given value.
63func BoolPtr(b bool) *bool {
64	return &b
65}
66
67// Int64Ptr returns a pointer to a new int64 containing the given value.
68func Int64Ptr(i int64) *int64 {
69	b := int64(i)
70	return &(b)
71}
72
73// StringPtr returns a pointer to a new string containing the given value.
74func StringPtr(s string) *string {
75	return &s
76}
77
78// BoolDefault takes a pointer to a bool and returns the value pointed to by the pointer if it is non-nil,
79// or def if the pointer is nil.
80func BoolDefault(b *bool, def bool) bool {
81	if b != nil {
82		return *b
83	}
84	return def
85}
86
87// Bool takes a pointer to a bool and returns true iff the pointer is non-nil and points to a true
88// value.
89func Bool(b *bool) bool {
90	return BoolDefault(b, false)
91}
92
93// String takes a pointer to a string and returns the value of the string if the pointer is non-nil,
94// or def if the pointer is nil.
95func StringDefault(s *string, def string) string {
96	if s != nil {
97		return *s
98	}
99	return def
100}
101
102// String takes a pointer to a string and returns the value of the string if the pointer is non-nil,
103// or an empty string.
104func String(s *string) string {
105	return StringDefault(s, "")
106}
107
108// Slice takes a pointer to a slice and returns the value of the slice if the pointer is non-nil,
109// or a nil slice.
110func Slice[T any](s *[]T) []T {
111	if s != nil {
112		return *s
113	}
114	return nil
115}
116
117// IntDefault takes a pointer to an int64 and returns the value pointed to by the pointer cast to int
118// if it is non-nil, or def if the pointer is nil.
119func IntDefault(i *int64, def int) int {
120	if i != nil {
121		return int(*i)
122	}
123	return def
124}
125
126// Int takes a pointer to an int64 and returns the value pointed to by the pointer cast to int
127// if it is non-nil, or 0 if the pointer is nil.
128func Int(i *int64) int {
129	return IntDefault(i, 0)
130}
131
132func isStruct(t reflect.Type) bool {
133	return t.Kind() == reflect.Struct
134}
135
136func isStructPtr(t reflect.Type) bool {
137	return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct
138}
139
140func isSlice(t reflect.Type) bool {
141	return t.Kind() == reflect.Slice
142}
143
144func isSliceOfStruct(t reflect.Type) bool {
145	return isSlice(t) && isStruct(t.Elem())
146}
147
148func isStringOrStringPtr(t reflect.Type) bool {
149	return t.Kind() == reflect.String || (t.Kind() == reflect.Pointer && t.Elem().Kind() == reflect.String)
150}
151
152func isMapOfStruct(t reflect.Type) bool {
153	return t.Kind() == reflect.Map && isStruct(t.Elem())
154}
155
156func isConfigurable(t reflect.Type) bool {
157	return isStruct(t) && t.NumField() > 0 && typeFields(t)[0].Type == configurableMarkerType
158}
159
160func IsConfigurable(t reflect.Type) bool {
161	return isConfigurable(t)
162}
163