Repository: go-go-golems/glazed
Pull request #418 (2024-07-03 17:13:36)

:ambulance: :umbrella: :books: Handle string alias and string declaration types for layers/parameters
This adds code to handle string alias and string declaration handling in the parameters/layers/reflect
modules of glazed.

It uses the opportunity to add a lot of documentation and unit tests.



Patch:
diff --git a/pkg/cmds/layers/parsed-layer.go b/pkg/cmds/layers/parsed-layer.go
index bb31ae8..d74c87b 100644
--- a/pkg/cmds/layers/parsed-layer.go
+++ b/pkg/cmds/layers/parsed-layer.go
@@ -124,6 +124,9 @@ func (p *ParsedLayers) Clone() *ParsedLayers {
 }
 
 func (p *ParsedLayers) GetOrCreate(layer ParameterLayer) *ParsedLayer {
+	if layer == nil {
+		panic("layer must not be nil")
+	}
 	slug := layer.GetSlug()
 	v, ok := p.Get(slug)
 	if !ok {
diff --git a/pkg/cmds/parameters/cobra.go b/pkg/cmds/parameters/cobra.go
index 4fc9f9f..f648529 100644
--- a/pkg/cmds/parameters/cobra.go
+++ b/pkg/cmds/parameters/cobra.go
@@ -184,8 +184,8 @@ func (pds *ParameterDefinitions) AddParametersToCobraCommand(
 			defaultValue := ""
 
 			if parameter.Default != nil {
-				defaultValue, ok = (*parameter.Default).(string)
-				if !ok {
+				defaultValue, err = cast.ToString(*parameter.Default)
+				if err != nil {
 					return errors.Errorf("Default value for parameter %s is not a string: %v", parameter.Name, *parameter.Default)
 				}
 			}
@@ -367,8 +367,8 @@ func (pds *ParameterDefinitions) AddParametersToCobraCommand(
 			defaultValue := ""
 
 			if parameter.Default != nil {
-				defaultValue, ok = (*parameter.Default).(string)
-				if !ok {
+				defaultValue, err = cast.ToString(*parameter.Default)
+				if err != nil {
 					return errors.Errorf("Default value for parameter %s is not a string: %v", parameter.Name, *parameter.Default)
 				}
 			}
diff --git a/pkg/cmds/parameters/parameters.go b/pkg/cmds/parameters/parameters.go
index 8ccbca7..4681918 100644
--- a/pkg/cmds/parameters/parameters.go
+++ b/pkg/cmds/parameters/parameters.go
@@ -159,7 +159,7 @@ func (p *ParameterDefinition) InitializeValueToEmptyValue(value reflect.Value) e
 		ParameterTypeChoiceList,
 		ParameterTypeStringListFromFiles,
 		ParameterTypeStringListFromFile:
-		value.Set(reflect.ValueOf([]string{}))
+		return reflect2.SetReflectValue(value, []string{})
 	case ParameterTypeDate:
 		value.Set(reflect.ValueOf(time.Time{}))
 	case ParameterTypeIntegerList:
@@ -213,11 +213,11 @@ func (p *ParameterDefinition) SetValueFromInterface(value reflect.Value, v inter
 		ParameterTypeChoiceList,
 		ParameterTypeStringListFromFiles,
 		ParameterTypeStringListFromFile:
-		list, ok := cast.CastList2[string, interface{}](v)
-		if !ok {
+		list, err := cast.CastListToStringList(v)
+		if err != nil {
 			return errors.Errorf("expected string list for parameter %s, got %T", p.Name, v)
 		}
-		value.Set(reflect.ValueOf(list))
+		return reflect2.SetReflectValue(value, list)
 
 	case ParameterTypeDate:
 		strVal, ok := v.(string)
@@ -416,8 +416,8 @@ func (p *ParameterDefinition) CheckValueValidity(v interface{}) error {
 	case ParameterTypeStringFromFiles:
 		fallthrough
 	case ParameterTypeString:
-		_, ok := v.(string)
-		if !ok {
+		_, err := cast.ToString(v)
+		if err != nil {
 			return errors.Errorf("Value for parameter %s is not a string: %v", p.Name, v)
 		}
 
@@ -485,16 +485,16 @@ func (p *ParameterDefinition) CheckValueValidity(v interface{}) error {
 	case ParameterTypeStringListFromFiles:
 		fallthrough
 	case ParameterTypeStringList:
-		_, ok := v.([]string)
-		if !ok {
+		_, err := cast.CastListToStringList(v)
+		if err != nil {
 			v_, ok := v.([]interface{})
 			if !ok {
 				return errors.Errorf("Value for parameter %s is not a string list: %v", p.Name, v)
 			}
 
 			// convert to string list
-			fixedDefault, ok := cast.CastList[string, interface{}](v_)
-			if !ok {
+			fixedDefault, err := cast.CastListToStringList(v_)
+			if err != nil {
 				return errors.Errorf("Value for parameter %s is not a string list: %v", p.Name, v)
 			}
 			_ = fixedDefault
@@ -517,12 +517,12 @@ func (p *ParameterDefinition) CheckValueValidity(v interface{}) error {
 			return errors.Errorf("ParameterDefinition %s is a choice parameter but has no choices", p.Name)
 		}
 
-		v_, ok := v.(string)
-		if !ok {
+		v_, err := cast.ToString(v)
+		if err != nil {
 			return errors.Errorf("Value for parameter %s is not a string: %v", p.Name, v)
 		}
 
-		err := p.checkChoiceValidity(v_)
+		err = p.checkChoiceValidity(v_)
 		if err != nil {
 			return err
 		}
@@ -532,8 +532,8 @@ func (p *ParameterDefinition) CheckValueValidity(v interface{}) error {
 			return errors.Errorf("ParameterDefinition %s is a choice parameter but has no choices", p.Name)
 		}
 
-		v_, ok := cast.CastList2[string, interface{}](v)
-		if !ok {
+		v_, err := cast.CastListToStringList(v)
+		if err != nil {
 			return errors.Errorf("Value for parameter %s is not a string list: %v", p.Name, v)
 		}
 
diff --git a/pkg/cmds/parameters/render.go b/pkg/cmds/parameters/render.go
index ace7e8a..6beff3b 100644
--- a/pkg/cmds/parameters/render.go
+++ b/pkg/cmds/parameters/render.go
@@ -96,8 +96,8 @@ func RenderValue(type_ ParameterType, value interface{}) (string, error) {
 		ParameterTypeStringListFromFile,
 		ParameterTypeStringList,
 		ParameterTypeChoiceList:
-		l, ok := cast.CastList2[string, interface{}](value)
-		if !ok {
+		l, err := cast.CastListToStringList(value)
+		if err != nil {
 			return "", errors.Errorf("expected []string, got %T", value)
 		}
 		return strings.Join(l, ","), nil
diff --git a/pkg/doc/topics/13-layers-and-parsed-layers.md b/pkg/doc/topics/13-layers-and-parsed-layers.md
new file mode 100644
index 0000000..ece8aff
--- /dev/null
+++ b/pkg/doc/topics/13-layers-and-parsed-layers.md
@@ -0,0 +1,418 @@
+---
+Title: Parameter Layers and Parsed Layers
+Slug: parameter-layers-and-parsed-layers
+Short: |
+    Learn how to use parameter layers and parsed layers in Glazed to organize and manage parameter definitions.
+Topics:
+  - layers
+  - middleware
+  - configuration
+Commands:
+Flags:
+IsTopLevel: false
+ShowPerDefault: true
+SectionType: GeneralTopic
+---
+## Parameter Layers
+
+Layers in the glazed package provide a way to group and organize parameter definitions. They allow for better structure
+and modularity in command-line interfaces and other parameter-driven systems.
+
+A layer is a logical grouping of related parameter definitions. It consists of several components:
+1. **Name**: A human-readable name for the layer.
+2. **Slug**: A unique identifier for the layer, used in code.
+3. **Description**: A brief explanation of the layer's purpose.
+4. **Prefix**: An optional prefix for parameter names within the layer.
+5. **Parameter Definitions**: A collection of parameter definitions that belong to this layer.
+
+1. **ParameterLayer**: An interface that groups parameter definitions and provides metadata.
+2. **ParameterLayers**: A collection of ParameterLayer objects.
+
+## Creating and Working with Parameter Layers
+
+The `ParameterLayerImpl` struct provides a straightforward implementation of the
+`ParameterLayer` interface.
+
+### Creating a Parameter Layer
+
+You can create a new parameter layer using the `NewParameterLayer` function:
+
+```go
+layer, err := NewParameterLayer("config", "Configuration",
+    WithDescription("Configuration options for the application"),
+    WithPrefix("config-"),
+    WithParameterDefinitions(
+        parameters.NewParameterDefinition("verbose", parameters.ParameterTypeBool),
+        parameters.NewParameterDefinition("output", parameters.ParameterTypeString),
+    ),
+)
+if err != nil {
+    // Handle error
+}
+```
+
+### Adding Parameters to a Layer
+
+You can add parameters to an existing layer using the `AddFlags` method:
+
+```go
+layer.AddFlags(
+    parameters.NewParameterDefinition("log-level", parameters.ParameterTypeString),
+    parameters.NewParameterDefinition("max-retries", parameters.ParameterTypeInteger),
+)
+```
+
+### Initializing Parameter Defaults from a Struct
+
+You can initialize the default values of parameters in a layer using a struct:
+
+```go
+type Config struct {
+    Verbose bool   `glazed.parameter:"verbose"`
+    Output  string `glazed.parameter:"output"`
+    LogLevel string `glazed.parameter:"log-level"`
+    MaxRetries int `glazed.parameter:"max-retries"`
+}
+
+defaultConfig := Config{
+    Verbose: true,
+    Output: "stdout",
+    LogLevel: "info",
+    MaxRetries: 3,
+}
+
+err := layer.InitializeParameterDefaultsFromStruct(&defaultConfig)
+if err != nil {
+    // Handle error
+}
+```
+
+### Initializing Parameter Defaults from a Map
+
+Alternatively, you can initialize defaults using a map:
+
+```go
+defaultValues := map[string]interface{}{
+    "verbose": true,
+    "output": "stdout",
+    "log-level": "info",
+    "max-retries": 3,
+}
+
+err := layer.InitializeParameterDefaultsFromParameters(defaultValues)
+if err != nil {
+    // Handle error
+}
+```
+
+### Initializing a Struct from Parameter Defaults
+
+You can also populate a struct with the default values from the parameter layer:
+
+```go
+var config Config
+err := layer.InitializeStructFromParameterDefaults(&config)
+if err != nil {
+    // Handle error
+}
+```
+
+### Loading a Parameter Layer from YAML
+
+You can create a parameter layer from a YAML definition:
+
+```go
+yamlContent := []byte(`
+name: Configuration
+slug: config
+description: Configuration options for the application
+flags:
+  - name: verbose
+    type: bool
+    help: Enable verbose output
+  - name: output
+    type: string
+    help: Output destination
+`)
+
+layer, err := NewParameterLayerFromYAML(yamlContent)
+if err != nil {
+    // Handle error
+}
+```
+
+### Cloning a Parameter Layer
+
+To create a deep copy of a parameter layer:
+
+```go
+clonedLayer := layer.Clone()
+```
+
+### Creating ParameterLayers
+
+```go
+layers := NewParameterLayers(
+    WithLayers(configLayer, outputLayer),
+)
+```
+
+### Accessing Layer Information
+
+```go
+name := layer.GetName()
+slug := layer.GetSlug()
+description := layer.GetDescription()
+```
+
+### ForEach and ForEachE
+
+Iterate over all parameter layers:
+
+```go
+parameterLayers.ForEach(func(key string, p ParameterLayer) {
+    // Process each layer
+})
+
+err := parameterLayers.ForEachE(func(key string, p ParameterLayer) error {
+    // Process each layer, return error to stop iteration
+    return nil
+})
+```
+
+### Subset
+
+Create a new ParameterLayers containing only the specified layers:
+
+```go
+subset := parameterLayers.Subset("config", "output")
+```
+
+### AppendLayers and PrependLayers
+
+Add layers to the end or beginning of the collection:
+
+```go
+parameterLayers.AppendLayers(newLayer1, newLayer2)
+parameterLayers.PrependLayers(newLayer3, newLayer4)
+```
+
+### Merge
+
+Merge two ParameterLayers collections:
+
+```go
+mergedLayers := parameterLayers.Merge(otherParameterLayers)
+```
+
+### Clone
+
+Create a deep copy of ParameterLayers:
+
+```go
+clonedParameterLayers := parameterLayers.Clone()
+```
+
+### GetAllParameterDefinitions
+
+Get all parameter definitions across all layers:
+
+```go
+allDefinitions := parameterLayers.GetAllParameterDefinitions()
+```
+
+## Parsed Layers
+
+A ParsedLayer is the result of parsing input data (such as command-line
+arguments, configuration files, or environment variables) using a ParameterLayer
+specification. It consists of:
+
+1. **Layer**: A reference to the original ParameterLayer used for parsing.
+2. **Parameters**: A collection of ParsedParameter objects, each containing:
+    - The original ParameterDefinition
+    - The parsed value
+    - Metadata about how the value was parsed (e.g., source, parse steps)
+
+ParsedLayers is a collection of ParsedLayer objects, typically representing all the layers used in a command or application.
+
+### Usage of ParsedLayers
+
+ParsedLayers are primarily used to:
+
+1. Store and organize parsed parameter values
+2. Access parsed values across different layers
+3. Initialize structs with parsed values
+4. Merge parsed values from different sources
+5. Provide a unified interface for accessing all parsed parameters in an application
+
+
+### Creating a ParsedLayer
+
+```go
+parsedLayer, err := NewParsedLayer(layer,
+    WithParsedParameterValue("verbose", true),
+)
+if err != nil {
+    // Handle error
+}
+```
+
+### Creating ParsedLayers
+
+```go
+parsedLayers := NewParsedLayers(
+    WithParsedLayer("config", parsedConfigLayer),
+    WithParsedLayer("output", parsedOutputLayer),
+)
+```
+
+### Accessing Parsed Values
+
+```go
+value, ok := parsedLayer.GetParameter("verbose")
+if !ok {
+    // Parameter not found
+}
+```
+
+### Initializing Structs from ParsedLayers
+
+```go
+type Config struct {
+    Verbose bool   `glazed.parameter:"verbose"`
+    Output  string `glazed.parameter:"output"`
+}
+
+var config Config
+err := parsedLayers.InitializeStruct("config", &config)
+if err != nil {
+    // Handle error
+}
+```
+
+### Merging ParsedLayers
+
+```go
+parsedLayers.GetDefaultParameterLayer().MergeParameters(otherParsedLayer)
+```
+
+### Getting All Parsed Parameters
+
+```go
+allParams := parsedLayers.GetAllParsedParameters()
+```
+
+
+### ForEach and ForEachE
+
+Iterate over all parsed layers:
+
+```go
+parsedLayers.ForEach(func(k string, v *ParsedLayer) {
+    // Process each layer
+})
+
+err := parsedLayers.ForEachE(func(k string, v *ParsedLayer) error {
+    // Process each layer, return error to stop iteration
+    return nil
+})
+```
+
+### GetDataMap
+
+Get a map of all parameter values across all layers:
+
+```go
+dataMap := parsedLayers.GetDataMap()
+```
+
+### GetOrCreate
+
+Get an existing ParsedLayer or create a new one if it doesn't exist:
+
+```go
+parsedLayer := parsedLayers.GetOrCreate(someParameterLayer)
+```
+
+### Clone
+
+Create a deep copy of ParsedLayers:
+
+```go
+clonedParsedLayers := parsedLayers.Clone()
+```
+
+
+## Real-world Usage Example
+
+Here's an example of how layers are used in a real-world scenario:
+
+```go
+package repo
+
+import (
+    "context"
+    cmds2 "github.com/go-go-golems/clay/pkg/cmds"
+    "github.com/go-go-golems/clay/pkg/repositories"
+    "github.com/go-go-golems/glazed/pkg/cmds"
+    "github.com/go-go-golems/glazed/pkg/cmds/layers"
+    "github.com/go-go-golems/glazed/pkg/cmds/parameters"
+    "github.com/go-go-golems/glazed/pkg/middlewares"
+    "github.com/go-go-golems/glazed/pkg/settings"
+)
+
+type ListCommand struct {
+    *cmds.CommandDescription
+}
+
+func NewListCommand(options ...cmds.CommandDescriptionOption) (*ListCommand, error) {
+    glazeParameterLayer, err := settings.NewGlazedParameterLayers()
+    if err != nil {
+        return nil, err
+    }
+    
+    options = append(options,
+        cmds.WithShort("Import a command directory or individual files into a database"),
+        cmds.WithFlags(),
+        cmds.WithArguments(
+            parameters.NewParameterDefinition(
+                "inputs",
+                parameters.ParameterTypeStringList,
+                parameters.WithHelp("The command directory or individual files to import"),
+                parameters.WithRequired(true),
+            ),
+        ),
+        cmds.WithLayersList(glazeParameterLayer),
+    )
+    
+    return &ListCommand{
+        CommandDescription: cmds.NewCommandDescription("list", options...),
+    }, nil
+}
+
+type ListSettings struct {
+    Inputs []string `glazed.parameter:"inputs"`
+}
+
+func (c *ListCommand) RunIntoGlazeProcessor(ctx context.Context, parsedLayers *layers.ParsedLayers, gp middlewares.Processor) error {
+    s := &ListSettings{}
+    d := parsedLayers.GetDefaultParameterLayer()
+    err := d.InitializeStruct(s)
+    if err != nil {
+        return err
+    }
+    
+    // Use the parsed parameters
+    commands, err := repositories.LoadCommandsFromInputs(cmds2.NewRawCommandLoader(), s.Inputs)
+    if err != nil {
+        return err
+    }
+    
+    err2 := cmds2.ListCommandsIntoProcessor(ctx, commands, gp)
+    if err2 != nil {
+        return err2
+    }
+    
+    return nil
+}
+```
diff --git a/pkg/helpers/cast/cast.go b/pkg/helpers/cast/cast.go
index 5b8b0da..ad3e53d 100644
--- a/pkg/helpers/cast/cast.go
+++ b/pkg/helpers/cast/cast.go
@@ -294,54 +294,6 @@ func CastInterfaceToFloatList[To FloatNumber](i interface{}) ([]To, bool) {
 	}
 }
 
-func CastStringMap2[To any, From any](m interface{}) (map[string]To, bool) {
-	casted, ok := m.(map[string]From)
-	if !ok {
-		// try to cast to map[string]interface{}
-		casted2, ok := m.(map[string]interface{})
-		if !ok {
-			return map[string]To{}, false
-		}
-		return CastStringMap[To, interface{}](casted2)
-	}
-
-	return CastStringMap[To, From](casted)
-}
-
-func CastMapMember[To any](m map[string]interface{}, k string) (*To, bool) {
-	v, ok := m[k]
-	if !ok {
-		return nil, false
-	}
-
-	casted, ok := v.(To)
-	if !ok {
-		return nil, false
-	}
-
-	return &casted, true
-}
-
-func GetAndCast[T any](ps map[string]interface{}, name string, default_ T) (T, bool, error) {
-	if val, ok := ps[name]; ok {
-		if castedVal, ok := val.(T); ok {
-			return castedVal, true, nil
-		}
-		return default_, false, errors.Errorf("could not cast %s to %T", name, val)
-	}
-	return default_, false, nil
-}
-
-func GetAndCastPtr[T any](ps map[string]interface{}, name string, default_ *T) (*T, bool, error) {
-	if val, ok := ps[name]; ok {
-		if castedVal, ok := val.(T); ok {
-			return &castedVal, true, nil
-		}
-		return default_, true, errors.Errorf("could not cast %s to %T", name, val)
-	}
-	return default_, false, nil
-}
-
 func InterfaceAddr[T any](t T) *interface{} {
 	t_ := interface{}(t)
 	return &t_
diff --git a/pkg/helpers/cast/string.go b/pkg/helpers/cast/string.go
new file mode 100644
index 0000000..5498ea7
--- /dev/null
+++ b/pkg/helpers/cast/string.go
@@ -0,0 +1,66 @@
+package cast
+
+import (
+	"fmt"
+	"reflect"
+)
+
+// ToString converts a value to a string using reflection.
+// It handles both type aliases and type declarations based on string.
+//
+// This function is useful for dynamically converting values to strings
+// at runtime, especially when dealing with types that may not be known
+// at compile time.
+func ToString(value interface{}) (string, error) {
+	v := reflect.ValueOf(value)
+	t := reflect.TypeOf(value)
+
+	// Check if the kind is string
+	if v.Kind() == reflect.String {
+		return v.String(), nil
+	}
+
+	// Check if the underlying type is string
+	if t.Kind() == reflect.String {
+		return v.Convert(reflect.TypeOf("")).String(), nil
+	}
+
+	return "", fmt.Errorf("cannot convert %v to string", t)
+}
+
+// CastListToStringList casts a list of items to a list of strings.
+// It handles both string aliases and string declarations.
+func CastListToStringList(list interface{}) ([]string, error) {
+	val := reflect.ValueOf(list)
+
+	// Check if the value is a slice or array
+	if val.Kind() != reflect.Slice && val.Kind() != reflect.Array {
+		return nil, fmt.Errorf("the provided value is not a list")
+	}
+
+	elemKind := val.Type().Elem().Kind()
+	if elemKind != reflect.String && elemKind != reflect.Interface {
+		return nil, fmt.Errorf("the list does not contain strings")
+	}
+
+	result := make([]string, val.Len())
+	for i := 0; i < val.Len(); i++ {
+		str, err := ToString(val.Index(i).Interface())
+		if err != nil {
+			return nil, err
+		}
+		result[i] = str
+	}
+
+	return result, nil
+}
+
+// CastStringListToList casts a list of strings to a list of a specified type T.
+// The target type T must be a string alias or string declaration.
+func CastStringListToList[T ~string](list []string) ([]T, error) {
+	result := make([]T, len(list))
+	for i, str := range list {
+		result[i] = T(str)
+	}
+	return result, nil
+}
diff --git a/pkg/helpers/reflect/reflect.go b/pkg/helpers/reflect/reflect.go
index 997a442..115e412 100644
--- a/pkg/helpers/reflect/reflect.go
+++ b/pkg/helpers/reflect/reflect.go
@@ -7,6 +7,10 @@ import (
 	"strconv"
 )
 
+// NOTE(manuel, 2024-07-03) This is quite a mess of a function and I'm not even entirely sure
+// what it's purpose is, and what the src can be (it tries to handle *interface{} but doesn't seem to handle
+// other point values that easily?
+
 func SetReflectValue(dst reflect.Value, src interface{}) error {
 	kind := dst.Kind()
 	if !dst.IsValid() {
@@ -25,10 +29,21 @@ func SetReflectValue(dst reflect.Value, src interface{}) error {
 		//exhaustive:ignore
 		switch kind {
 		case reflect.String:
-			if s, ok := src.(string); ok {
-				dst.SetString(s)
+			srcValue := reflect.ValueOf(src)
+			srcKind := srcValue.Kind()
+
+			assignableToString := srcValue.Type().AssignableTo(reflect.TypeOf(""))
+
+			if srcKind == reflect.String || (srcKind == reflect.Ptr && srcValue.Elem().Kind() == reflect.String) {
+				dst.SetString(srcValue.String())
+				return nil
+			}
+
+			if assignableToString {
+				dst.Set(srcValue)
 				return nil
 			}
+
 			return errors.Errorf("cannot set reflect.Value of type %s from %T", kind, src)
 
 		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
@@ -192,33 +207,35 @@ func SetReflectValue(dst reflect.Value, src interface{}) error {
 			return errors.Errorf("cannot set reflect.Value of type %s from %T", kind, src)
 		case reflect.Slice:
 			//exhaustive:ignore
-			sliceKind := dst.Type().Elem().Kind()
+			dstElementKind := dst.Type().Elem().Kind()
 			//exhaustive:ignore
-			switch sliceKind {
+			switch dstElementKind {
 			case reflect.String:
-				if s, ok := src.([]string); ok {
-					dst.Set(reflect.ValueOf(s))
-					return nil
+				s, err := cast.CastListToStringList(src)
+				if err != nil {
+					return errors.Errorf("cannot cast %T to []string", src)
 				}
-				if s, ok := src.([]interface{}); ok {
-					v2_, ok := cast.CastList[string, interface{}](s)
-					if !ok {
-						return errors.Errorf("cannot cast %T to []string", src)
-					}
-					dst.Set(reflect.ValueOf(v2_))
+
+				// Get the type of the target slice elements
+				targetElemType := dst.Type().Elem()
+
+				// Get the type of the source slice elements
+				sourceElemType := reflect.TypeOf(src).Elem()
+
+				// Check if the source slice is assignable to the target slice
+				if reflect.TypeOf(s).AssignableTo(dst.Type()) {
+					// Direct assignment is possible
+					dst.Set(reflect.ValueOf(s))
 					return nil
 				}
 
-				if s, ok := src.(*interface{}); ok {
-					s_, ok := (*s).([]interface{})
-					if !ok {
-						return errors.Errorf("cannot cast %T to []string", src)
+				if sourceElemType.Kind() == dstElementKind {
+					// Direct assignment is not possible, perform type conversion
+					newSlice := reflect.MakeSlice(dst.Type(), len(s), len(s))
+					for i, s := range s {
+						newSlice.Index(i).Set(reflect.ValueOf(s).Convert(targetElemType))
 					}
-					v2_, ok := cast.CastList[string, interface{}](s_)
-					if !ok {
-						return errors.Errorf("cannot cast %T to []string", src)
-					}
-					dst.Set(reflect.ValueOf(v2_))
+					dst.Set(newSlice)
 					return nil
 				}
 
@@ -340,6 +357,11 @@ func SetReflectValue(dst reflect.Value, src interface{}) error {
 	if err != nil {
 		// try again, checking if src is an *interface{} and unwrapping that
 		if i, ok := src.(*interface{}); ok {
+			// if i == nil, we can't do anything
+			if i == nil {
+				return nil
+			}
+
 			src = *i
 			err = setValue(src)
 			if err != nil {
diff --git a/pkg/settings/settings_rename.go b/pkg/settings/settings_rename.go
index c0a81d4..f842ae6 100644
--- a/pkg/settings/settings_rename.go
+++ b/pkg/settings/settings_rename.go
@@ -82,8 +82,8 @@ func NewRenameSettingsFromParameters(glazedLayer *layers.ParsedLayer) (*RenameSe
 		}, nil
 	}
 
-	renameFields, ok := cast.CastList2[string, interface{}](rename)
-	if !ok {
+	renameFields, err := cast.CastListToStringList(rename)
+	if err != nil {
 		return nil, errors.Errorf("Invalid rename fields %s", rename)
 	}
 	renamesFieldsMap := map[types.FieldName]types.FieldName{}


Test patch:
diff --git a/pkg/cmds/layers/layer_test.go b/pkg/cmds/layers/layer_test.go
new file mode 100644
index 0000000..187168c
--- /dev/null
+++ b/pkg/cmds/layers/layer_test.go
@@ -0,0 +1,286 @@
+package layers
+
+import (
+	"fmt"
+	"github.com/go-go-golems/glazed/pkg/cmds/parameters"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+	"testing"
+)
+
+// Helper function to create a parameter layer
+func createParameterLayer(t *testing.T, slug, name string, paramDefs ...*parameters.ParameterDefinition) ParameterLayer {
+	layer, err := NewParameterLayer(slug, name, WithParameterDefinitions(paramDefs...))
+	require.NoError(t, err)
+	require.NotNil(t, layer)
+	return layer
+}
+
+// Helper function to create a parsed layer
+func createParsedLayer(t *testing.T, layer ParameterLayer, parsedValues map[string]interface{}) *ParsedLayer {
+	options := make([]ParsedLayerOption, 0, len(parsedValues))
+	for key, value := range parsedValues {
+		options = append(options, WithParsedParameterValue(key, value))
+	}
+	parsedLayer, err := NewParsedLayer(layer, options...)
+	require.NoError(t, err)
+	require.NotNil(t, parsedLayer)
+	return parsedLayer
+}
+
+func TestNewParameterLayers(t *testing.T) {
+	layers := NewParameterLayers()
+	assert.NotNil(t, layers)
+	assert.Equal(t, 0, layers.Len())
+}
+
+func TestParameterLayersSubset(t *testing.T) {
+	layer1 := createParameterLayer(t, "layer1", "Layer 1")
+	layer2 := createParameterLayer(t, "layer2", "Layer 2")
+	layer3 := createParameterLayer(t, "layer3", "Layer 3")
+
+	layers := NewParameterLayers(WithLayers(layer1, layer2, layer3))
+
+	subset := layers.Subset("layer1", "layer3")
+
+	assert.Equal(t, 2, subset.Len())
+	val, present := subset.Get("layer1")
+	assert.NotNil(t, val)
+	assert.True(t, present)
+	val, present = subset.Get("layer2")
+	assert.Nil(t, val)
+	assert.False(t, present)
+	val, present = subset.Get("layer3")
+	assert.NotNil(t, val)
+	assert.True(t, present)
+}
+
+func TestParameterLayersForEach(t *testing.T) {
+	layer1 := createParameterLayer(t, "layer1", "Layer 1")
+	layer2 := createParameterLayer(t, "layer2", "Layer 2")
+
+	layers := NewParameterLayers(WithLayers(layer1, layer2))
+
+	count := 0
+	layers.ForEach(func(key string, p ParameterLayer) {
+		count++
+		assert.Contains(t, []string{"layer1", "layer2"}, key)
+	})
+
+	assert.Equal(t, 2, count)
+}
+
+func TestParameterLayersForEachE(t *testing.T) {
+	layer1 := createParameterLayer(t, "layer1", "Layer 1")
+	layer2 := createParameterLayer(t, "layer2", "Layer 2")
+
+	layers := NewParameterLayers(WithLayers(layer1, layer2))
+
+	count := 0
+	err := layers.ForEachE(func(key string, p ParameterLayer) error {
+		count++
+		return nil
+	})
+
+	assert.NoError(t, err)
+	assert.Equal(t, 2, count)
+}
+
+func TestParameterLayersAppendLayers(t *testing.T) {
+	layers := NewParameterLayers()
+	layer1 := createParameterLayer(t, "layer1", "Layer 1")
+	layer2 := createParameterLayer(t, "layer2", "Layer 2")
+
+	layers.AppendLayers(layer1, layer2)
+
+	assert.Equal(t, 2, layers.Len())
+	val, present := layers.Get("layer1")
+	assert.Equal(t, layer1, val)
+	assert.True(t, present)
+	val, present = layers.Get("layer2")
+	assert.Equal(t, layer2, val)
+	assert.True(t, present)
+}
+
+func TestParameterLayersPrependLayers(t *testing.T) {
+	layer0 := createParameterLayer(t, "layer0", "Layer 0")
+
+	layers := NewParameterLayers(
+		WithLayers(layer0),
+	)
+	layer1 := createParameterLayer(t, "layer1", "Layer 1")
+	layer2 := createParameterLayer(t, "layer2", "Layer 2")
+
+	layers.PrependLayers(layer1, layer2)
+
+	assert.Equal(t, 3, layers.Len())
+	first := layers.Oldest()
+	assert.Equal(t, "layer1", first.Key)
+	assert.Equal(t, layer1, first.Value)
+	second := first.Next()
+	assert.Equal(t, "layer2", second.Key)
+	assert.Equal(t, layer2, second.Value)
+	third := second.Next()
+	assert.Equal(t, "layer0", third.Key)
+	assert.Equal(t, "Layer 0", third.Value.GetName())
+	assert.Nil(t, third.Next())
+}
+
+func TestParameterLayersMerge(t *testing.T) {
+	layer1 := createParameterLayer(t, "layer1", "Layer 1")
+	layer2 := createParameterLayer(t, "layer2", "Layer 2")
+	layers1 := NewParameterLayers(WithLayers(layer1))
+	layers2 := NewParameterLayers(WithLayers(layer2))
+
+	merged := layers1.Merge(layers2)
+
+	assert.Equal(t, 2, merged.Len())
+	val, present := merged.Get("layer1")
+	assert.NotNil(t, val)
+	assert.True(t, present)
+	val, present = merged.Get("layer2")
+	assert.True(t, present)
+	assert.NotNil(t, val)
+}
+
+func TestParameterLayersAsList(t *testing.T) {
+	layer1 := createParameterLayer(t, "layer1", "Layer 1")
+	layer2 := createParameterLayer(t, "layer2", "Layer 2")
+	layers := NewParameterLayers(WithLayers(layer1, layer2))
+
+	list := layers.AsList()
+
+	assert.Equal(t, 2, len(list))
+	assert.Contains(t, list, layer1)
+	assert.Contains(t, list, layer2)
+}
+
+func TestParameterLayersClone(t *testing.T) {
+	layer1 := createParameterLayer(t, "layer1", "Layer 1")
+	layers := NewParameterLayers(WithLayers(layer1))
+
+	cloned := layers.Clone()
+
+	assert.Equal(t, layers.Len(), cloned.Len())
+	v1, p1 := layers.Get("layer1")
+	assert.True(t, p1)
+	assert.NotNil(t, v1)
+	v2, p2 := cloned.Get("layer1")
+	assert.True(t, p2)
+	assert.NotNil(t, v2)
+	assert.NotSame(t, v1, v2)
+	assert.Equal(t, v1.GetSlug(), v2.GetSlug())
+}
+
+func TestParameterLayersGetAllParameterDefinitions(t *testing.T) {
+	layer1 := createParameterLayer(t, "layer1", "Layer 1",
+		parameters.NewParameterDefinition("param1", parameters.ParameterTypeString),
+	)
+	layer2 := createParameterLayer(t, "layer2", "Layer 2",
+		parameters.NewParameterDefinition("param2", parameters.ParameterTypeInteger),
+	)
+
+	layers := NewParameterLayers(WithLayers(layer1, layer2))
+
+	allDefs := layers.GetAllParameterDefinitions()
+
+	assert.Equal(t, 2, allDefs.Len())
+	val, present := allDefs.Get("param1")
+	assert.True(t, present)
+	assert.NotNil(t, val)
+	val, present = allDefs.Get("param2")
+	assert.True(t, present)
+	assert.NotNil(t, val)
+}
+
+func TestParameterLayersWithLayers(t *testing.T) {
+	layer1 := createParameterLayer(t, "layer1", "Layer 1")
+	layer2 := createParameterLayer(t, "layer2", "Layer 2")
+
+	layers := NewParameterLayers(WithLayers(layer1, layer2))
+
+	assert.Equal(t, 2, layers.Len())
+	val, present := layers.Get("layer1")
+	assert.True(t, present)
+	assert.Equal(t, layer1, val)
+	val, present = layers.Get("layer2")
+	assert.True(t, present)
+	assert.Equal(t, layer2, val)
+}
+
+func TestParameterLayersWithDuplicateSlugs(t *testing.T) {
+	layer1 := createParameterLayer(t, "duplicate", "Layer 1")
+	layer2 := createParameterLayer(t, "duplicate", "Layer 2")
+
+	layers := NewParameterLayers(WithLayers(layer1, layer2))
+
+	assert.Equal(t, 1, layers.Len())
+	val, present := layers.Get("duplicate")
+	assert.True(t, present)
+	assert.Equal(t, "Layer 2", val.GetName())
+}
+
+func TestParameterLayersSubsetWithNonExistentLayers(t *testing.T) {
+	layer1 := createParameterLayer(t, "layer1", "Layer 1")
+	layers := NewParameterLayers(WithLayers(layer1))
+
+	subset := layers.Subset("layer1", "non_existent")
+
+	assert.Equal(t, 1, subset.Len())
+	_, present := subset.Get("layer1")
+	assert.True(t, present)
+	_, present = subset.Get("non_existent")
+	assert.False(t, present)
+}
+
+func TestParameterLayersMergeWithOverlappingLayers(t *testing.T) {
+	layer1 := createParameterLayer(t, "layer1", "Layer 1 - Original")
+	layer2 := createParameterLayer(t, "layer2", "Layer 2")
+	layers1 := NewParameterLayers(WithLayers(layer1, layer2))
+
+	layer1Duplicate := createParameterLayer(t, "layer1", "Layer 1 - Duplicate")
+	layer3 := createParameterLayer(t, "layer3", "Layer 3")
+	layers2 := NewParameterLayers(WithLayers(layer1Duplicate, layer3))
+
+	merged := layers1.Merge(layers2)
+
+	assert.Equal(t, 3, merged.Len())
+	val, present := merged.Get("layer1")
+	assert.True(t, present)
+	assert.Equal(t, "Layer 1 - Duplicate", val.GetName())
+	_, present = merged.Get("layer2")
+	assert.True(t, present)
+	_, present = merged.Get("layer3")
+	assert.True(t, present)
+}
+
+func TestParameterLayersWithLargeNumberOfLayers(t *testing.T) {
+	numLayers := 1000
+	layers := NewParameterLayers()
+
+	for i := 0; i < numLayers; i++ {
+		layer := createParameterLayer(t, fmt.Sprintf("layer%d", i), fmt.Sprintf("Layer %d", i))
+		layers.AppendLayers(layer)
+	}
+
+	assert.Equal(t, numLayers, layers.Len())
+	_, present := layers.Get("layer0")
+	assert.True(t, present)
+	_, present = layers.Get(fmt.Sprintf("layer%d", numLayers-1))
+	assert.True(t, present)
+}
+
+func TestParameterLayersWithUnicodeLayerNames(t *testing.T) {
+	layer1 := createParameterLayer(t, "layer1", "Layer 1 - 你好")
+	layer2 := createParameterLayer(t, "layer2", "Layer 2 - こんにちは")
+
+	layers := NewParameterLayers(WithLayers(layer1, layer2))
+
+	assert.Equal(t, 2, layers.Len())
+	val, present := layers.Get("layer1")
+	assert.True(t, present)
+	assert.Equal(t, "Layer 1 - 你好", val.GetName())
+	val, present = layers.Get("layer2")
+	assert.True(t, present)
+	assert.Equal(t, "Layer 2 - こんにちは", val.GetName())
+}
diff --git a/pkg/cmds/layers/parsed-layer_test.go b/pkg/cmds/layers/parsed-layer_test.go
new file mode 100644
index 0000000..22e40e6
--- /dev/null
+++ b/pkg/cmds/layers/parsed-layer_test.go
@@ -0,0 +1,421 @@
+package layers
+
+import (
+	"github.com/go-go-golems/glazed/pkg/cmds/parameters"
+	"github.com/pkg/errors"
+	"github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func TestNewParsedLayers(t *testing.T) {
+	parsedLayers := NewParsedLayers()
+	assert.NotNil(t, parsedLayers)
+	assert.Equal(t, 0, parsedLayers.Len())
+}
+
+func TestParsedLayersWithParsedLayer(t *testing.T) {
+	layer := createParameterLayer(t, "test", "Test Layer")
+	parsedLayer := createParsedLayer(t, layer, nil)
+
+	parsedLayers := NewParsedLayers(WithParsedLayer("test", parsedLayer))
+
+	assert.Equal(t, 1, parsedLayers.Len())
+	val, present := parsedLayers.Get("test")
+	assert.True(t, present)
+	assert.Equal(t, parsedLayer, val)
+}
+
+func TestParsedLayersClone(t *testing.T) {
+	layer := createParameterLayer(t, "test", "Test Layer")
+	parsedLayer := createParsedLayer(t, layer, nil)
+	parsedLayers := NewParsedLayers(WithParsedLayer("test", parsedLayer))
+
+	cloned := parsedLayers.Clone()
+
+	assert.Equal(t, parsedLayers.Len(), cloned.Len())
+	originalVal, _ := parsedLayers.Get("test")
+	clonedVal, present := cloned.Get("test")
+	assert.True(t, present)
+	assert.NotSame(t, originalVal, clonedVal)
+	assert.Equal(t, originalVal.Layer, clonedVal.Layer)
+}
+
+func TestParsedLayersGetOrCreate(t *testing.T) {
+	parsedLayers := NewParsedLayers()
+	layer := createParameterLayer(t, "test", "Test Layer")
+
+	// Get non-existent layer (should create)
+	parsedLayer := parsedLayers.GetOrCreate(layer)
+	assert.NotNil(t, parsedLayer)
+	assert.Equal(t, layer, parsedLayer.Layer)
+
+	// Get existing layer
+	sameLayer := parsedLayers.GetOrCreate(layer)
+	assert.Equal(t, parsedLayer, sameLayer)
+}
+
+func TestParsedLayersGetDataMap(t *testing.T) {
+	layer1 := createParameterLayer(t, "layer1", "Layer 1",
+		parameters.NewParameterDefinition("param1", parameters.ParameterTypeString),
+	)
+	parsedLayer1 := createParsedLayer(t, layer1, map[string]interface{}{"param1": "value1"})
+
+	layer2 := createParameterLayer(t, "layer2", "Layer 2",
+		parameters.NewParameterDefinition("param2", parameters.ParameterTypeInteger),
+	)
+	parsedLayer2 := createParsedLayer(t, layer2, map[string]interface{}{"param2": 42})
+
+	parsedLayers := NewParsedLayers(
+		WithParsedLayer("layer1", parsedLayer1),
+		WithParsedLayer("layer2", parsedLayer2),
+	)
+
+	dataMap := parsedLayers.GetDataMap()
+	assert.Equal(t, 2, len(dataMap))
+	assert.Equal(t, "value1", dataMap["param1"])
+	assert.Equal(t, 42, dataMap["param2"])
+}
+
+func TestParsedLayersInitializeStruct(t *testing.T) {
+	type TestStruct struct {
+		Param1 string `glazed.parameter:"param1"`
+		Param2 int    `glazed.parameter:"param2"`
+	}
+
+	layer := createParameterLayer(t, "test", "Test Layer",
+		parameters.NewParameterDefinition("param1", parameters.ParameterTypeString),
+		parameters.NewParameterDefinition("param2", parameters.ParameterTypeInteger),
+	)
+	parsedLayer := createParsedLayer(t, layer, map[string]interface{}{
+		"param1": "value1",
+		"param2": 42,
+	})
+	parsedLayers := NewParsedLayers(WithParsedLayer("test", parsedLayer))
+
+	var result TestStruct
+	err := parsedLayers.InitializeStruct("test", &result)
+	assert.NoError(t, err)
+	assert.Equal(t, "value1", result.Param1)
+	assert.Equal(t, 42, result.Param2)
+}
+
+func TestParsedLayersGetAllParsedParameters(t *testing.T) {
+	layer1 := createParameterLayer(t, "layer1", "Layer 1",
+		parameters.NewParameterDefinition("param1", parameters.ParameterTypeString),
+	)
+	parsedLayer1 := createParsedLayer(t, layer1, map[string]interface{}{"param1": "value1"})
+
+	layer2 := createParameterLayer(t, "layer2", "Layer 2",
+		parameters.NewParameterDefinition("param2", parameters.ParameterTypeInteger),
+	)
+	parsedLayer2 := createParsedLayer(t, layer2, map[string]interface{}{"param2": 42})
+
+	parsedLayers := NewParsedLayers(
+		WithParsedLayer("layer1", parsedLayer1),
+		WithParsedLayer("layer2", parsedLayer2),
+	)
+
+	allParams := parsedLayers.GetAllParsedParameters()
+	assert.Equal(t, 2, allParams.Len())
+	param1, present := allParams.Get("param1")
+	assert.True(t, present)
+	assert.Equal(t, "value1", param1.Value)
+	param2, present := allParams.Get("param2")
+	assert.True(t, present)
+	assert.Equal(t, 42, param2.Value)
+}
+
+func TestParsedLayersGetParameter(t *testing.T) {
+	layer := createParameterLayer(t, "test", "Test Layer",
+		parameters.NewParameterDefinition("param", parameters.ParameterTypeString),
+	)
+	parsedLayer := createParsedLayer(t, layer, map[string]interface{}{"param": "value"})
+	parsedLayers := NewParsedLayers(WithParsedLayer("test", parsedLayer))
+
+	param, present := parsedLayers.GetParameter("test", "param")
+	assert.True(t, present)
+	assert.Equal(t, "value", param.Value)
+
+	_, present = parsedLayers.GetParameter("non_existent", "param")
+	assert.False(t, present)
+
+	_, present = parsedLayers.GetParameter("test", "non_existent")
+	assert.False(t, present)
+}
+
+func TestParsedLayersGetDefaultParameterLayer(t *testing.T) {
+	parsedLayers := NewParsedLayers()
+
+	defaultLayer := parsedLayers.GetDefaultParameterLayer()
+	assert.NotNil(t, defaultLayer)
+	assert.Equal(t, DefaultSlug, defaultLayer.Layer.GetSlug())
+
+	// Calling it again should return the same layer
+	sameDefaultLayer := parsedLayers.GetDefaultParameterLayer()
+	assert.Equal(t, defaultLayer, sameDefaultLayer)
+}
+
+func TestParsedLayersForEach(t *testing.T) {
+	layer1 := createParameterLayer(t, "layer1", "Layer 1")
+	parsedLayer1 := createParsedLayer(t, layer1, nil)
+
+	layer2 := createParameterLayer(t, "layer2", "Layer 2")
+	parsedLayer2 := createParsedLayer(t, layer2, nil)
+
+	parsedLayers := NewParsedLayers(
+		WithParsedLayer("layer1", parsedLayer1),
+		WithParsedLayer("layer2", parsedLayer2),
+	)
+
+	count := 0
+	parsedLayers.ForEach(func(k string, v *ParsedLayer) {
+		count++
+		assert.Contains(t, []string{"layer1", "layer2"}, k)
+	})
+	assert.Equal(t, 2, count)
+}
+
+func TestParsedLayersForEachE(t *testing.T) {
+	layer1 := createParameterLayer(t, "layer1", "Layer 1")
+	parsedLayer1 := createParsedLayer(t, layer1, nil)
+
+	layer2 := createParameterLayer(t, "layer2", "Layer 2")
+	parsedLayer2 := createParsedLayer(t, layer2, nil)
+
+	parsedLayers := NewParsedLayers(
+		WithParsedLayer("layer1", parsedLayer1),
+		WithParsedLayer("layer2", parsedLayer2),
+	)
+
+	count := 0
+	err := parsedLayers.ForEachE(func(k string, v *ParsedLayer) error {
+		count++
+		return nil
+	})
+	assert.NoError(t, err)
+	assert.Equal(t, 2, count)
+
+	// Test with error
+	errorOnSecond := parsedLayers.ForEachE(func(k string, v *ParsedLayer) error {
+		if k == "layer2" {
+			return assert.AnError
+		}
+		return nil
+	})
+	assert.Error(t, errorOnSecond)
+}
+
+func TestParsedLayerInitializeStructWithUnexportedFields(t *testing.T) {
+	layer := createParameterLayer(t, "test", "Test Layer",
+		parameters.NewParameterDefinition("exported", parameters.ParameterTypeString),
+	)
+	parsedLayer := createParsedLayer(t, layer, map[string]interface{}{"exported": "value"})
+
+	type TestStruct struct {
+		Exported   string `glazed.parameter:"exported"`
+		unexported string
+	}
+
+	result := TestStruct{
+		unexported: "unexported",
+	}
+	err := parsedLayer.InitializeStruct(&result)
+	assert.NoError(t, err)
+	assert.Equal(t, "value", result.Exported)
+	assert.Equal(t, "unexported", result.unexported)
+
+}
+
+func TestParsedLayersInitializeStructWithNonPointer(t *testing.T) {
+	parsedLayers := NewParsedLayers()
+	layer := createParameterLayer(t, "test", "Test Layer",
+		parameters.NewParameterDefinition("param", parameters.ParameterTypeString),
+	)
+	parsedLayer := createParsedLayer(t, layer, map[string]interface{}{"param": "value"})
+	parsedLayers.Set("test", parsedLayer)
+
+	type TestStruct struct {
+		Param string `glazed.parameter:"param"`
+	}
+
+	var result TestStruct
+	err := parsedLayers.InitializeStruct("test", result) // Note: passing result, not &result
+	assert.Error(t, err)
+	assert.Contains(t, err.Error(), "pointer")
+}
+
+func TestParsedLayersGetParameterNonExistentLayer(t *testing.T) {
+	parsedLayers := NewParsedLayers()
+
+	_, present := parsedLayers.GetParameter("non_existent", "param")
+	assert.False(t, present)
+}
+
+func TestParsedLayersGetOrCreateNilLayer(t *testing.T) {
+	parsedLayers := NewParsedLayers()
+
+	// Depending on how you want to handle this case, you might expect an error or a new empty layer
+	// Alternatively, if you want to panic:
+	assert.Panics(t, func() { parsedLayers.GetOrCreate(nil) })
+}
+
+func TestParsedLayersInitializeStructUnsupportedTypes(t *testing.T) {
+	parsedLayers := NewParsedLayers()
+	layer := createParameterLayer(t, "test", "Test Layer",
+		parameters.NewParameterDefinition("supported", parameters.ParameterTypeString),
+		parameters.NewParameterDefinition("unsupported", parameters.ParameterTypeString),
+	)
+	parsedLayer := createParsedLayer(t, layer, map[string]interface{}{
+		"supported":   "value",
+		"unsupported": make(chan int), // channels are not supported
+	})
+	parsedLayers.Set("test", parsedLayer)
+
+	type TestStruct struct {
+		Supported   string   `glazed.parameter:"supported"`
+		Unsupported chan int `glazed.parameter:"unsupported"`
+	}
+
+	// as long as the given values are compatible, we let it slide...
+	var result TestStruct
+	err := parsedLayers.InitializeStruct("test", &result)
+	assert.NoError(t, err)
+}
+
+func TestParsedLayersForEachEWithError(t *testing.T) {
+	layer1 := createParameterLayer(t, "layer1", "Layer 1")
+	parsedLayer1 := createParsedLayer(t, layer1, nil)
+	layer2 := createParameterLayer(t, "layer2", "Layer 2")
+	parsedLayer2 := createParsedLayer(t, layer2, nil)
+
+	parsedLayers := NewParsedLayers(
+		WithParsedLayer("layer1", parsedLayer1),
+		WithParsedLayer("layer2", parsedLayer2),
+	)
+
+	count := 0
+	err := parsedLayers.ForEachE(func(k string, v *ParsedLayer) error {
+		count++
+		if k == "layer2" {
+			return errors.New("intentional error")
+		}
+		return nil
+	})
+
+	assert.Error(t, err)
+	assert.Equal(t, "intentional error", err.Error())
+	assert.Equal(t, 2, count) // The loop should have proceeded to the second layer before stopping
+}
+
+func TestParsedLayersInitializeStructStringTypes(t *testing.T) {
+	// Define custom types
+	type StringAlias string
+	type StringDeclaration = string
+
+	// Define the test struct
+	type TestStruct struct {
+		StringField            string              `glazed.parameter:"string_field"`
+		StringAliasField       StringAlias         `glazed.parameter:"string_alias_field"`
+		StringDeclarationField StringDeclaration   `glazed.parameter:"string_declaration_field"`
+		StringListField        []string            `glazed.parameter:"string_list_field"`
+		StringAliasListField   []StringAlias       `glazed.parameter:"string_alias_list_field"`
+		StringDeclListField    []StringDeclaration `glazed.parameter:"string_decl_list_field"`
+	}
+
+	// Create a parameter layer with all the necessary definitions
+	layer := createParameterLayer(t, "test", "Test Layer",
+		parameters.NewParameterDefinition("string_field", parameters.ParameterTypeString),
+		parameters.NewParameterDefinition("string_alias_field", parameters.ParameterTypeString),
+		parameters.NewParameterDefinition("string_declaration_field", parameters.ParameterTypeString),
+		parameters.NewParameterDefinition("string_list_field", parameters.ParameterTypeStringList),
+		parameters.NewParameterDefinition("string_alias_list_field", parameters.ParameterTypeStringList),
+		parameters.NewParameterDefinition("string_decl_list_field", parameters.ParameterTypeStringList),
+	)
+
+	// Create a parsed layer with test values
+	parsedLayer := createParsedLayer(t, layer, map[string]interface{}{
+		"string_field":             "regular string",
+		"string_alias_field":       "aliased string",
+		"string_declaration_field": "declared string",
+		"string_list_field":        []string{"a", "b", "c"},
+		"string_alias_list_field":  []string{"x", "y", "z"},
+		"string_decl_list_field":   []string{"1", "2", "3"},
+	})
+
+	// Create ParsedLayers and add the parsed layer
+	parsedLayers := NewParsedLayers(WithParsedLayer("test", parsedLayer))
+
+	// Initialize the struct
+	var result TestStruct
+	err := parsedLayers.InitializeStruct("test", &result)
+
+	// Assert no error occurred
+	assert.NoError(t, err)
+
+	// Verify each field was correctly initialized
+	assert.Equal(t, "regular string", result.StringField)
+	assert.Equal(t, StringAlias("aliased string"), result.StringAliasField)
+	assert.Equal(t, StringDeclaration("declared string"), result.StringDeclarationField)
+	assert.Equal(t, []string{"a", "b", "c"}, result.StringListField)
+	assert.Equal(t, []StringAlias{"x", "y", "z"}, result.StringAliasListField)
+	assert.Equal(t, []StringDeclaration{"1", "2", "3"}, result.StringDeclListField)
+
+	// Additional type checks
+	assert.IsType(t, "", result.StringField)
+	assert.IsType(t, StringAlias(""), result.StringAliasField)
+	assert.IsType(t, StringDeclaration(""), result.StringDeclarationField)
+	assert.IsType(t, []string{}, result.StringListField)
+	assert.IsType(t, []StringAlias{}, result.StringAliasListField)
+	assert.IsType(t, []StringDeclaration{}, result.StringDeclListField)
+}
+
+func TestParsedLayersInitializeStructStringPointerTypes(t *testing.T) {
+	// Define custom types
+	type StringAlias string
+	type StringDeclaration = string
+
+	// Define the test struct with pointer fields
+	type TestStruct struct {
+		StringPtrField            *string            `glazed.parameter:"string_ptr_field"`
+		StringAliasPtrField       *StringAlias       `glazed.parameter:"string_alias_ptr_field"`
+		StringDeclarationPtrField *StringDeclaration `glazed.parameter:"string_declaration_ptr_field"`
+	}
+
+	// Create a parameter layer with all the necessary definitions
+	layer := createParameterLayer(t, "test", "Test Layer",
+		parameters.NewParameterDefinition("string_ptr_field", parameters.ParameterTypeString),
+		parameters.NewParameterDefinition("string_alias_ptr_field", parameters.ParameterTypeString),
+		parameters.NewParameterDefinition("string_declaration_ptr_field", parameters.ParameterTypeString),
+	)
+
+	// Create a parsed layer with test values
+	parsedLayer := createParsedLayer(t, layer, map[string]interface{}{
+		"string_ptr_field":             "regular string",
+		"string_alias_ptr_field":       "aliased string",
+		"string_declaration_ptr_field": "declared string",
+	})
+
+	// Create ParsedLayers and add the parsed layer
+	parsedLayers := NewParsedLayers(WithParsedLayer("test", parsedLayer))
+
+	// Initialize the struct
+	var result TestStruct
+	err := parsedLayers.InitializeStruct("test", &result)
+
+	// Assert no error occurred
+	assert.NoError(t, err)
+
+	// Verify each field was correctly initialized
+	assert.NotNil(t, result.StringPtrField)
+	assert.NotNil(t, result.StringAliasPtrField)
+	assert.NotNil(t, result.StringDeclarationPtrField)
+
+	assert.Equal(t, "regular string", *result.StringPtrField)
+	assert.Equal(t, StringAlias("aliased string"), *result.StringAliasPtrField)
+	assert.Equal(t, StringDeclaration("declared string"), *result.StringDeclarationPtrField)
+
+	// Additional type checks
+	assert.IsType(t, (*string)(nil), result.StringPtrField)
+	assert.IsType(t, (*StringAlias)(nil), result.StringAliasPtrField)
+	assert.IsType(t, (*StringDeclaration)(nil), result.StringDeclarationPtrField)
+}
diff --git a/pkg/cmds/parameters/parameters_test.go b/pkg/cmds/parameters/parameters_test.go
index 6dc199b..2ca817d 100644
--- a/pkg/cmds/parameters/parameters_test.go
+++ b/pkg/cmds/parameters/parameters_test.go
@@ -25,6 +25,9 @@ type ValidityTest struct {
 	parameterDefinition *ParameterDefinition
 }
 
+type StringAlias = string
+type StringDeclaration string
+
 //go:embed "test-data/parameters_validity_test.yaml"
 var validityTestYaml []byte
 
@@ -269,6 +272,57 @@ func TestSetValueFromDefaultString(t *testing.T) {
 	assert.Equal(t, "", s)
 }
 
+func TestSetValueFromDefaultStringAlias(t *testing.T) {
+	initialParameterTests()
+	stringFlag, _ := testParameterDefinitions.Get("string-flag")
+
+	var s StringAlias = "test"
+
+	// get values of testStruct.StringAlias
+	sValue := reflect.ValueOf(&s).Elem()
+
+	err := stringFlag.SetValueFromDefault(sValue)
+	require.NoError(t, err)
+	assert.Equal(t, StringAlias("default"), s)
+
+	stringFlag, _ = testParameterDefinitions.Get("string-flag-without-default")
+	err = stringFlag.SetValueFromDefault(sValue)
+	require.NoError(t, err)
+	assert.Equal(t, StringAlias(""), s)
+
+	s = "foo"
+
+	stringFlag, _ = testParameterDefinitions.Get("string-flag-with-empty-default")
+	err = stringFlag.SetValueFromDefault(sValue)
+	require.NoError(t, err)
+	assert.Equal(t, StringAlias(""), s)
+}
+
+func TestSetValueFromDefaultStringDeclaration(t *testing.T) {
+	initialParameterTests()
+	stringFlag, _ := testParameterDefinitions.Get("string-flag")
+
+	var s StringDeclaration = "test"
+
+	// get values of testStruct.StringDeclaration
+	sValue := reflect.ValueOf(&s).Elem()
+
+	err := stringFlag.SetValueFromDefault(sValue)
+	require.NoError(t, err)
+	assert.Equal(t, StringDeclaration("default"), s)
+
+	stringFlag, _ = testParameterDefinitions.Get("string-flag-without-default")
+	err = stringFlag.SetValueFromDefault(sValue)
+	require.NoError(t, err)
+	assert.Equal(t, StringDeclaration(""), s)
+
+	s = "foo"
+
+	stringFlag, _ = testParameterDefinitions.Get("string-flag-with-empty-default")
+	err = stringFlag.SetValueFromDefault(sValue)
+	require.NoError(t, err)
+	assert.Equal(t, StringDeclaration(""), s)
+}
 func TestSetValueFromDefaultBool(t *testing.T) {
 	boolFlag, _ := testParameterDefinitions.Get("bool-flag")
 
@@ -348,6 +402,118 @@ func TestSetValueFromDefaultChoiceList(t *testing.T) {
 	require.Error(t, err)
 }
 
+func TestSetValueFromDefaultChoiceAlias(t *testing.T) {
+	initialParameterTests()
+	choiceFlag, _ := testParameterDefinitions.Get("choice-flag")
+
+	var c StringAlias = "foo"
+
+	// get values of testStruct.ChoiceAlias
+	cValue := reflect.ValueOf(&c).Elem()
+
+	err := choiceFlag.SetValueFromDefault(cValue)
+	require.NoError(t, err)
+	assert.Equal(t, StringAlias("default"), c)
+
+	choiceFlag, _ = testParameterDefinitions.Get("choice-flag-without-default")
+	err = choiceFlag.SetValueFromDefault(cValue)
+	require.NoError(t, err)
+	assert.Equal(t, StringAlias(""), c)
+
+	choiceFlag = &ParameterDefinition{
+		Name:    "choice-flag-with-invalid-default",
+		Type:    ParameterTypeChoice,
+		Default: cast.InterfaceAddr("invalid"),
+		Choices: []string{"foo", "bar"},
+	}
+	err = choiceFlag.SetValueFromDefault(cValue)
+	require.Error(t, err)
+}
+
+func TestSetValueFromDefaultChoiceDeclaration(t *testing.T) {
+	initialParameterTests()
+	choiceFlag, _ := testParameterDefinitions.Get("choice-flag")
+
+	var c StringDeclaration = "foo"
+
+	// get values of testStruct.ChoiceDeclaration
+	cValue := reflect.ValueOf(&c).Elem()
+
+	err := choiceFlag.SetValueFromDefault(cValue)
+	require.NoError(t, err)
+	assert.Equal(t, StringDeclaration("default"), c)
+
+	choiceFlag, _ = testParameterDefinitions.Get("choice-flag-without-default")
+	err = choiceFlag.SetValueFromDefault(cValue)
+	require.NoError(t, err)
+	assert.Equal(t, StringDeclaration(""), c)
+
+	choiceFlag = &ParameterDefinition{
+		Name:    "choice-flag-with-invalid-default",
+		Type:    ParameterTypeChoice,
+		Default: cast.InterfaceAddr("invalid"),
+		Choices: []string{"foo", "bar"},
+	}
+	err = choiceFlag.SetValueFromDefault(cValue)
+	require.Error(t, err)
+}
+
+func TestSetValueFromDefaultChoiceListAlias(t *testing.T) {
+	initialParameterTests()
+	choiceListFlag, _ := testParameterDefinitions.Get("choice-list-flag")
+
+	var cl []StringAlias = []StringAlias{"foo", "bar"}
+
+	// get values of testStruct.ChoiceListAlias
+	clValue := reflect.ValueOf(&cl).Elem()
+
+	err := choiceListFlag.SetValueFromDefault(clValue)
+	require.NoError(t, err)
+	assert.Equal(t, []StringAlias{"default", "choice1", "choice2"}, cl)
+
+	choiceListFlag, _ = testParameterDefinitions.Get("choice-list-flag-without-default")
+	err = choiceListFlag.SetValueFromDefault(clValue)
+	require.NoError(t, err)
+	assert.Equal(t, []StringAlias{}, cl)
+
+	choiceListFlag = &ParameterDefinition{
+		Name:    "choice-list-flag-with-invalid-default",
+		Type:    ParameterTypeChoiceList,
+		Default: cast.InterfaceAddr([]string{"invalid"}),
+		Choices: []string{"foo", "bar"},
+	}
+	err = choiceListFlag.SetValueFromDefault(clValue)
+	require.Error(t, err)
+}
+
+func TestSetValueFromDefaultChoiceListDeclaration(t *testing.T) {
+	initialParameterTests()
+	choiceListFlag, _ := testParameterDefinitions.Get("choice-list-flag")
+
+	var cl []StringDeclaration = []StringDeclaration{"foo", "bar"}
+
+	// get values of testStruct.ChoiceListDeclaration
+	clValue := reflect.ValueOf(&cl).Elem()
+
+	err := choiceListFlag.SetValueFromDefault(clValue)
+	require.NoError(t, err)
+	assert.Equal(t, []StringDeclaration{"default", "choice1", "choice2"}, cl)
+
+	choiceListFlag, _ = testParameterDefinitions.Get("choice-list-flag-without-default")
+	err = choiceListFlag.SetValueFromDefault(clValue)
+	require.NoError(t, err)
+	assert.Equal(t, []StringDeclaration{}, cl)
+
+	choiceListFlag = &ParameterDefinition{
+		Name:    "choice-list-flag-with-invalid-default",
+		Type:    ParameterTypeChoiceList,
+		Default: cast.InterfaceAddr([]string{"invalid"}),
+		Choices: []string{"foo", "bar"},
+	}
+	err = choiceListFlag.SetValueFromDefault(clValue)
+	require.Error(t, err)
+}
+
 func TestSetValueFromDefaultIntList(t *testing.T) {
 	intListFlag, _ := testParameterDefinitions.Get("int-list-flag")
 
@@ -549,6 +715,58 @@ func TestSetValueFromDefaultStringListFromFile(t *testing.T) {
 	assert.Equal(t, []string{}, fl)
 }
 
+func TestSetValueFromDefaultStringListAlias(t *testing.T) {
+	initialParameterTests()
+	stringListFlag, _ := testParameterDefinitions.Get("string-list-flag")
+
+	var sl []StringAlias = []StringAlias{"test"}
+
+	// get values of testStruct.StringListAlias
+	slValue := reflect.ValueOf(&sl).Elem()
+
+	err := stringListFlag.SetValueFromDefault(slValue)
+	require.NoError(t, err)
+	assert.Equal(t, []StringAlias{"default1", "default2"}, sl)
+
+	stringListFlag, _ = testParameterDefinitions.Get("string-list-flag-without-default")
+	err = stringListFlag.SetValueFromDefault(slValue)
+	require.NoError(t, err)
+	assert.Equal(t, []StringAlias{}, sl)
+
+	sl = []StringAlias{"foo"}
+
+	stringListFlag, _ = testParameterDefinitions.Get("string-list-flag-with-empty-default")
+	err = stringListFlag.SetValueFromDefault(slValue)
+	require.NoError(t, err)
+	assert.Equal(t, []StringAlias{}, sl)
+}
+
+func TestSetValueFromDefaultStringListDeclaration(t *testing.T) {
+	initialParameterTests()
+	stringListFlag, _ := testParameterDefinitions.Get("string-list-flag")
+
+	var sl []StringDeclaration = []StringDeclaration{"test"}
+
+	// get values of testStruct.StringListDeclaration
+	slValue := reflect.ValueOf(&sl).Elem()
+
+	err := stringListFlag.SetValueFromDefault(slValue)
+	require.NoError(t, err)
+	assert.Equal(t, []StringDeclaration{"default1", "default2"}, sl)
+
+	stringListFlag, _ = testParameterDefinitions.Get("string-list-flag-without-default")
+	err = stringListFlag.SetValueFromDefault(slValue)
+	require.NoError(t, err)
+	assert.Equal(t, []StringDeclaration{}, sl)
+
+	sl = []StringDeclaration{"foo"}
+
+	stringListFlag, _ = testParameterDefinitions.Get("string-list-flag-with-empty-default")
+	err = stringListFlag.SetValueFromDefault(slValue)
+	require.NoError(t, err)
+	assert.Equal(t, []StringDeclaration{}, sl)
+}
+
 func TestSetValueFromDefaultKeyValue(t *testing.T) {
 	keyValueFlag, _ := testParameterDefinitions.Get("key-value-flag")
 
@@ -760,6 +978,184 @@ func TestCheckValueValidity(t *testing.T) {
 			value:   "string instead of string list",
 			wantErr: true,
 		},
+
+		// StringAlias tests
+		{
+			name: "valid string alias value",
+			param: ParameterDefinition{
+				Name:    "test",
+				Type:    ParameterTypeString,
+				Default: cast.InterfaceAddr("default"),
+			},
+			value:   StringAlias("test value"),
+			wantErr: false,
+		},
+		{
+			name: "invalid string alias value",
+			param: ParameterDefinition{
+				Name:    "test",
+				Type:    ParameterTypeString,
+				Default: cast.InterfaceAddr("default"),
+			},
+			value:   123,
+			wantErr: true,
+		},
+		// StringDeclaration tests
+		{
+			name: "valid string declaration value",
+			param: ParameterDefinition{
+				Name:    "test",
+				Type:    ParameterTypeString,
+				Default: cast.InterfaceAddr("default"),
+			},
+			value:   StringDeclaration("test value"),
+			wantErr: false,
+		},
+		{
+			name: "invalid string declaration value",
+			param: ParameterDefinition{
+				Name:    "test",
+				Type:    ParameterTypeString,
+				Default: cast.InterfaceAddr("default"),
+			},
+			value:   123,
+			wantErr: true,
+		},
+		// ChoiceAlias tests
+		{
+			name: "valid choice alias value",
+			param: ParameterDefinition{
+				Name:    "test",
+				Type:    ParameterTypeChoice,
+				Default: cast.InterfaceAddr("choice1"),
+				Choices: []string{"choice1", "choice2"},
+			},
+			value:   StringAlias("choice2"),
+			wantErr: false,
+		},
+		{
+			name: "invalid choice alias value",
+			param: ParameterDefinition{
+				Name:    "test",
+				Type:    ParameterTypeChoice,
+				Default: cast.InterfaceAddr("choice1"),
+				Choices: []string{"choice1", "choice2"},
+			},
+			value:   StringAlias("choice3"),
+			wantErr: true,
+		},
+		// ChoiceDeclaration tests
+		{
+			name: "valid choice declaration value",
+			param: ParameterDefinition{
+				Name:    "test",
+				Type:    ParameterTypeChoice,
+				Default: cast.InterfaceAddr("choice1"),
+				Choices: []string{"choice1", "choice2"},
+			},
+			value:   StringDeclaration("choice2"),
+			wantErr: false,
+		},
+		{
+			name: "invalid choice declaration value",
+			param: ParameterDefinition{
+				Name:    "test",
+				Type:    ParameterTypeChoice,
+				Default: cast.InterfaceAddr("choice1"),
+				Choices: []string{"choice1", "choice2"},
+			},
+			value:   StringDeclaration("choice3"),
+			wantErr: true,
+		},
+		// ChoiceListAlias tests
+		{
+			name: "valid choice list alias value",
+			param: ParameterDefinition{
+				Name:    "test",
+				Type:    ParameterTypeChoiceList,
+				Default: cast.InterfaceAddr([]string{"choice1", "choice2"}),
+				Choices: []string{"choice1", "choice2", "choice3"},
+			},
+			value:   []StringAlias{"choice1", "choice3"},
+			wantErr: false,
+		},
+		{
+			name: "invalid choice list alias value",
+			param: ParameterDefinition{
+				Name:    "test",
+				Type:    ParameterTypeChoiceList,
+				Default: cast.InterfaceAddr([]string{"choice1", "choice2"}),
+				Choices: []string{"choice1", "choice2", "choice3"},
+			},
+			value:   []StringAlias{"choice4"},
+			wantErr: true,
+		},
+		// ChoiceListDeclaration tests
+		{
+			name: "valid choice list declaration value",
+			param: ParameterDefinition{
+				Name:    "test",
+				Type:    ParameterTypeChoiceList,
+				Default: cast.InterfaceAddr([]string{"choice1", "choice2"}),
+				Choices: []string{"choice1", "choice2", "choice3"},
+			},
+			value:   []StringDeclaration{"choice1", "choice3"},
+			wantErr: false,
+		},
+		{
+			name: "invalid choice list declaration value",
+			param: ParameterDefinition{
+				Name:    "test",
+				Type:    ParameterTypeChoiceList,
+				Default: cast.InterfaceAddr([]string{"choice1", "choice2"}),
+				Choices: []string{"choice1", "choice2", "choice3"},
+			},
+			value:   []StringDeclaration{"choice4"},
+			wantErr: true,
+		},
+
+		// StringListAlias tests
+		{
+			name: "valid string list alias value",
+			param: ParameterDefinition{
+				Name:    "test",
+				Type:    ParameterTypeStringList,
+				Default: nil,
+			},
+			value:   []StringAlias{"a", "b", "c"},
+			wantErr: false,
+		},
+		{
+			name: "invalid string list alias value",
+			param: ParameterDefinition{
+				Name:    "test",
+				Type:    ParameterTypeStringList,
+				Default: nil,
+			},
+			value:   "string instead of string list",
+			wantErr: true,
+		},
+		// StringListDeclaration tests
+		{
+			name: "valid string list declaration value",
+			param: ParameterDefinition{
+				Name:    "test",
+				Type:    ParameterTypeStringList,
+				Default: nil,
+			},
+			value:   []StringDeclaration{"a", "b", "c"},
+			wantErr: false,
+		},
+		{
+			name: "invalid string list declaration value",
+			param: ParameterDefinition{
+				Name:    "test",
+				Type:    ParameterTypeStringList,
+				Default: nil,
+			},
+			value:   "string instead of string list",
+			wantErr: true,
+		},
 	}
 
 	for _, tt := range tests {
diff --git a/pkg/helpers/cast/string_test.go b/pkg/helpers/cast/string_test.go
new file mode 100644
index 0000000..064a783
--- /dev/null
+++ b/pkg/helpers/cast/string_test.go
@@ -0,0 +1,216 @@
+package cast_test
+
+import (
+	. "github.com/go-go-golems/glazed/pkg/helpers/cast"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+)
+
+type MyStringAlias string
+type MyString string
+
+func TestToString_RegularString(t *testing.T) {
+	input := "hello"
+	expected := "hello"
+	result, err := ToString(input)
+	require.NoError(t, err)
+	assert.Equal(t, expected, result)
+}
+
+func TestToString_StringTypeAlias(t *testing.T) {
+	input := MyStringAlias("hello")
+	expected := "hello"
+	result, err := ToString(input)
+	require.NoError(t, err)
+	assert.Equal(t, expected, result)
+}
+
+func TestToString_StringTypeDeclaration(t *testing.T) {
+	input := MyString("hello")
+	expected := "hello"
+	result, err := ToString(input)
+	require.NoError(t, err)
+	assert.Equal(t, expected, result)
+}
+
+func TestToString_PointerToString(t *testing.T) {
+	str := "hello"
+	input := &str
+	_, err := ToString(input)
+	require.Error(t, err)
+}
+
+func TestToString_PointerToStringTypeAlias(t *testing.T) {
+	str := MyStringAlias("hello")
+	input := &str
+	_, err := ToString(input)
+	require.Error(t, err)
+}
+
+func TestToString_PointerToStringTypeDeclaration(t *testing.T) {
+	str := MyString("hello")
+	input := &str
+	_, err := ToString(input)
+	require.Error(t, err)
+}
+
+func TestToString_InterfaceHoldingInt(t *testing.T) {
+	var input interface{} = 123
+	_, err := ToString(input)
+	require.Error(t, err)
+}
+
+func TestToString_InterfaceHoldingFloat(t *testing.T) {
+	var input interface{} = 123.45
+	_, err := ToString(input)
+	require.Error(t, err)
+}
+
+func TestToString_InterfaceHoldingBool(t *testing.T) {
+	var input interface{} = true
+	_, err := ToString(input)
+	require.Error(t, err)
+}
+
+func TestToString_InterfaceHoldingStruct(t *testing.T) {
+	type MyStruct struct {
+		Field string
+	}
+	var input interface{} = MyStruct{Field: "value"}
+	_, err := ToString(input)
+	require.Error(t, err)
+}
+
+func TestToString_InterfaceHoldingString(t *testing.T) {
+	var input interface{} = "hello"
+	expected := "hello"
+	result, err := ToString(input)
+	require.NoError(t, err)
+	assert.Equal(t, expected, result)
+}
+
+func TestToString_InterfaceHoldingStringTypeAlias(t *testing.T) {
+	var input interface{} = MyStringAlias("hello")
+	expected := "hello"
+	result, err := ToString(input)
+	require.NoError(t, err)
+	assert.Equal(t, expected, result)
+}
+
+func TestToString_InterfaceHoldingStringTypeDeclaration(t *testing.T) {
+	var input interface{} = MyString("hello")
+	expected := "hello"
+	result, err := ToString(input)
+	require.NoError(t, err)
+	assert.Equal(t, expected, result)
+}
+
+func TestCastListToStringList_RegularStringSlice(t *testing.T) {
+	input := []string{"hello", "world"}
+	expected := []string{"hello", "world"}
+	result, err := CastListToStringList(input)
+	require.NoError(t, err)
+	assert.Equal(t, expected, result)
+}
+
+func TestCastListToStringList_StringTypeAliasSlice(t *testing.T) {
+	input := []MyStringAlias{"hello", "world"}
+	expected := []string{"hello", "world"}
+	result, err := CastListToStringList(input)
+	require.NoError(t, err)
+	assert.Equal(t, expected, result)
+}
+
+func TestCastListToStringList_StringTypeDeclarationSlice(t *testing.T) {
+	input := []MyString{"hello", "world"}
+	expected := []string{"hello", "world"}
+	result, err := CastListToStringList(input)
+	require.NoError(t, err)
+	assert.Equal(t, expected, result)
+}
+
+func TestCastListToStringList_MixedTypeSlice(t *testing.T) {
+	input := []interface{}{"hello", MyStringAlias("world"), MyString("foo")}
+	expected := []string{"hello", "world", "foo"}
+	result, err := CastListToStringList(input)
+	require.NoError(t, err)
+	assert.Equal(t, expected, result)
+}
+
+func TestCastListToStringList_InterfaceHoldingString(t *testing.T) {
+	input := []interface{}{"hello", "world"}
+	expected := []string{"hello", "world"}
+	result, err := CastListToStringList(input)
+	require.NoError(t, err)
+	assert.Equal(t, expected, result)
+}
+
+func TestCastListToStringList_InterfaceHoldingStringTypeAlias(t *testing.T) {
+	input := []interface{}{MyStringAlias("hello"), MyStringAlias("world")}
+	expected := []string{"hello", "world"}
+	result, err := CastListToStringList(input)
+	require.NoError(t, err)
+	assert.Equal(t, expected, result)
+}
+
+func TestCastListToStringList_InterfaceHoldingStringTypeDeclaration(t *testing.T) {
+	input := []interface{}{MyString("hello"), MyString("world")}
+	expected := []string{"hello", "world"}
+	result, err := CastListToStringList(input)
+	require.NoError(t, err)
+	assert.Equal(t, expected, result)
+}
+
+func TestCastListToStringList_InvalidTypeInSlice(t *testing.T) {
+	input := []interface{}{"hello", 123, "world"}
+	_, err := CastListToStringList(input)
+	require.Error(t, err)
+}
+
+func TestCastListToStringList_NonSliceInput(t *testing.T) {
+	input := "not a slice"
+	_, err := CastListToStringList(input)
+	require.Error(t, err)
+}
+
+func TestCastListToStringList_EmptySlice(t *testing.T) {
+	input := []string{}
+	expected := []string{}
+	result, err := CastListToStringList(input)
+	require.NoError(t, err)
+	assert.Equal(t, expected, result)
+}
+
+func TestCastListToStringList_NilSlice(t *testing.T) {
+	var input []string
+	expected := []string{}
+	result, err := CastListToStringList(input)
+	require.NoError(t, err)
+	assert.Equal(t, expected, result)
+}
+
+func TestCastStringListToList_StringTypeAlias(t *testing.T) {
+	input := []string{"hello", "world"}
+	expected := []MyStringAlias{"hello", "world"}
+	result, err := CastStringListToList[MyStringAlias](input)
+	require.NoError(t, err)
+	assert.Equal(t, expected, result)
+}
+
+func TestCastStringListToList_StringTypeDeclaration(t *testing.T) {
+	input := []string{"hello", "world"}
+	expected := []MyString{"hello", "world"}
+	result, err := CastStringListToList[MyString](input)
+	require.NoError(t, err)
+	assert.Equal(t, expected, result)
+}
+
+func TestCastStringListToList_EmptyList(t *testing.T) {
+	input := []string{}
+	expected := []MyStringAlias{}
+	result, err := CastStringListToList[MyStringAlias](input)
+	require.NoError(t, err)
+	assert.Equal(t, expected, result)
+}
diff --git a/pkg/helpers/reflect/reflect_test.go b/pkg/helpers/reflect/reflect_test.go
index 0b5d3f1..dfe7b95 100644
--- a/pkg/helpers/reflect/reflect_test.go
+++ b/pkg/helpers/reflect/reflect_test.go
@@ -539,3 +539,151 @@ func TestSetReflectStringListInterface(t *testing.T) {
 	err = SetReflectValue(sValue, []interface{}{"hello", 1})
 	require.Error(t, err)
 }
+
+type StringAlias string
+type StringDeclaration string
+
+func TestSetReflectString(t *testing.T) {
+	var s string
+	err := SetReflectValue(reflect.ValueOf(&s).Elem(), "test")
+	assert.NoError(t, err)
+	assert.Equal(t, "test", s)
+}
+
+func TestSetReflectStringFromAlias(t *testing.T) {
+	var s string
+	err := SetReflectValue(reflect.ValueOf(&s).Elem(), StringAlias("test"))
+	assert.NoError(t, err)
+	assert.Equal(t, "test", s)
+}
+
+func TestSetReflectStringFromDeclaration(t *testing.T) {
+	var s string
+	err := SetReflectValue(reflect.ValueOf(&s).Elem(), StringDeclaration("test"))
+	assert.NoError(t, err)
+	assert.Equal(t, "test", s)
+}
+
+func TestSetReflectStringAlias(t *testing.T) {
+	var s StringAlias
+	err := SetReflectValue(reflect.ValueOf(&s).Elem(), "test")
+	assert.NoError(t, err)
+	assert.Equal(t, StringAlias("test"), s)
+}
+
+func TestSetReflectStringAliasFromAlias(t *testing.T) {
+	var s StringAlias
+	err := SetReflectValue(reflect.ValueOf(&s).Elem(), StringAlias("test"))
+	assert.NoError(t, err)
+	assert.Equal(t, StringAlias("test"), s)
+}
+
+func TestSetReflectStringAliasFromDeclaration(t *testing.T) {
+	var s StringAlias
+	err := SetReflectValue(reflect.ValueOf(&s).Elem(), StringDeclaration("test"))
+	assert.NoError(t, err)
+	assert.Equal(t, StringAlias("test"), s)
+}
+
+func TestSetReflectStringDeclaration(t *testing.T) {
+	var s StringDeclaration
+	err := SetReflectValue(reflect.ValueOf(&s).Elem(), "test")
+	assert.NoError(t, err)
+	assert.Equal(t, StringDeclaration("test"), s)
+}
+
+func TestSetReflectStringDeclarationFromAlias(t *testing.T) {
+	var s StringDeclaration
+	err := SetReflectValue(reflect.ValueOf(&s).Elem(), StringAlias("test"))
+	assert.NoError(t, err)
+	assert.Equal(t, StringDeclaration("test"), s)
+}
+
+func TestSetReflectStringDeclarationFromDeclaration(t *testing.T) {
+	var s StringDeclaration
+	err := SetReflectValue(reflect.ValueOf(&s).Elem(), StringDeclaration("test"))
+	assert.NoError(t, err)
+	assert.Equal(t, StringDeclaration("test"), s)
+}
+
+func TestSetReflectStringSlice(t *testing.T) {
+	var s []string
+	err := SetReflectValue(reflect.ValueOf(&s).Elem(), []string{"a", "b"})
+	assert.NoError(t, err)
+	assert.Equal(t, []string{"a", "b"}, s)
+}
+
+func TestSetReflectStringSliceFromAlias(t *testing.T) {
+	var s []string
+	err := SetReflectValue(reflect.ValueOf(&s).Elem(), []StringAlias{"a", "b"})
+	assert.NoError(t, err)
+	assert.Equal(t, []string{"a", "b"}, s)
+}
+
+func TestSetReflectStringSliceFromDeclaration(t *testing.T) {
+	var s []string
+	err := SetReflectValue(reflect.ValueOf(&s).Elem(), []StringDeclaration{"a", "b"})
+	assert.NoError(t, err)
+	assert.Equal(t, []string{"a", "b"}, s)
+}
+
+func TestSetReflectStringAliasSlice(t *testing.T) {
+	var s []StringAlias
+	err := SetReflectValue(reflect.ValueOf(&s).Elem(), []string{"a", "b"})
+	assert.NoError(t, err)
+	assert.Equal(t, []StringAlias{"a", "b"}, s)
+}
+
+func TestSetReflectStringAliasSliceFromAlias(t *testing.T) {
+	var s []StringAlias
+	err := SetReflectValue(reflect.ValueOf(&s).Elem(), []StringAlias{"a", "b"})
+	assert.NoError(t, err)
+	assert.Equal(t, []StringAlias{"a", "b"}, s)
+}
+
+func TestSetReflectStringAliasSliceFromDeclaration(t *testing.T) {
+	var s []StringAlias
+	err := SetReflectValue(reflect.ValueOf(&s).Elem(), []StringDeclaration{"a", "b"})
+	assert.NoError(t, err)
+	assert.Equal(t, []StringAlias{"a", "b"}, s)
+}
+
+func TestSetReflectStringDeclarationSlice(t *testing.T) {
+	var s []StringDeclaration
+	err := SetReflectValue(reflect.ValueOf(&s).Elem(), []string{"a", "b"})
+	assert.NoError(t, err)
+	assert.Equal(t, []StringDeclaration{"a", "b"}, s)
+}
+
+func TestSetReflectStringDeclarationSliceFromAlias(t *testing.T) {
+	var s []StringDeclaration
+	err := SetReflectValue(reflect.ValueOf(&s).Elem(), []StringAlias{"a", "b"})
+	assert.NoError(t, err)
+	assert.Equal(t, []StringDeclaration{"a", "b"}, s)
+}
+
+func TestSetReflectStringDeclarationSliceFromDeclaration(t *testing.T) {
+	var s []StringDeclaration
+	err := SetReflectValue(reflect.ValueOf(&s).Elem(), []StringDeclaration{"a", "b"})
+	assert.NoError(t, err)
+	assert.Equal(t, []StringDeclaration{"a", "b"}, s)
+}
+
+func TestSetReflectStringSliceFromInterface(t *testing.T) {
+	var s []string
+	err := SetReflectValue(reflect.ValueOf(&s).Elem(), []interface{}{"a", "b"})
+	assert.NoError(t, err)
+	assert.Equal(t, []string{"a", "b"}, s)
+}
+
+func TestSetReflectStringError(t *testing.T) {
+	var s string
+	err := SetReflectValue(reflect.ValueOf(&s).Elem(), 42)
+	assert.Error(t, err)
+}
+
+func TestSetReflectStringSliceError(t *testing.T) {
+	var s []string
+	err := SetReflectValue(reflect.ValueOf(&s).Elem(), []int{1, 2})
+	assert.Error(t, err)
+}