github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/cmd/test/info/internal/internal.go (about)

     1  // Package internal provides internal implementation for the info test command.
     2  package internal
     3  
     4  import (
     5  	"bytes"
     6  	"encoding/json"
     7  	"fmt"
     8  	"strings"
     9  )
    10  
    11  // Presence describes the presence of a filename in file listing
    12  type Presence int
    13  
    14  // Possible Presence states
    15  const (
    16  	Absent Presence = iota
    17  	Present
    18  	Renamed
    19  	Multiple
    20  )
    21  
    22  // Position is the placement of the test character in the filename
    23  type Position int
    24  
    25  // Predefined positions
    26  const (
    27  	PositionMiddle Position = 1 << iota
    28  	PositionLeft
    29  	PositionRight
    30  	PositionNone Position = 0
    31  	PositionAll  Position = PositionRight<<1 - 1
    32  )
    33  
    34  // PositionList contains all valid positions
    35  var PositionList = []Position{PositionMiddle, PositionLeft, PositionRight}
    36  
    37  // ControlResult contains the result of a single character test
    38  type ControlResult struct {
    39  	Text       string `json:"-"`
    40  	WriteError map[Position]string
    41  	GetError   map[Position]string
    42  	InList     map[Position]Presence
    43  }
    44  
    45  // InfoReport is the structure of the JSON output
    46  type InfoReport struct {
    47  	Remote               string
    48  	ControlCharacters    *map[string]ControlResult
    49  	MaxFileLength        *int
    50  	CanStream            *bool
    51  	CanWriteUnnormalized *bool
    52  	CanReadUnnormalized  *bool
    53  	CanReadRenormalized  *bool
    54  }
    55  
    56  func (e Position) String() string {
    57  	switch e {
    58  	case PositionNone:
    59  		return "none"
    60  	case PositionAll:
    61  		return "all"
    62  	}
    63  	var buf bytes.Buffer
    64  	if e&PositionMiddle != 0 {
    65  		buf.WriteString("middle")
    66  		e &= ^PositionMiddle
    67  	}
    68  	if e&PositionLeft != 0 {
    69  		if buf.Len() != 0 {
    70  			buf.WriteRune(',')
    71  		}
    72  		buf.WriteString("left")
    73  		e &= ^PositionLeft
    74  	}
    75  	if e&PositionRight != 0 {
    76  		if buf.Len() != 0 {
    77  			buf.WriteRune(',')
    78  		}
    79  		buf.WriteString("right")
    80  		e &= ^PositionRight
    81  	}
    82  	if e != PositionNone {
    83  		panic("invalid position")
    84  	}
    85  	return buf.String()
    86  }
    87  
    88  // MarshalText encodes the position when used as a map key
    89  func (e Position) MarshalText() ([]byte, error) {
    90  	return []byte(e.String()), nil
    91  }
    92  
    93  // UnmarshalText decodes a position when used as a map key
    94  func (e *Position) UnmarshalText(text []byte) error {
    95  	switch s := strings.ToLower(string(text)); s {
    96  	default:
    97  		*e = PositionNone
    98  		for _, p := range strings.Split(s, ",") {
    99  			switch p {
   100  			case "left":
   101  				*e |= PositionLeft
   102  			case "middle":
   103  				*e |= PositionMiddle
   104  			case "right":
   105  				*e |= PositionRight
   106  			default:
   107  				return fmt.Errorf("unknown position: %s", e)
   108  			}
   109  		}
   110  	case "none":
   111  		*e = PositionNone
   112  	case "all":
   113  		*e = PositionAll
   114  	}
   115  	return nil
   116  }
   117  
   118  func (e Presence) String() string {
   119  	switch e {
   120  	case Absent:
   121  		return "absent"
   122  	case Present:
   123  		return "present"
   124  	case Renamed:
   125  		return "renamed"
   126  	case Multiple:
   127  		return "multiple"
   128  	default:
   129  		panic("invalid presence")
   130  	}
   131  }
   132  
   133  // MarshalJSON encodes the presence when used as a JSON value
   134  func (e Presence) MarshalJSON() ([]byte, error) {
   135  	return json.Marshal(e.String())
   136  }
   137  
   138  // UnmarshalJSON decodes a presence when used as a JSON value
   139  func (e *Presence) UnmarshalJSON(text []byte) error {
   140  	var s string
   141  	if err := json.Unmarshal(text, &s); err != nil {
   142  		return err
   143  	}
   144  	switch s := strings.ToLower(s); s {
   145  	case "absent":
   146  		*e = Absent
   147  	case "present":
   148  		*e = Present
   149  	case "renamed":
   150  		*e = Renamed
   151  	case "multiple":
   152  		*e = Multiple
   153  	default:
   154  		return fmt.Errorf("unknown presence: %s", e)
   155  	}
   156  	return nil
   157  }