github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/builtins/core/arraytools/2darray.go (about)

     1  package arraytools
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"sync"
     7  	"sync/atomic"
     8  
     9  	"github.com/lmorg/murex/lang"
    10  	"github.com/lmorg/murex/lang/types"
    11  	"github.com/lmorg/murex/utils/json"
    12  )
    13  
    14  func init() {
    15  	lang.DefineFunction("2darray", twoDArray, types.Json)
    16  }
    17  
    18  type mdarray struct {
    19  	mutex sync.Mutex
    20  	array [][]string
    21  	len   int
    22  }
    23  
    24  func newMultiArray(len int) mdarray {
    25  	array := [][]string{make([]string, len)}
    26  	return mdarray{array: array, len: len}
    27  }
    28  
    29  func (a *mdarray) Append(index int, count int, value string) {
    30  	a.mutex.Lock()
    31  
    32  	if len(a.array) <= count {
    33  		a.array = append(a.array, make([]string, a.len))
    34  	}
    35  
    36  	a.array[count][index] = value
    37  	a.mutex.Unlock()
    38  }
    39  
    40  func twoDArray(p *lang.Process) (err error) {
    41  	p.Stdout.SetDataType(types.Json)
    42  
    43  	if p.Parameters.Len() == 0 {
    44  		return errors.New("missing parameters. Expecting code blocks to populate array")
    45  	}
    46  
    47  	block := make(map[int][]rune)
    48  
    49  	for i := 0; i < p.Parameters.Len(); i++ {
    50  		block[i], err = p.Parameters.Block(i)
    51  		if err != nil {
    52  			return err
    53  		}
    54  	}
    55  
    56  	var (
    57  		wg       sync.WaitGroup
    58  		array    = newMultiArray(p.Parameters.Len())
    59  		errCount int32
    60  		i        int
    61  	)
    62  
    63  	for i = 0; i < p.Parameters.Len(); i++ {
    64  		wg.Add(1)
    65  
    66  		index := i
    67  		count := 0
    68  
    69  		go func() {
    70  			fork := p.Fork(lang.F_NO_STDIN | lang.F_CREATE_STDOUT)
    71  			_, err := fork.Execute(block[index])
    72  
    73  			if err != nil {
    74  				fork.Stderr.Write([]byte(fmt.Sprintf("error executing fork (block %d): %s", index, err.Error())))
    75  			}
    76  
    77  			err = fork.Stdout.ReadArray(p.Context, func(b []byte) {
    78  				count++
    79  				array.Append(index, count, string(b))
    80  			})
    81  
    82  			if err != nil {
    83  				p.Stderr.Writeln([]byte(fmt.Sprintf("error in ReadArray() (block %d): %s: ", index, err.Error())))
    84  				atomic.AddInt32(&errCount, 1)
    85  			}
    86  
    87  			wg.Done()
    88  		}()
    89  	}
    90  
    91  	wg.Wait()
    92  
    93  	if errCount > 0 {
    94  		return fmt.Errorf("%d/%d blocks contained errors. Please read STDERR for details", errCount, i+1)
    95  	}
    96  
    97  	b, err := json.Marshal(array.array, p.Stdout.IsTTY())
    98  	if err != nil {
    99  		return err
   100  	}
   101  
   102  	_, err = p.Stdout.Write(b)
   103  	return err
   104  }