// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package unique

import (
	
	
	
)

// clone makes a copy of value, and may update string values found in value
// with a cloned version of those strings. The purpose of explicitly cloning
// strings is to avoid accidentally giving a large string a long lifetime.
//
// Note that this will clone strings in structs and arrays found in value,
// and will clone value if it itself is a string. It will not, however, clone
// strings if value is of interface or slice type (that is, found via an
// indirection).
func clone[ comparable]( ,  *cloneSeq)  {
	for ,  := range .stringOffsets {
		 := (*string)(unsafe.Pointer(uintptr(unsafe.Pointer(&)) + ))
		* = stringslite.Clone(*)
	}
	return 
}

// singleStringClone describes how to clone a single string.
var singleStringClone = cloneSeq{stringOffsets: []uintptr{0}}

// cloneSeq describes how to clone a value of a particular type.
type cloneSeq struct {
	stringOffsets []uintptr
}

// makeCloneSeq creates a cloneSeq for a type.
func makeCloneSeq( *abi.Type) cloneSeq {
	if  == nil {
		return cloneSeq{}
	}
	if .Kind() == abi.String {
		return singleStringClone
	}
	var  cloneSeq
	switch .Kind() {
	case abi.Struct:
		buildStructCloneSeq(, &, 0)
	case abi.Array:
		buildArrayCloneSeq(, &, 0)
	}
	return 
}

// buildStructCloneSeq populates a cloneSeq for an abi.Type that has Kind abi.Struct.
func buildStructCloneSeq( *abi.Type,  *cloneSeq,  uintptr) {
	 := .StructType()
	for  := range .Fields {
		 := &.Fields[]
		switch .Typ.Kind() {
		case abi.String:
			.stringOffsets = append(.stringOffsets, +.Offset)
		case abi.Struct:
			(.Typ, , +.Offset)
		case abi.Array:
			buildArrayCloneSeq(.Typ, , +.Offset)
		}
	}
}

// buildArrayCloneSeq populates a cloneSeq for an abi.Type that has Kind abi.Array.
func buildArrayCloneSeq( *abi.Type,  *cloneSeq,  uintptr) {
	 := .ArrayType()
	 := .Elem
	 := 
	for range .Len {
		switch .Kind() {
		case abi.String:
			.stringOffsets = append(.stringOffsets, )
		case abi.Struct:
			buildStructCloneSeq(, , )
		case abi.Array:
			(, , )
		}
		 += .Size()
		 := uintptr(.FieldAlign())
		 = ( +  - 1) &^ ( - 1)
	}
}