package jx

import (
	
	
	

	
)

// Num represents number, which can be raw json number or number string.
//
// Same as Raw, but with number invariants.
//
// Examples:
//
//	123.45   // Str: false, IsInt: false
//	"123.45" // Str: true,  IsInt: false
//	"12345"  // Str: true,  IsInt: true
//	12345    // Str: false, IsInt: true
type Num []byte

func ( Num) () Decoder {
	 := 0
	 := len()
	if .Str() {
		 = 1
		--
	}
	return Decoder{
		buf:  ,
		head: ,
		tail: ,
	}
}

// Str reports whether Num is string number.
func ( Num) () bool {
	return len() > 0 && [0] == '"'
}

func ( Num) () ( int,  error) {
	// Allow decoding floats with zero fractional, like 1.0 as 1.
	 = -1
	for ,  := range  {
		if  == '.' {
			 = 
			continue
		}
		if  == -1 {
			continue
		}
		switch  {
		case '0', '"': // ok
		default:
			return , errors.Errorf("non-zero fractional part %q at %d", , )
		}
	}
	return , nil
}

// Int64 decodes number as a signed 64-bit integer.
// Works on floats with zero fractional part.
func ( Num) () (int64, error) {
	,  := .floatAsInt()
	if  != nil {
		return 0, errors.Wrap(, "float as int")
	}
	 := .dec()
	if  != -1 {
		.tail = 
	}
	return .Int64()
}

// IsInt reports whether number is integer.
func ( Num) () bool {
	if len() == 0 {
		return false
	}
	 := 
	if [0] == '"' {
		 = [1 : len()-1]
	}
	if [0] == '-' {
		 = [1:]
	}
	for ,  := range  {
		switch  {
		case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': // ok
		default:
			return false
		}
	}
	return true
}

// Uint64 decodes number as an unsigned 64-bit integer.
// Works on floats with zero fractional part.
func ( Num) () (uint64, error) {
	,  := .floatAsInt()
	if  != nil {
		return 0, errors.Wrap(, "float as int")
	}
	 := .dec()
	if  != -1 {
		.tail = 
	}
	return .UInt64()
}

// Float64 decodes number as 64-bit floating point.
func ( Num) () (float64, error) {
	 := .dec()
	return .Float64()
}

// Equal reports whether numbers are strictly equal, including their formats.
func ( Num) ( Num) bool {
	return bytes.Equal(, )
}

func ( Num) () string {
	if len() == 0 {
		return "<invalid>"
	}
	return string()
}

// Format implements fmt.Formatter.
func ( Num) ( fmt.State,  rune) {
	switch  {
	case 's', 'v':
		_, _ = .Write()
	case 'd':
		,  := .Int64()
		if  != nil {
			fmt.Fprintf(, "%%!invalid(Num=%s)", .String())
			return
		}
		 := big.NewInt()
		.Format(, )
	case 'f':
		,  := .Float64()
		if  != nil {
			fmt.Fprintf(, "%%!invalid(Num=%s)", .String())
			return
		}
		 := big.NewFloat()
		.Format(, )
	}
}

// Sign reports sign of number.
//
// 0 is zero, 1 is positive, -1 is negative.
func ( Num) () int {
	if len() == 0 {
		return 0
	}
	 := [0]
	if  == '"' {
		if len() < 2 {
			return 0
		}
		 = [1]
	}
	switch  {
	case '-':
		return -1
	case '0':
		return 0
	default:
		return 1
	}
}

// Positive reports whether number is positive.
func ( Num) () bool { return .Sign() > 0 }

// Negative reports whether number is negative.
func ( Num) () bool { return .Sign() < 0 }

// Zero reports whether number is zero.
func ( Num) () bool {
	if len() == 0 {
		return false
	}
	if len() == 1 {
		return [0] == '0'
	}
	for ,  := range  {
		switch  {
		case '.', '0', '-':
			continue
		default:
			return false
		}
	}
	return true
}