github.com/viant/toolbox@v0.34.5/iterator.go (about)

     1  package toolbox
     2  
     3  import (
     4  	"reflect"
     5  	"time"
     6  )
     7  
     8  //Iterator represents generic iterator.
     9  type Iterator interface {
    10  	//HasNext returns true if iterator has next element.
    11  	HasNext() bool
    12  
    13  	//Next sets item pointer with next element.
    14  	Next(itemPointer interface{}) error
    15  }
    16  
    17  type sliceIterator struct {
    18  	sliceValue reflect.Value
    19  	index      int
    20  }
    21  
    22  func (i *sliceIterator) HasNext() bool {
    23  	return i.index < i.sliceValue.Len()
    24  }
    25  
    26  func (i *sliceIterator) Next(itemPointer interface{}) error {
    27  	value := i.sliceValue.Index(i.index)
    28  	i.index++
    29  	itemPointerValue := reflect.ValueOf(itemPointer)
    30  	itemPointerValue.Elem().Set(value)
    31  	return nil
    32  }
    33  
    34  type stringSliceIterator struct {
    35  	sliceValue []string
    36  	index      int
    37  }
    38  
    39  func (i *stringSliceIterator) HasNext() bool {
    40  	return i.index < len(i.sliceValue)
    41  }
    42  
    43  func (i *stringSliceIterator) Next(itemPointer interface{}) error {
    44  	value := i.sliceValue[i.index]
    45  	i.index++
    46  	if stringPointer, ok := itemPointer.(*string); ok {
    47  		*stringPointer = value
    48  		return nil
    49  	}
    50  	interfacePointer := itemPointer.(*interface{})
    51  	*interfacePointer = value
    52  	return nil
    53  }
    54  
    55  type interfaceSliceIterator struct {
    56  	sliceValue []interface{}
    57  	index      int
    58  }
    59  
    60  func (i *interfaceSliceIterator) HasNext() bool {
    61  	return i.index < len(i.sliceValue)
    62  }
    63  
    64  func (i *interfaceSliceIterator) Next(itemPointer interface{}) error {
    65  	value := i.sliceValue[i.index]
    66  	i.index++
    67  
    68  	switch actual := itemPointer.(type) {
    69  	case *interface{}:
    70  		*actual = value
    71  		return nil
    72  	case *string:
    73  		*actual = AsString(value)
    74  		return nil
    75  	case *int:
    76  		*actual = AsInt(value)
    77  		return nil
    78  	case *int64:
    79  		*actual = int64(AsInt(value))
    80  		return nil
    81  	case *time.Time:
    82  		var timestamp = AsTime(value, DefaultDateLayout)
    83  		if timestamp != nil {
    84  			*actual = *timestamp
    85  		}
    86  		return nil
    87  
    88  	}
    89  	itemPointerValue := reflect.ValueOf(itemPointer)
    90  	if value != nil {
    91  		itemPointerValue.Elem().Set(reflect.ValueOf(value))
    92  	} else {
    93  		itemPointerValue.Elem().Set(reflect.Zero(reflect.TypeOf(itemPointer).Elem()))
    94  
    95  	}
    96  	return nil
    97  }
    98  
    99  //NewSliceIterator creates a new slice iterator.
   100  func NewSliceIterator(slice interface{}) Iterator {
   101  	if aSlice, ok := slice.([]interface{}); ok {
   102  		return &interfaceSliceIterator{aSlice, 0}
   103  	}
   104  	if aSlice, ok := slice.([]string); ok {
   105  		return &stringSliceIterator{aSlice, 0}
   106  	}
   107  	sliceValue := DiscoverValueByKind(reflect.ValueOf(slice), reflect.Slice)
   108  	return &sliceIterator{sliceValue: sliceValue}
   109  }