// Integers without a width.
//
//     moon run src/examples/01-integers

///|
fn main raise {
  // Nothing here overflows: the digits grow until memory runs out.
  let hundred = @moonnum.parse_int("100")
  println("50! = \{@moonnum.factorial(50N)}")
  println("2^200 = \{@moonnum.power(2N, 200N)}")
  println("C(100, 50) = \{@moonnum.comb(hundred, 50N)}")
  println("isqrt(10^40) = \{@moonnum.isqrt(@moonnum.power(10N, 40N))}")

  // Floor division and modulo agree, whatever the signs are.
  println("")
  // Columns are padded with `format_int`, which is the library formatting itself.
  println("  " + "    a" + "     b" + "   a//b" + "    a%b")
  for (a, b) in [(7N, 2N), (-7N, 2N), (7N, -2N), (-7N, -2N)] {
    let (q, r) = @moonnum.divmod(a, b)
    println(
      "  " +
      @moonnum.format_int(a, ">5d") +
      @moonnum.format_int(b, ">6d") +
      @moonnum.format_int(q, ">7d") +
      @moonnum.format_int(r, ">7d"),
    )
  }

  // A negative exponent with a modulus is a modular inverse, not a fraction.
  println("")
  println("3^-1 mod 7 = \{@moonnum.power(3N, -1N, modulus=7N)}")
  println("2^1000 mod 97 = \{@moonnum.power(2N, 1000N, modulus=97N)}")

  // Reading and writing other bases, with the spellings Python accepts.
  println("")
  let value = @moonnum.parse_int("0xff_ec", base=0)
  println("0xff_ec = \{value}")
  println("base 2:  \{value.to_string(radix=2)}")
  println("base 36: \{value.to_string(radix=36)}")

  // Bytes are two's complement when asked, big-endian unless told otherwise.
  println("")
  let bytes = @moonnum.to_bytes(-2N, length=4, signed=true)
  println("(-2).to_bytes(4, signed=True) = \{hex_of(bytes)}")
  println("read back: \{@moonnum.of_bytes(bytes, signed=true)}")

  // Refusals are values, so a bad literal is a branch and not a crash.
  println("")
  let broken : String = @moonnum.parse_int("12x", base=0).to_string() catch {
    @moonnum.Malformed(at~, reason~) => "refused at \{at}: \{reason}"
    _ => "refused"
  }
  println("\"12x\" -> \{broken}")
}

///|
/// Hex, for printing byte arrays.
fn hex_of(bytes : Bytes) -> String {
  let alphabet = "0123456789abcdef"
  let sb = StringBuilder()
  for byte in bytes {
    let value = byte.to_int()
    sb.write_char(alphabet.get_char(value / 16).unwrap())
    sb.write_char(alphabet.get_char(value % 16).unwrap())
  }
  sb.to_string()
}