_partial_arithmetic.pony


trait _PartialArithmetic
  fun add_partial[T: (Integer[T] val & Int)](x: T, y: T): T? =>
    (let r: T, let overflow: Bool) = x.addc(y)
    if overflow then error else r end

  fun sub_partial[T: (Integer[T] val & Int)](x: T, y: T): T? =>
    (let r: T, let overflow: Bool) = x.subc(y)
    if overflow then error else r end

  fun mul_partial[T: (Integer[T] val & Int)](x: T, y: T): T? =>
    (let r: T, let overflow: Bool) = x.mulc(y)
    if overflow then error else r end

primitive _UnsignedPartialArithmetic is _PartialArithmetic

  fun div_checked[T: _UnsignedInteger[T] val](x: T, y: T): (T, Bool) =>
    (x / y, (y == T.from[U8](0)))

  fun rem_checked[T: _UnsignedInteger[T] val](x: T, y: T): (T, Bool) =>
    (x % y, y == T.from[U8](0))

  fun div_partial[T: _UnsignedInteger[T] val](x: T, y: T): T? =>
    if (y == T.from[U8](0)) then
      error
    else
      x /~ y
    end

  fun rem_partial[T: _UnsignedInteger[T] val](x: T, y: T): T? =>
    if (y == T.from[U8](0)) then
      error
    else
      x %~ y
    end

  fun divrem_partial[T: _UnsignedInteger[T] val](x: T, y: T): (T, T)? =>
    if (y == T.from[U8](0)) then
      error
    else
      (x /~ y, x %~ y)
    end

primitive _SignedPartialArithmetic is _PartialArithmetic

  fun div_checked[T: (_SignedInteger[T, U] val & Signed), U: _UnsignedInteger[U] val](x: T, y: T): (T, Bool) =>
    (x / y, (y == T.from[I8](0)) or ((y == T.from[I8](I8(-1))) and (x == T.min_value())))

  fun rem_checked[T: (_SignedInteger[T, U] val & Signed), U: _UnsignedInteger[U] val](x: T, y: T): (T, Bool) =>
    (x % y, (y == T.from[I8](0)) or ((y == T.from[I8](I8(-1))) and (x == T.min_value())))

  fun div_partial[T: (_SignedInteger[T, U] val & Signed), U: _UnsignedInteger[U] val](x: T, y: T): T? =>
    if (y == T.from[I8](0)) or ((y == T.from[I8](I8(-1))) and (x == T.min_value())) then
      error
    else
      x /~ y
    end

  fun rem_partial[T: (_SignedInteger[T, U] val & Signed), U: _UnsignedInteger[U] val](x: T, y: T): T? =>
    if (y == T.from[I8](0)) or ((y == T.from[I8](I8(-1))) and (x == T.min_value())) then
      error
    else
      x %~ y
    end

  fun divrem_partial[T: (_SignedInteger[T, U] val & Signed), U: _UnsignedInteger[U] val](x: T, y: T): (T, T)? =>
    if (y == T.from[I8](0)) or ((y == T.from[I8](I8(-1))) and (x == T.min_value())) then
      error
    else
      (x/~y, x %~ y)
    end

  fun neg_partial[T: (_SignedInteger[T, U] val & Signed), U: _UnsignedInteger[U] val](x: T): T? =>
    if x == T.min_value() then
      error
    else
      -~x
    end