package reflect

import "unsafe"

// Some of code here has been copied from the Go sources:
//   https://github.com/golang/go/blob/go1.15.2/src/reflect/swapper.go
// It has the following copyright note:
//
// 		Copyright 2016 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.

func Swapper(slice interface{}) func(i, j int) {
	v := ValueOf(slice)
	if v.Kind() != Slice {
		panic(&ValueError{Method: "Swapper"})
	}

	// Just return Nop func if nothing to swap.
	if v.Len() < 2 {
		return func(i, j int) {}
	}

	typ := v.typecode.Elem()
	size := typ.Size()

	header := (*sliceHeader)(v.value)
	tmp := unsafe.Pointer(&make([]byte, size)[0])

	return func(i, j int) {
		if uint(i) >= uint(header.len) || uint(j) >= uint(header.len) {
			panic("reflect: slice index out of range")
		}
		val1 := unsafe.Pointer(uintptr(header.data) + uintptr(i)*size)
		val2 := unsafe.Pointer(uintptr(header.data) + uintptr(j)*size)
		memcpy(tmp, val1, size)
		memcpy(val1, val2, size)
		memcpy(val2, tmp, size)
	}
}
