github.com/mem/u-root@v2.0.1-0.20181004165302-9b18b4636a33+incompatible/cmds/elvish/eval/vals/rat.go (about)

     1  package vals
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"math/big"
     7  
     8  	"github.com/xiaq/persistent/hash"
     9  )
    10  
    11  var ErrOnlyStrOrRat = errors.New("only str or rat may be converted to rat")
    12  
    13  // Rat is a rational number.
    14  type Rat struct {
    15  	b *big.Rat
    16  }
    17  
    18  var _ interface{} = Rat{}
    19  
    20  func (Rat) Kind() string {
    21  	return "string"
    22  }
    23  
    24  func (r Rat) Equal(a interface{}) bool {
    25  	if r == a {
    26  		return true
    27  	}
    28  	r2, ok := a.(Rat)
    29  	if !ok {
    30  		return false
    31  	}
    32  	return r.b.Cmp(r2.b) == 0
    33  }
    34  
    35  func (r Rat) Hash() uint32 {
    36  	// TODO(xiaq): Use a more efficient implementation.
    37  	return hash.String(r.String())
    38  }
    39  
    40  func (r Rat) Repr(int) string {
    41  	return "(rat " + r.String() + ")"
    42  }
    43  
    44  func (r Rat) String() string {
    45  	if r.b.IsInt() {
    46  		return r.b.Num().String()
    47  	}
    48  	return r.b.String()
    49  }
    50  
    51  // ToRat converts a Value to rat. A str can be converted to a rat if it can be
    52  // parsed. A rat is returned as-is. Other types of values cannot be converted.
    53  func ToRat(v interface{}) (Rat, error) {
    54  	switch v := v.(type) {
    55  	case Rat:
    56  		return v, nil
    57  	case string:
    58  		r := big.Rat{}
    59  		_, err := fmt.Sscanln(string(v), &r)
    60  		if err != nil {
    61  			return Rat{}, fmt.Errorf("%s cannot be parsed as rat", Repr(v, NoPretty))
    62  		}
    63  		return Rat{&r}, nil
    64  	default:
    65  		return Rat{}, ErrOnlyStrOrRat
    66  	}
    67  }