@@ -569,12 +569,13 @@ struct field {
569569}
570570
571571// Field cache data for structure types and associated RWMutex.
572- let mut fieldMap = map[uintptr][]& field{}
572+ let mut fieldMap = map[uintptr][]field{}
573573let mut fieldMapLock = runtime::rwmutex{}
574574
575575// Returns field cache data for the structure type T.
576576// If the structure is not cached yet, it will cache it.
577- fn cachedFields[T](): []&field {
577+ #disable nilptr boundary
578+ fn cachedFields[T](): []field {
578579 const t = comptime::TypeOf(T)
579580 fieldMapLock.rLock()
580581 mut cache, mut exist := fieldMap[t.Hash()]
@@ -597,16 +598,24 @@ fn cachedFields[T](): []&field {
597598 p := unsafe { (*T)(0) }
598599 const pv = comptime::ValueOf(unsafe { *p })
599600 const fields = t.Fields()
600- const for i, f in t.Decl().Fields() {
601- const tag = f.Tag("json")
601+ mut n := 0
602+ // Grow cache by field count,
603+ // a typical JSON structure is encoded with all fields.
604+ cache = make([]field, len(fields))
605+ const for i, f in fields {
606+ const fd = f.Decl()
607+ const tag = fd.Tag("json")
602608 const match {
603- | f .Public() | tag != "":
604- name := getFieldName[T](f .Public(), f .Name(), tag)
609+ | fd .Public() | tag != "":
610+ name := getFieldName[T](fd .Public(), fd .Name(), tag)
605611 if name != "" {
606- comptime::TypeAlias(fieldType, fields[i] .Type())
612+ comptime::TypeAlias(fieldType, f .Type())
607613
608- mut fieldCache := new(field)
614+ // Initialize directly the slice's memory.
615+ // This is efficient than appending a temporary cache object.
616+ mut &fieldCache := unsafe { &(*&cache[n]) }
609617 fieldCache.offset = uintptr(&pv.FieldByIndex(i).Unwrap())
618+ n++
610619
611620 // Cache name for non-escape.
612621 fieldCache.nameNonEsc = name
@@ -624,11 +633,12 @@ fn cachedFields[T](): []&field {
624633 fieldCache.encodePlain = typeEncoderPlain[fieldType]
625634 fieldCache.encodeIndent = typeEncoderIndent[fieldType]
626635 fieldCache.decode = typeDecoder[fieldType]
627-
628- cache = append(cache, fieldCache)
629636 }
630637 }
631638 }
639+ // Truncate the cache, there may be skipped fields.
640+ cache = cache[:n]
641+ // Save the cache and return.
632642 fieldMap[t.Hash()] = cache
633643 fieldMapLock.unlock()
634644 ret cache
0 commit comments