package mangler

import (
	"unsafe"

	"codeberg.org/gruf/go-xunsafe"
)

// field stores the minimum necessary
// data for iterating and mangling
// each field in a given struct.
type field struct {
	mangle Mangler
	offset uintptr
}

// iterStructType returns a Mangler capable of iterating
// and mangling the given struct type currently in TypeIter{}.
// note this will fetch sub-Manglers for each struct field.
func iterStructType(t xunsafe.TypeIter) Mangler {

	// Number of struct fields.
	n := t.Type.NumField()

	// Gather mangler functions.
	fields := make([]field, n)
	for i := 0; i < n; i++ {

		// Get struct field at index.
		ft, sfield := t.StructField(i)

		// Get field mangler.
		fn := loadOrGet(ft)
		if fn == nil {
			return nil
		}

		// Set field info.
		fields[i] = field{
			mangle: fn,
			offset: sfield.Offset,
		}
	}

	// Handle no. fields.
	switch len(fields) {
	case 0:
		return empty_mangler
	case 1:
		return fields[0].mangle
	default:
		return func(buf []byte, ptr unsafe.Pointer) []byte {
			for i := range fields {
				// Get struct field ptr via offset.
				fptr := add(ptr, fields[i].offset)

				// Mangle the struct field data.
				buf = fields[i].mangle(buf, fptr)
				buf = append(buf, ',')
			}

			if len(fields) > 0 {
				// Drop final comma.
				buf = buf[:len(buf)-1]
			}

			return buf
		}
	}
}
