Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / github.com / golang / protobuf / proto / table_merge.go
1 // Go support for Protocol Buffers - Google's data interchange format
2 //
3 // Copyright 2016 The Go Authors.  All rights reserved.
4 // https://github.com/golang/protobuf
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are
8 // met:
9 //
10 //     * Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 //     * Redistributions in binary form must reproduce the above
13 // copyright notice, this list of conditions and the following disclaimer
14 // in the documentation and/or other materials provided with the
15 // distribution.
16 //     * Neither the name of Google Inc. nor the names of its
17 // contributors may be used to endorse or promote products derived from
18 // this software without specific prior written permission.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32 package proto
33
34 import (
35         "fmt"
36         "reflect"
37         "strings"
38         "sync"
39         "sync/atomic"
40 )
41
42 // Merge merges the src message into dst.
43 // This assumes that dst and src of the same type and are non-nil.
44 func (a *InternalMessageInfo) Merge(dst, src Message) {
45         mi := atomicLoadMergeInfo(&a.merge)
46         if mi == nil {
47                 mi = getMergeInfo(reflect.TypeOf(dst).Elem())
48                 atomicStoreMergeInfo(&a.merge, mi)
49         }
50         mi.merge(toPointer(&dst), toPointer(&src))
51 }
52
53 type mergeInfo struct {
54         typ reflect.Type
55
56         initialized int32 // 0: only typ is valid, 1: everything is valid
57         lock        sync.Mutex
58
59         fields       []mergeFieldInfo
60         unrecognized field // Offset of XXX_unrecognized
61 }
62
63 type mergeFieldInfo struct {
64         field field // Offset of field, guaranteed to be valid
65
66         // isPointer reports whether the value in the field is a pointer.
67         // This is true for the following situations:
68         //      * Pointer to struct
69         //      * Pointer to basic type (proto2 only)
70         //      * Slice (first value in slice header is a pointer)
71         //      * String (first value in string header is a pointer)
72         isPointer bool
73
74         // basicWidth reports the width of the field assuming that it is directly
75         // embedded in the struct (as is the case for basic types in proto3).
76         // The possible values are:
77         //      0: invalid
78         //      1: bool
79         //      4: int32, uint32, float32
80         //      8: int64, uint64, float64
81         basicWidth int
82
83         // Where dst and src are pointers to the types being merged.
84         merge func(dst, src pointer)
85 }
86
87 var (
88         mergeInfoMap  = map[reflect.Type]*mergeInfo{}
89         mergeInfoLock sync.Mutex
90 )
91
92 func getMergeInfo(t reflect.Type) *mergeInfo {
93         mergeInfoLock.Lock()
94         defer mergeInfoLock.Unlock()
95         mi := mergeInfoMap[t]
96         if mi == nil {
97                 mi = &mergeInfo{typ: t}
98                 mergeInfoMap[t] = mi
99         }
100         return mi
101 }
102
103 // merge merges src into dst assuming they are both of type *mi.typ.
104 func (mi *mergeInfo) merge(dst, src pointer) {
105         if dst.isNil() {
106                 panic("proto: nil destination")
107         }
108         if src.isNil() {
109                 return // Nothing to do.
110         }
111
112         if atomic.LoadInt32(&mi.initialized) == 0 {
113                 mi.computeMergeInfo()
114         }
115
116         for _, fi := range mi.fields {
117                 sfp := src.offset(fi.field)
118
119                 // As an optimization, we can avoid the merge function call cost
120                 // if we know for sure that the source will have no effect
121                 // by checking if it is the zero value.
122                 if unsafeAllowed {
123                         if fi.isPointer && sfp.getPointer().isNil() { // Could be slice or string
124                                 continue
125                         }
126                         if fi.basicWidth > 0 {
127                                 switch {
128                                 case fi.basicWidth == 1 && !*sfp.toBool():
129                                         continue
130                                 case fi.basicWidth == 4 && *sfp.toUint32() == 0:
131                                         continue
132                                 case fi.basicWidth == 8 && *sfp.toUint64() == 0:
133                                         continue
134                                 }
135                         }
136                 }
137
138                 dfp := dst.offset(fi.field)
139                 fi.merge(dfp, sfp)
140         }
141
142         // TODO: Make this faster?
143         out := dst.asPointerTo(mi.typ).Elem()
144         in := src.asPointerTo(mi.typ).Elem()
145         if emIn, err := extendable(in.Addr().Interface()); err == nil {
146                 emOut, _ := extendable(out.Addr().Interface())
147                 mIn, muIn := emIn.extensionsRead()
148                 if mIn != nil {
149                         mOut := emOut.extensionsWrite()
150                         muIn.Lock()
151                         mergeExtension(mOut, mIn)
152                         muIn.Unlock()
153                 }
154         }
155
156         if mi.unrecognized.IsValid() {
157                 if b := *src.offset(mi.unrecognized).toBytes(); len(b) > 0 {
158                         *dst.offset(mi.unrecognized).toBytes() = append([]byte(nil), b...)
159                 }
160         }
161 }
162
163 func (mi *mergeInfo) computeMergeInfo() {
164         mi.lock.Lock()
165         defer mi.lock.Unlock()
166         if mi.initialized != 0 {
167                 return
168         }
169         t := mi.typ
170         n := t.NumField()
171
172         props := GetProperties(t)
173         for i := 0; i < n; i++ {
174                 f := t.Field(i)
175                 if strings.HasPrefix(f.Name, "XXX_") {
176                         continue
177                 }
178
179                 mfi := mergeFieldInfo{field: toField(&f)}
180                 tf := f.Type
181
182                 // As an optimization, we can avoid the merge function call cost
183                 // if we know for sure that the source will have no effect
184                 // by checking if it is the zero value.
185                 if unsafeAllowed {
186                         switch tf.Kind() {
187                         case reflect.Ptr, reflect.Slice, reflect.String:
188                                 // As a special case, we assume slices and strings are pointers
189                                 // since we know that the first field in the SliceSlice or
190                                 // StringHeader is a data pointer.
191                                 mfi.isPointer = true
192                         case reflect.Bool:
193                                 mfi.basicWidth = 1
194                         case reflect.Int32, reflect.Uint32, reflect.Float32:
195                                 mfi.basicWidth = 4
196                         case reflect.Int64, reflect.Uint64, reflect.Float64:
197                                 mfi.basicWidth = 8
198                         }
199                 }
200
201                 // Unwrap tf to get at its most basic type.
202                 var isPointer, isSlice bool
203                 if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 {
204                         isSlice = true
205                         tf = tf.Elem()
206                 }
207                 if tf.Kind() == reflect.Ptr {
208                         isPointer = true
209                         tf = tf.Elem()
210                 }
211                 if isPointer && isSlice && tf.Kind() != reflect.Struct {
212                         panic("both pointer and slice for basic type in " + tf.Name())
213                 }
214
215                 switch tf.Kind() {
216                 case reflect.Int32:
217                         switch {
218                         case isSlice: // E.g., []int32
219                                 mfi.merge = func(dst, src pointer) {
220                                         // NOTE: toInt32Slice is not defined (see pointer_reflect.go).
221                                         /*
222                                                 sfsp := src.toInt32Slice()
223                                                 if *sfsp != nil {
224                                                         dfsp := dst.toInt32Slice()
225                                                         *dfsp = append(*dfsp, *sfsp...)
226                                                         if *dfsp == nil {
227                                                                 *dfsp = []int64{}
228                                                         }
229                                                 }
230                                         */
231                                         sfs := src.getInt32Slice()
232                                         if sfs != nil {
233                                                 dfs := dst.getInt32Slice()
234                                                 dfs = append(dfs, sfs...)
235                                                 if dfs == nil {
236                                                         dfs = []int32{}
237                                                 }
238                                                 dst.setInt32Slice(dfs)
239                                         }
240                                 }
241                         case isPointer: // E.g., *int32
242                                 mfi.merge = func(dst, src pointer) {
243                                         // NOTE: toInt32Ptr is not defined (see pointer_reflect.go).
244                                         /*
245                                                 sfpp := src.toInt32Ptr()
246                                                 if *sfpp != nil {
247                                                         dfpp := dst.toInt32Ptr()
248                                                         if *dfpp == nil {
249                                                                 *dfpp = Int32(**sfpp)
250                                                         } else {
251                                                                 **dfpp = **sfpp
252                                                         }
253                                                 }
254                                         */
255                                         sfp := src.getInt32Ptr()
256                                         if sfp != nil {
257                                                 dfp := dst.getInt32Ptr()
258                                                 if dfp == nil {
259                                                         dst.setInt32Ptr(*sfp)
260                                                 } else {
261                                                         *dfp = *sfp
262                                                 }
263                                         }
264                                 }
265                         default: // E.g., int32
266                                 mfi.merge = func(dst, src pointer) {
267                                         if v := *src.toInt32(); v != 0 {
268                                                 *dst.toInt32() = v
269                                         }
270                                 }
271                         }
272                 case reflect.Int64:
273                         switch {
274                         case isSlice: // E.g., []int64
275                                 mfi.merge = func(dst, src pointer) {
276                                         sfsp := src.toInt64Slice()
277                                         if *sfsp != nil {
278                                                 dfsp := dst.toInt64Slice()
279                                                 *dfsp = append(*dfsp, *sfsp...)
280                                                 if *dfsp == nil {
281                                                         *dfsp = []int64{}
282                                                 }
283                                         }
284                                 }
285                         case isPointer: // E.g., *int64
286                                 mfi.merge = func(dst, src pointer) {
287                                         sfpp := src.toInt64Ptr()
288                                         if *sfpp != nil {
289                                                 dfpp := dst.toInt64Ptr()
290                                                 if *dfpp == nil {
291                                                         *dfpp = Int64(**sfpp)
292                                                 } else {
293                                                         **dfpp = **sfpp
294                                                 }
295                                         }
296                                 }
297                         default: // E.g., int64
298                                 mfi.merge = func(dst, src pointer) {
299                                         if v := *src.toInt64(); v != 0 {
300                                                 *dst.toInt64() = v
301                                         }
302                                 }
303                         }
304                 case reflect.Uint32:
305                         switch {
306                         case isSlice: // E.g., []uint32
307                                 mfi.merge = func(dst, src pointer) {
308                                         sfsp := src.toUint32Slice()
309                                         if *sfsp != nil {
310                                                 dfsp := dst.toUint32Slice()
311                                                 *dfsp = append(*dfsp, *sfsp...)
312                                                 if *dfsp == nil {
313                                                         *dfsp = []uint32{}
314                                                 }
315                                         }
316                                 }
317                         case isPointer: // E.g., *uint32
318                                 mfi.merge = func(dst, src pointer) {
319                                         sfpp := src.toUint32Ptr()
320                                         if *sfpp != nil {
321                                                 dfpp := dst.toUint32Ptr()
322                                                 if *dfpp == nil {
323                                                         *dfpp = Uint32(**sfpp)
324                                                 } else {
325                                                         **dfpp = **sfpp
326                                                 }
327                                         }
328                                 }
329                         default: // E.g., uint32
330                                 mfi.merge = func(dst, src pointer) {
331                                         if v := *src.toUint32(); v != 0 {
332                                                 *dst.toUint32() = v
333                                         }
334                                 }
335                         }
336                 case reflect.Uint64:
337                         switch {
338                         case isSlice: // E.g., []uint64
339                                 mfi.merge = func(dst, src pointer) {
340                                         sfsp := src.toUint64Slice()
341                                         if *sfsp != nil {
342                                                 dfsp := dst.toUint64Slice()
343                                                 *dfsp = append(*dfsp, *sfsp...)
344                                                 if *dfsp == nil {
345                                                         *dfsp = []uint64{}
346                                                 }
347                                         }
348                                 }
349                         case isPointer: // E.g., *uint64
350                                 mfi.merge = func(dst, src pointer) {
351                                         sfpp := src.toUint64Ptr()
352                                         if *sfpp != nil {
353                                                 dfpp := dst.toUint64Ptr()
354                                                 if *dfpp == nil {
355                                                         *dfpp = Uint64(**sfpp)
356                                                 } else {
357                                                         **dfpp = **sfpp
358                                                 }
359                                         }
360                                 }
361                         default: // E.g., uint64
362                                 mfi.merge = func(dst, src pointer) {
363                                         if v := *src.toUint64(); v != 0 {
364                                                 *dst.toUint64() = v
365                                         }
366                                 }
367                         }
368                 case reflect.Float32:
369                         switch {
370                         case isSlice: // E.g., []float32
371                                 mfi.merge = func(dst, src pointer) {
372                                         sfsp := src.toFloat32Slice()
373                                         if *sfsp != nil {
374                                                 dfsp := dst.toFloat32Slice()
375                                                 *dfsp = append(*dfsp, *sfsp...)
376                                                 if *dfsp == nil {
377                                                         *dfsp = []float32{}
378                                                 }
379                                         }
380                                 }
381                         case isPointer: // E.g., *float32
382                                 mfi.merge = func(dst, src pointer) {
383                                         sfpp := src.toFloat32Ptr()
384                                         if *sfpp != nil {
385                                                 dfpp := dst.toFloat32Ptr()
386                                                 if *dfpp == nil {
387                                                         *dfpp = Float32(**sfpp)
388                                                 } else {
389                                                         **dfpp = **sfpp
390                                                 }
391                                         }
392                                 }
393                         default: // E.g., float32
394                                 mfi.merge = func(dst, src pointer) {
395                                         if v := *src.toFloat32(); v != 0 {
396                                                 *dst.toFloat32() = v
397                                         }
398                                 }
399                         }
400                 case reflect.Float64:
401                         switch {
402                         case isSlice: // E.g., []float64
403                                 mfi.merge = func(dst, src pointer) {
404                                         sfsp := src.toFloat64Slice()
405                                         if *sfsp != nil {
406                                                 dfsp := dst.toFloat64Slice()
407                                                 *dfsp = append(*dfsp, *sfsp...)
408                                                 if *dfsp == nil {
409                                                         *dfsp = []float64{}
410                                                 }
411                                         }
412                                 }
413                         case isPointer: // E.g., *float64
414                                 mfi.merge = func(dst, src pointer) {
415                                         sfpp := src.toFloat64Ptr()
416                                         if *sfpp != nil {
417                                                 dfpp := dst.toFloat64Ptr()
418                                                 if *dfpp == nil {
419                                                         *dfpp = Float64(**sfpp)
420                                                 } else {
421                                                         **dfpp = **sfpp
422                                                 }
423                                         }
424                                 }
425                         default: // E.g., float64
426                                 mfi.merge = func(dst, src pointer) {
427                                         if v := *src.toFloat64(); v != 0 {
428                                                 *dst.toFloat64() = v
429                                         }
430                                 }
431                         }
432                 case reflect.Bool:
433                         switch {
434                         case isSlice: // E.g., []bool
435                                 mfi.merge = func(dst, src pointer) {
436                                         sfsp := src.toBoolSlice()
437                                         if *sfsp != nil {
438                                                 dfsp := dst.toBoolSlice()
439                                                 *dfsp = append(*dfsp, *sfsp...)
440                                                 if *dfsp == nil {
441                                                         *dfsp = []bool{}
442                                                 }
443                                         }
444                                 }
445                         case isPointer: // E.g., *bool
446                                 mfi.merge = func(dst, src pointer) {
447                                         sfpp := src.toBoolPtr()
448                                         if *sfpp != nil {
449                                                 dfpp := dst.toBoolPtr()
450                                                 if *dfpp == nil {
451                                                         *dfpp = Bool(**sfpp)
452                                                 } else {
453                                                         **dfpp = **sfpp
454                                                 }
455                                         }
456                                 }
457                         default: // E.g., bool
458                                 mfi.merge = func(dst, src pointer) {
459                                         if v := *src.toBool(); v {
460                                                 *dst.toBool() = v
461                                         }
462                                 }
463                         }
464                 case reflect.String:
465                         switch {
466                         case isSlice: // E.g., []string
467                                 mfi.merge = func(dst, src pointer) {
468                                         sfsp := src.toStringSlice()
469                                         if *sfsp != nil {
470                                                 dfsp := dst.toStringSlice()
471                                                 *dfsp = append(*dfsp, *sfsp...)
472                                                 if *dfsp == nil {
473                                                         *dfsp = []string{}
474                                                 }
475                                         }
476                                 }
477                         case isPointer: // E.g., *string
478                                 mfi.merge = func(dst, src pointer) {
479                                         sfpp := src.toStringPtr()
480                                         if *sfpp != nil {
481                                                 dfpp := dst.toStringPtr()
482                                                 if *dfpp == nil {
483                                                         *dfpp = String(**sfpp)
484                                                 } else {
485                                                         **dfpp = **sfpp
486                                                 }
487                                         }
488                                 }
489                         default: // E.g., string
490                                 mfi.merge = func(dst, src pointer) {
491                                         if v := *src.toString(); v != "" {
492                                                 *dst.toString() = v
493                                         }
494                                 }
495                         }
496                 case reflect.Slice:
497                         isProto3 := props.Prop[i].proto3
498                         switch {
499                         case isPointer:
500                                 panic("bad pointer in byte slice case in " + tf.Name())
501                         case tf.Elem().Kind() != reflect.Uint8:
502                                 panic("bad element kind in byte slice case in " + tf.Name())
503                         case isSlice: // E.g., [][]byte
504                                 mfi.merge = func(dst, src pointer) {
505                                         sbsp := src.toBytesSlice()
506                                         if *sbsp != nil {
507                                                 dbsp := dst.toBytesSlice()
508                                                 for _, sb := range *sbsp {
509                                                         if sb == nil {
510                                                                 *dbsp = append(*dbsp, nil)
511                                                         } else {
512                                                                 *dbsp = append(*dbsp, append([]byte{}, sb...))
513                                                         }
514                                                 }
515                                                 if *dbsp == nil {
516                                                         *dbsp = [][]byte{}
517                                                 }
518                                         }
519                                 }
520                         default: // E.g., []byte
521                                 mfi.merge = func(dst, src pointer) {
522                                         sbp := src.toBytes()
523                                         if *sbp != nil {
524                                                 dbp := dst.toBytes()
525                                                 if !isProto3 || len(*sbp) > 0 {
526                                                         *dbp = append([]byte{}, *sbp...)
527                                                 }
528                                         }
529                                 }
530                         }
531                 case reflect.Struct:
532                         switch {
533                         case !isPointer:
534                                 panic(fmt.Sprintf("message field %s without pointer", tf))
535                         case isSlice: // E.g., []*pb.T
536                                 mi := getMergeInfo(tf)
537                                 mfi.merge = func(dst, src pointer) {
538                                         sps := src.getPointerSlice()
539                                         if sps != nil {
540                                                 dps := dst.getPointerSlice()
541                                                 for _, sp := range sps {
542                                                         var dp pointer
543                                                         if !sp.isNil() {
544                                                                 dp = valToPointer(reflect.New(tf))
545                                                                 mi.merge(dp, sp)
546                                                         }
547                                                         dps = append(dps, dp)
548                                                 }
549                                                 if dps == nil {
550                                                         dps = []pointer{}
551                                                 }
552                                                 dst.setPointerSlice(dps)
553                                         }
554                                 }
555                         default: // E.g., *pb.T
556                                 mi := getMergeInfo(tf)
557                                 mfi.merge = func(dst, src pointer) {
558                                         sp := src.getPointer()
559                                         if !sp.isNil() {
560                                                 dp := dst.getPointer()
561                                                 if dp.isNil() {
562                                                         dp = valToPointer(reflect.New(tf))
563                                                         dst.setPointer(dp)
564                                                 }
565                                                 mi.merge(dp, sp)
566                                         }
567                                 }
568                         }
569                 case reflect.Map:
570                         switch {
571                         case isPointer || isSlice:
572                                 panic("bad pointer or slice in map case in " + tf.Name())
573                         default: // E.g., map[K]V
574                                 mfi.merge = func(dst, src pointer) {
575                                         sm := src.asPointerTo(tf).Elem()
576                                         if sm.Len() == 0 {
577                                                 return
578                                         }
579                                         dm := dst.asPointerTo(tf).Elem()
580                                         if dm.IsNil() {
581                                                 dm.Set(reflect.MakeMap(tf))
582                                         }
583
584                                         switch tf.Elem().Kind() {
585                                         case reflect.Ptr: // Proto struct (e.g., *T)
586                                                 for _, key := range sm.MapKeys() {
587                                                         val := sm.MapIndex(key)
588                                                         val = reflect.ValueOf(Clone(val.Interface().(Message)))
589                                                         dm.SetMapIndex(key, val)
590                                                 }
591                                         case reflect.Slice: // E.g. Bytes type (e.g., []byte)
592                                                 for _, key := range sm.MapKeys() {
593                                                         val := sm.MapIndex(key)
594                                                         val = reflect.ValueOf(append([]byte{}, val.Bytes()...))
595                                                         dm.SetMapIndex(key, val)
596                                                 }
597                                         default: // Basic type (e.g., string)
598                                                 for _, key := range sm.MapKeys() {
599                                                         val := sm.MapIndex(key)
600                                                         dm.SetMapIndex(key, val)
601                                                 }
602                                         }
603                                 }
604                         }
605                 case reflect.Interface:
606                         // Must be oneof field.
607                         switch {
608                         case isPointer || isSlice:
609                                 panic("bad pointer or slice in interface case in " + tf.Name())
610                         default: // E.g., interface{}
611                                 // TODO: Make this faster?
612                                 mfi.merge = func(dst, src pointer) {
613                                         su := src.asPointerTo(tf).Elem()
614                                         if !su.IsNil() {
615                                                 du := dst.asPointerTo(tf).Elem()
616                                                 typ := su.Elem().Type()
617                                                 if du.IsNil() || du.Elem().Type() != typ {
618                                                         du.Set(reflect.New(typ.Elem())) // Initialize interface if empty
619                                                 }
620                                                 sv := su.Elem().Elem().Field(0)
621                                                 if sv.Kind() == reflect.Ptr && sv.IsNil() {
622                                                         return
623                                                 }
624                                                 dv := du.Elem().Elem().Field(0)
625                                                 if dv.Kind() == reflect.Ptr && dv.IsNil() {
626                                                         dv.Set(reflect.New(sv.Type().Elem())) // Initialize proto message if empty
627                                                 }
628                                                 switch sv.Type().Kind() {
629                                                 case reflect.Ptr: // Proto struct (e.g., *T)
630                                                         Merge(dv.Interface().(Message), sv.Interface().(Message))
631                                                 case reflect.Slice: // E.g. Bytes type (e.g., []byte)
632                                                         dv.Set(reflect.ValueOf(append([]byte{}, sv.Bytes()...)))
633                                                 default: // Basic type (e.g., string)
634                                                         dv.Set(sv)
635                                                 }
636                                         }
637                                 }
638                         }
639                 default:
640                         panic(fmt.Sprintf("merger not found for type:%s", tf))
641                 }
642                 mi.fields = append(mi.fields, mfi)
643         }
644
645         mi.unrecognized = invalidField
646         if f, ok := t.FieldByName("XXX_unrecognized"); ok {
647                 if f.Type != reflect.TypeOf([]byte{}) {
648                         panic("expected XXX_unrecognized to be of type []byte")
649                 }
650                 mi.unrecognized = toField(&f)
651         }
652
653         atomic.StoreInt32(&mi.initialized, 1)
654 }