github.com/gagliardetto/solana-go@v1.11.0/text/encoder.go (about)

     1  // Copyright 2020 dfuse Platform Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package text
    16  
    17  import (
    18  	"fmt"
    19  	"io"
    20  	"reflect"
    21  	"strings"
    22  
    23  	"github.com/fatih/color"
    24  )
    25  
    26  var (
    27  	EncoderColorCyan   = color.New(color.FgCyan)
    28  	EncoderColorYellow = color.New(color.FgYellow)
    29  	EncoderColorGreen  = color.New(color.FgGreen)
    30  	EncoderColorWhite  = color.New(color.FgWhite)
    31  )
    32  
    33  type Encoder struct {
    34  	output      io.Writer
    35  	indentLevel int
    36  }
    37  
    38  func NewEncoder(w io.Writer) *Encoder {
    39  	return &Encoder{
    40  		output: w,
    41  	}
    42  }
    43  
    44  func isZero(rv reflect.Value) (b bool) {
    45  	return rv.Kind() == 0
    46  }
    47  
    48  func isNil(rv reflect.Value) (b bool) {
    49  	defer func(b bool) {
    50  		if err := recover(); err != nil {
    51  			b = true
    52  		}
    53  	}(b)
    54  	return rv.IsNil()
    55  }
    56  
    57  func (e *Encoder) Encode(v interface{}, option *Option) (err error) {
    58  	if option == nil {
    59  		option = &Option{}
    60  	}
    61  	return e.encode(reflect.ValueOf(v), option)
    62  }
    63  
    64  type Option struct {
    65  	indent     bool
    66  	linear     bool
    67  	fgColor    *color.Color
    68  	NoTypeName bool
    69  }
    70  
    71  func (e *Encoder) encode(rv reflect.Value, option *Option) (err error) {
    72  	if option == nil {
    73  		option = &Option{}
    74  	}
    75  
    76  	if isZero(rv) {
    77  		return e.ToWriter("NIL_VALUE", option.indent, option.fgColor)
    78  	}
    79  
    80  	if enc, ok := rv.Interface().(TextEncodable); ok {
    81  		return enc.TextEncode(e, option)
    82  	}
    83  
    84  	//if sr, ok := rv.Interface().(fmt.Stringer); ok {
    85  	//	return e.ToWriter(sr.String(), option.indent, option.fgColor)
    86  	//}
    87  
    88  	switch rv.Kind() {
    89  	case reflect.String:
    90  		return e.ToWriter(rv.String(), option.indent, option.fgColor)
    91  	case reflect.Uint8, reflect.Int8:
    92  		return e.ToWriter(fmt.Sprintf("%d", byte(rv.Uint())), option.indent, option.fgColor)
    93  	case reflect.Int16:
    94  		return e.ToWriter(fmt.Sprintf("%d", int16(rv.Int())), option.indent, option.fgColor)
    95  	case reflect.Uint16:
    96  		return e.ToWriter(fmt.Sprintf("%d", uint16(rv.Uint())), option.indent, option.fgColor)
    97  	case reflect.Int32:
    98  		return e.ToWriter(fmt.Sprintf("%d", int32(rv.Int())), option.indent, option.fgColor)
    99  	case reflect.Uint32:
   100  		return e.ToWriter(fmt.Sprintf("%d", uint32(rv.Uint())), option.indent, option.fgColor)
   101  	case reflect.Uint64:
   102  		return e.ToWriter(fmt.Sprintf("%d", rv.Uint()), option.indent, option.fgColor)
   103  	case reflect.Int64:
   104  		return e.ToWriter(fmt.Sprintf("%d", rv.Int()), option.indent, option.fgColor)
   105  	case reflect.Float32:
   106  		return e.ToWriter(fmt.Sprintf("%f", float32(rv.Float())), option.indent, option.fgColor)
   107  	case reflect.Float64:
   108  		return e.ToWriter(fmt.Sprintf("%f", rv.Float()), option.indent, option.fgColor)
   109  	case reflect.Bool:
   110  		return e.ToWriter(fmt.Sprintf("%t", rv.Bool()), option.indent, option.fgColor)
   111  	case reflect.Ptr:
   112  		return e.encode(rv.Elem(), option)
   113  	}
   114  
   115  	rv = reflect.Indirect(rv)
   116  	rt := rv.Type()
   117  	switch rt.Kind() {
   118  	case reflect.Array:
   119  		l := rt.Len()
   120  		e.indentLevel++
   121  		for i := 0; i < l; i++ {
   122  			if err := e.ToWriter("\n", false, nil); err != nil {
   123  				return err
   124  			}
   125  			if err := e.ToWriter(fmt.Sprintf("[%d] ", i), true, nil); err != nil {
   126  				return err
   127  			}
   128  			if err = e.encode(rv.Index(i), option); err != nil {
   129  				return
   130  			}
   131  		}
   132  		e.indentLevel--
   133  	case reflect.Slice:
   134  		l := rv.Len()
   135  		e.indentLevel++
   136  		for i := 0; i < l; i++ {
   137  
   138  			if err := e.ToWriter("\n", false, nil); err != nil {
   139  				return err
   140  			}
   141  
   142  			if err := e.ToWriter(fmt.Sprintf("[%d] ", i), true, nil); err != nil {
   143  				return err
   144  			}
   145  
   146  			if err = e.encode(rv.Index(i), option); err != nil {
   147  				return
   148  			}
   149  			//if err := e.ToWriter("\n"); err != nil {
   150  			//	return err
   151  			//}
   152  		}
   153  		e.indentLevel--
   154  	case reflect.Struct:
   155  		if err = e.encodeStruct(rt, rv, option); err != nil {
   156  			return
   157  		}
   158  
   159  	case reflect.Map:
   160  		for _, mapKey := range rv.MapKeys() {
   161  			if err = e.Encode(mapKey.Interface(), option); err != nil {
   162  				return
   163  			}
   164  
   165  			if err = e.Encode(rv.MapIndex(mapKey).Interface(), option); err != nil {
   166  				return
   167  			}
   168  		}
   169  
   170  	default:
   171  		return e.ToWriter("NOT TEXTABLE", false, option.fgColor)
   172  	}
   173  	return
   174  }
   175  
   176  func (e *Encoder) ToWriter(s string, indent bool, c *color.Color) (err error) {
   177  	if indent {
   178  		indent := strings.Repeat(" ", e.indentLevel)
   179  		if _, err = e.output.Write([]byte(indent)); err != nil {
   180  			return err
   181  		}
   182  	}
   183  	if c != nil {
   184  		s = c.Sprintf("%s", s)
   185  	}
   186  	_, err = e.output.Write([]byte(s))
   187  
   188  	return nil
   189  }
   190  
   191  func (e *Encoder) encodeStruct(rt reflect.Type, rv reflect.Value, option *Option) (err error) {
   192  	e.indentLevel++
   193  	defer func() {
   194  		e.indentLevel--
   195  	}()
   196  
   197  	if err := e.ToWriter("\n", false, nil); err != nil {
   198  		return err
   199  	}
   200  
   201  	if !option.NoTypeName {
   202  		if err := e.ToWriter(rt.Name(), true, EncoderColorCyan); err != nil {
   203  			return err
   204  		}
   205  	}
   206  
   207  	if !option.linear {
   208  		if err := e.ToWriter("\n", false, nil); err != nil {
   209  			return err
   210  		}
   211  	} else {
   212  		if err := e.ToWriter(" ", false, nil); err != nil {
   213  			return err
   214  		}
   215  	}
   216  
   217  	l := rv.NumField()
   218  	for i := 0; i < l; i++ {
   219  		structField := rt.Field(i)
   220  		fieldTag := parseFieldTag(structField.Tag)
   221  		fieldOption := &Option{
   222  			fgColor:    EncoderColorWhite,
   223  			linear:     fieldTag.Linear,
   224  			NoTypeName: false,
   225  		}
   226  
   227  		fieldOption.linear = fieldTag.Linear
   228  
   229  		if fieldTag.Skip {
   230  			continue
   231  		}
   232  
   233  		rv := rv.Field(i)
   234  
   235  		if !rv.CanInterface() {
   236  			continue
   237  		}
   238  
   239  		if err := e.ToWriter(structField.Name+": ", !option.linear, EncoderColorGreen); err != nil {
   240  			return err
   241  		}
   242  
   243  		if err := e.encode(rv, fieldOption); err != nil {
   244  			return err
   245  		}
   246  
   247  		if !option.linear {
   248  			if err := e.ToWriter("\n", false, nil); err != nil {
   249  				return err
   250  			}
   251  		} else {
   252  			if err := e.ToWriter(" ", false, nil); err != nil {
   253  				return err
   254  			}
   255  		}
   256  	}
   257  	return nil
   258  }