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 }