diff --git a/builtin/assert.mbt b/builtin/assert.mbt index b97b5754a..e9f8ddb2a 100644 --- a/builtin/assert.mbt +++ b/builtin/assert.mbt @@ -20,6 +20,32 @@ fn debug_string[T : Show](t : T) -> String { } ///| +/// Asserts that two values are equal. If they are not equal, raises a failure +/// with a message containing the source location and the values being compared. +/// +/// Parameters: +/// +/// * `a` : First value to compare. +/// * `b` : Second value to compare. +/// * `loc` : Source location information to include in failure messages. This is +/// usually automatically provided by the compiler. +/// +/// Throws a `Failure` error if the values are not equal, with a message showing +/// the location of the failing assertion and the actual values that were +/// compared. +/// +/// Example: +/// +/// ```moonbit +/// test "assert_eq" { +/// assert_eq!(1, 1) +/// assert_eq!("hello", "hello") +/// } +/// +/// test "panic assert_eq/not_equal" { +/// ignore(assert_eq!(1, 2)) // Will fail with message showing values and location +/// } +/// ``` pub fn assert_eq[T : Eq + Show](a : T, b : T, loc~ : SourceLoc = _) -> Unit! { if a != b { fail!("FAILED: \{loc} `\{a} == \{b}`") @@ -27,6 +53,32 @@ pub fn assert_eq[T : Eq + Show](a : T, b : T, loc~ : SourceLoc = _) -> Unit! { } ///| +/// Asserts that two values of the same type are not equal. If the values are +/// equal, raises a failure with a detailed error message including the source +/// location and string representation of both values. +/// +/// Parameters: +/// +/// * `first` : The first value to compare. +/// * `second` : The second value to compare. +/// * `location` : Source location information for error reporting. Defaults to +/// the current location. +/// +/// Throws a `Failure` error if the values are equal. The error message includes +/// the source location and string representations of both values. +/// +/// Example: +/// +/// ```moonbit +/// test "assert_not_eq" { +/// assert_not_eq!(1, 2) // Passes +/// assert_not_eq!(1, 1) // Fails with message showing values are equal +/// } +/// +/// test "panic assert_not_eq/equal_values" { +/// ignore(assert_not_eq!(42, 42)) // Fails with detailed error message +/// } +/// ``` pub fn assert_not_eq[T : Eq + Show]( a : T, b : T, @@ -40,6 +92,29 @@ pub fn assert_not_eq[T : Eq + Show]( } ///| +/// Asserts that the given boolean value is true. Throws an error with source +/// location information if the assertion fails. +/// +/// Parameters: +/// +/// * `condition` : The boolean value to be checked. +/// * `location` : The source location where the assertion is made. Defaults to +/// the current location. +/// +/// Throws a `Failure` error with a descriptive message including the source +/// location if the condition is false. +/// +/// Example: +/// +/// ```moonbit +/// test "assert_true" { +/// assert_true!(true) +/// } +/// +/// test "panic assert_true/false_condition" { +/// ignore(assert_true!(false)) // Throws Failure +/// } +/// ``` pub fn assert_true(x : Bool, loc~ : SourceLoc = _) -> Unit! { if not(x) { fail!("FAILED: \{loc} `\{x}` is not true") @@ -47,6 +122,30 @@ pub fn assert_true(x : Bool, loc~ : SourceLoc = _) -> Unit! { } ///| +/// Tests whether a boolean condition is false, throwing an error if the +/// condition is true. +/// +/// Parameters: +/// +/// * `condition` : The boolean condition to test. +/// * `location` : The source location where the assertion is made. Used in error +/// messages. +/// +/// Throws a `Failure` error if the condition is true. The error message includes +/// the source location and the value that was expected to be false. +/// +/// Example: +/// +/// ```moonbit +/// test "assert_false" { +/// assert_false!(false) +/// assert_false!(1 > 2) +/// } +/// +/// test "panic assert_false/with_true" { +/// assert_false!(true) // This will fail with an error message +/// } +/// ``` pub fn assert_false(x : Bool, loc~ : SourceLoc = _) -> Unit! { if x { let x = debug_string(x) diff --git a/builtin/autoloc.mbt b/builtin/autoloc.mbt index a5817a00b..a625cd749 100644 --- a/builtin/autoloc.mbt +++ b/builtin/autoloc.mbt @@ -13,9 +13,29 @@ // limitations under the License. ///| +/// Represents a source code location in a MoonBit program, containing +/// information about the file path, line number, and column number. Used +/// internally by the compiler for error reporting and debugging purposes. +/// +/// This type is public to all packages but its internal representation is +/// opaque. Users cannot construct values of this type directly; they are +/// automatically created by the compiler when needed. pub(all) type SourceLoc ///| +/// Converts a source location to its string representation. +/// +/// Parameters: +/// +/// * `source_location` : A source code location containing information about the +/// file path, line number, and column number. +/// +/// Returns a string representation of the source location, typically in the +/// format "file:line:column". +/// +/// Note: This function is primarily used internally by the compiler for error +/// reporting and debugging purposes. Source locations are automatically created +/// by the compiler when needed. pub fn SourceLoc::to_string(self : SourceLoc) -> String = "%loc_to_string" ///| @@ -24,9 +44,23 @@ pub impl Show for SourceLoc with output(self, logger) { } ///| +/// Represents a type for storing argument locations in source code. It is an +/// array of optional source locations, where each element corresponds to an +/// argument's location in the source code. Used internally by the compiler for +/// error reporting and debugging purposes. pub(all) type ArgsLoc Array[SourceLoc?] derive(Show) ///| +/// Converts an array of optional source locations to its JSON string +/// representation. Each location in the array is either represented as a string +/// if present, or "null" if absent. +/// +/// Parameters: +/// +/// * `self` : The array of optional source locations to be converted. +/// +/// Returns a JSON array string where each element is either a string +/// representation of a source location or "null". pub fn ArgsLoc::to_json(self : ArgsLoc) -> String { let buf = StringBuilder::new(size_hint=10) buf.write_char('[') diff --git a/builtin/bigint_nonjs.mbt b/builtin/bigint_nonjs.mbt index ec40c2e00..a27400311 100644 --- a/builtin/bigint_nonjs.mbt +++ b/builtin/bigint_nonjs.mbt @@ -79,19 +79,69 @@ let one : BigInt = 1N // Conversion Functions ///| -/// Convert an Int to a BigInt. +/// Converts a 32-bit signed integer to a BigInt. +/// +/// Parameters: +/// +/// * `value` : The 32-bit signed integer (`Int`) to be converted. +/// +/// Returns a `BigInt` equivalent to the input integer. +/// +/// Example: +/// +/// ```moonbit +/// test "BigInt::from_int" { +/// let big = BigInt::from_int(42) +/// inspect!(big, content="42") +/// let neg = BigInt::from_int(-42) +/// inspect!(neg, content="-42") +/// } +/// ``` pub fn BigInt::from_int(n : Int) -> BigInt { BigInt::from_int64(n.to_int64()) } ///| -/// Convert an UInt to a BigInt. +/// Converts an unsigned 32-bit integer to a `BigInt`. +/// +/// Parameters: +/// +/// * `value` : The unsigned 32-bit integer to be converted. +/// +/// Returns a `BigInt` representing the same numerical value as the input. +/// +/// Example: +/// +/// ```moonbit +/// test "BigInt::from_uint" { +/// let n = 42U +/// inspect!(BigInt::from_uint(n), content="42") +/// } +/// ``` pub fn BigInt::from_uint(n : UInt) -> BigInt { BigInt::from_uint64(n.to_uint64()) } ///| -/// Convert an Int64 to a BigInt. +/// Converts a signed 64-bit integer to a `BigInt`. +/// +/// Parameters: +/// +/// * `number` : A 64-bit signed integer (`Int64`) to be converted. +/// +/// Returns a `BigInt` value that represents the same numerical value as the +/// input. +/// +/// Example: +/// +/// ```moonbit +/// test "BigInt::from_int64" { +/// let big = BigInt::from_int64(9223372036854775807L) // max value of Int64 +/// inspect!(big, content="9223372036854775807") +/// let neg = BigInt::from_int64(-9223372036854775808L) // min value of Int64 +/// inspect!(neg, content="-9223372036854775808") +/// } +/// ``` pub fn BigInt::from_int64(n : Int64) -> BigInt { if n < 0L { -BigInt::from_uint64((-n).reinterpret_as_uint64()) @@ -100,8 +150,27 @@ pub fn BigInt::from_int64(n : Int64) -> BigInt { } } -///| -/// Convert an UInt64 to a BigInt. +///| +/// Converts an unsigned 64-bit integer to a `BigInt`. +/// +/// Parameters: +/// +/// * `value` : The unsigned 64-bit integer (`UInt64`) to be converted. +/// +/// Returns a new `BigInt` with the same value as the input. The resulting +/// `BigInt` will always have a positive sign since the input is an unsigned +/// integer. +/// +/// Example: +/// +/// ```moonbit +/// test "BigInt::from_uint64" { +/// let n = BigInt::from_uint64(12345678901234567890UL) +/// inspect!(n, content="12345678901234567890") +/// let zero = BigInt::from_uint64(0UL) +/// inspect!(zero, content="0") +/// } +/// ``` pub fn BigInt::from_uint64(n : UInt64) -> BigInt { if n == 0UL { return { limbs: FixedArray::make(1, 0), sign: Positive, len: 1 } @@ -120,7 +189,25 @@ pub fn BigInt::from_uint64(n : UInt64) -> BigInt { // Arithmetic Operations ///| -/// Negate a bigint +/// Negates a big integer, returning a new big integer with the opposite sign. If +/// the input is zero, returns zero. +/// +/// Parameters: +/// +/// * `self` : The big integer to negate. +/// +/// Returns a new big integer with the opposite sign of the input, or zero if the +/// input is zero. +/// +/// Example: +/// +/// ```moonbit +/// test "BigInt::op_neg" { +/// inspect!(-42N, content="-42") +/// inspect!(-(-42N), content="42") +/// inspect!(-0N, content="0") +/// } +/// ``` pub fn BigInt::op_neg(self : BigInt) -> BigInt { if self.is_zero() { return zero @@ -129,7 +216,27 @@ pub fn BigInt::op_neg(self : BigInt) -> BigInt { } ///| -/// Add two bigint. +/// Adds two arbitrary-precision integers. Handles positive and negative numbers +/// correctly by converting subtraction of negative numbers into addition of +/// positive numbers. +/// +/// Parameters: +/// +/// * `self` : The first big integer to add. +/// * `other` : The second big integer to add. +/// +/// Returns a new `BigInt` that represents the sum of the two input numbers. +/// +/// Example: +/// +/// ```moonbit +/// test "BigInt::op_add" { +/// let a = 9223372036854775807N // Max value of Int64 +/// let b = 1N +/// inspect!(a + b, content="9223372036854775808") // Beyond Int64 range +/// inspect!(-a + -b, content="-9223372036854775808") +/// } +/// ``` pub fn BigInt::op_add(self : BigInt, other : BigInt) -> BigInt { if self.sign == Negative { if other.sign == Negative { @@ -157,7 +264,27 @@ pub fn BigInt::op_add(self : BigInt, other : BigInt) -> BigInt { } ///| -/// Subtract two bigint +/// Subtracts one arbitrary-precision integer from another. Handles positive and +/// negative numbers appropriately. +/// +/// Parameters: +/// +/// * `self` : The minuend (the number to subtract from). +/// * `other` : The subtrahend (the number to be subtracted). +/// +/// Returns a new `BigInt` representing the difference between `self` and +/// `other`. +/// +/// Example: +/// +/// ```moonbit +/// test "BigInt::op_sub" { +/// let a = 12345678901234567890N +/// let b = 9876543210987654321N +/// inspect!(a - b, content="2469135690246913569") +/// inspect!(-a - b, content="-22222222112222222211") +/// } +/// ``` pub fn BigInt::op_sub(self : BigInt, other : BigInt) -> BigInt { // first make sure self and other > 0 if self.sign == Negative { @@ -209,7 +336,31 @@ pub fn BigInt::op_sub(self : BigInt, other : BigInt) -> BigInt { } ///| -/// Multiply two bigint +/// Multiplies two arbitrary-precision integers. Uses the most efficient +/// multiplication algorithm based on the size of the operands: +/// +/// * Grade school multiplication for small numbers +/// * Karatsuba multiplication for large numbers +/// +/// Parameters: +/// +/// * `self` : The first arbitrary-precision integer to multiply. +/// * `other` : The second arbitrary-precision integer to multiply. +/// +/// Returns the product of the two numbers. The sign of the result follows the +/// standard multiplication rules: positive if both operands have the same sign, +/// negative otherwise. +/// +/// Example: +/// +/// ```moonbit +/// test "BigInt::op_mul" { +/// let a = 12345678901234567890N +/// let b = -98765432109876543210N +/// inspect!(a * b, content="-1219326311370217952237463801111263526900") +/// inspect!(a * 0N, content="0") +/// } +/// ``` pub fn BigInt::op_mul(self : BigInt, other : BigInt) -> BigInt { if self.is_zero() || other.is_zero() { return zero @@ -277,7 +428,36 @@ fn BigInt::split(self : BigInt, half : Int) -> (BigInt, BigInt) { } ///| -/// Divide two bigint +/// Performs division between two arbitrary-precision integers, following +/// standard arithmetic rules for signed division. +/// +/// Parameters: +/// +/// * `self` : The dividend big integer. +/// * `other` : The divisor big integer. +/// +/// Returns the quotient of the division. +/// +/// Throws a panic if the divisor is zero. +/// +/// Example: +/// +/// ```moonbit +/// test "BigInt::op_div" { +/// let a = BigInt::from_string("100") +/// let b = BigInt::from_string("20") +/// inspect!(a / b, content="5") +/// inspect!(-a / b, content="-5") +/// inspect!(a / -b, content="-5") +/// inspect!(-a / -b, content="5") +/// } +/// +/// test "panic BigInt::op_div/division_by_zero" { +/// let a = BigInt::from_string("100") +/// let b = BigInt::from_string("0") +/// ignore(a / b) // Division by zero +/// } +/// ``` pub fn BigInt::op_div(self : BigInt, other : BigInt) -> BigInt { // TODO: // guard (other != zero, "division by zero") @@ -299,7 +479,34 @@ pub fn BigInt::op_div(self : BigInt, other : BigInt) -> BigInt { } ///| -/// Modulo two bigint +/// Calculates the modulo (remainder) of dividing one big integer by another. +/// +/// Parameters: +/// +/// * `self` : The dividend big integer. +/// * `other` : The divisor big integer. +/// +/// Returns the remainder of the division operation. +/// +/// Throws an error if `other` is zero. +/// +/// Example: +/// +/// ```moonbit +/// test "BigInt::op_mod" { +/// let a = 42N +/// let b = 5N +/// inspect!(a % b, content="2") +/// let c = -42N +/// let d = -5N +/// inspect!(c % d, content="-2") +/// } +/// +/// test "panic BigInt::op_mod/divide_by_zero" { +/// let a = 42N +/// ignore(a % 0N) // Division by zero +/// } +/// ``` pub fn BigInt::op_mod(self : BigInt, other : BigInt) -> BigInt { if other == zero { abort("division by zero") @@ -462,10 +669,34 @@ fn BigInt::grade_school_div(self : BigInt, other : BigInt) -> (BigInt, BigInt) { // Bitwise Operations ///| -/// Left shift a bigint -/// The sign of the result is the same as the sign of the input. -/// Only the absolute value is shifted. +/// Performs a left shift operation on a `BigInt` value. Preserves the sign of +/// the original number while shifting only its absolute value. +/// +/// Parameters: +/// +/// * `self` : The `BigInt` value to be shifted. +/// * `n` : The number of positions to shift left. Must be non-negative. +/// +/// Returns a new `BigInt` value that is the result of shifting the absolute +/// value of the input left by `n` positions, maintaining the original sign. +/// +/// Throws a panic if the shift count is negative. +/// +/// Example: +/// +/// ```moonbit +/// test "BigInt::op_shl" { +/// let x = 5N +/// inspect!(x << 2, content="20") +/// let y = -5N +/// inspect!(y << 2, content="-20") +/// } /// +/// test "panic BigInt::op_shl/negative_shift" { +/// let x = 5N +/// ignore(x << -1) // Panics with "negative shift count" +/// } +/// ``` pub fn BigInt::op_shl(self : BigInt, n : Int) -> BigInt { if n < 0 { abort("negative shift count") @@ -500,9 +731,36 @@ pub fn BigInt::op_shl(self : BigInt, n : Int) -> BigInt { } ///| -/// Right shift a bigint -/// The sign of the result is the same as the sign of the input. -/// Only the absolute value is shifted. +/// Performs arithmetic right shift operation on a big integer value. The shift +/// operation preserves the sign of the number while shifting the absolute value +/// right by `n` bits. For negative numbers, the result is rounded towards +/// negative infinity. +/// +/// Parameters: +/// +/// * `self` : The big integer value to be shifted. +/// * `n` : The number of bits to shift right. Must be non-negative. +/// +/// Returns a new `BigInt` value that represents the result of shifting `self` +/// right by `n` bits. +/// +/// Throws a panic if `n` is negative. +/// +/// Example: +/// +/// ```moonbit +/// test "BigInt::op_shr" { +/// let n = BigInt::from_string("1024") +/// inspect!(n >> 3, content="128") +/// let neg = BigInt::from_string("-1024") +/// inspect!(neg >> 3, content="-128") +/// } +/// +/// test "panic BigInt::op_shr/negative_shift" { +/// let n = BigInt::from_string("1024") +/// ignore(n >> -1) // Panics with "negative shift count" +/// } +/// ``` pub fn BigInt::op_shr(self : BigInt, n : Int) -> BigInt { if n < 0 { abort("negative shift count") @@ -544,13 +802,54 @@ pub fn BigInt::op_shr(self : BigInt, n : Int) -> BigInt { // Comparison Operations ///| -/// Check if a bigint is zero +/// Checks whether a `BigInt` value is equal to zero. +/// +/// Parameters: +/// +/// * `self` : The `BigInt` value to be checked. +/// +/// Returns `true` if the `BigInt` is zero, `false` otherwise. +/// +/// Example: +/// +/// ```moonbit +/// test "BigInt::is_zero" { +/// inspect!(0N.is_zero(), content="true") +/// inspect!(42N.is_zero(), content="false") +/// inspect!((-1N).is_zero(), content="false") +/// } +/// ``` pub fn BigInt::is_zero(self : BigInt) -> Bool { self.len == 1 && self.limbs[0] == 0 } ///| -/// Implements the compare trait for BigInt +/// Compares two arbitrary-precision integers and returns their relative order. +/// +/// Parameters: +/// +/// * `self` : The first arbitrary-precision integer to compare. +/// * `other` : The second arbitrary-precision integer to compare. +/// +/// Returns an integer indicating the relative order: +/// +/// * A negative value if `self` is less than `other` +/// * Zero if `self` equals `other` +/// * A positive value if `self` is greater than `other` +/// +/// Example: +/// +/// ```moonbit +/// test "BigInt::compare" { +/// let a = BigInt::from_string("42") +/// let b = BigInt::from_string("24") +/// let c = BigInt::from_string("-42") +/// inspect!(a.compare(b), content="1") // 42 > 24 +/// inspect!(b.compare(a), content="-1") // 24 < 42 +/// inspect!(c.compare(a), content="-1") // -42 < 42 +/// inspect!(a.compare(a), content="0") // 42 = 42 +/// } +/// ``` pub fn BigInt::compare(self : BigInt, other : BigInt) -> Int { if self.sign != other.sign { return if self.sign == Positive { 1 } else { -1 } @@ -577,7 +876,27 @@ pub fn BigInt::compare(self : BigInt, other : BigInt) -> Int { } ///| -/// Implements the Eq trait for BigInt +/// Compares two `BigInt` values for equality. Returns true if both numbers have +/// the same sign and magnitude. +/// +/// Parameters: +/// +/// * `self` : The first `BigInt` value to compare. +/// * `other` : The second `BigInt` value to compare. +/// +/// Returns `true` if the two `BigInt` values are equal, `false` otherwise. +/// +/// Example: +/// +/// ```moonbit +/// test "BigInt::op_equal" { +/// let a = 123456789N +/// let b = 123456789N +/// let c = -123456789N +/// inspect!(a == b, content="true") +/// inspect!(a == c, content="false") +/// } +/// ``` pub fn BigInt::op_equal(self : BigInt, other : BigInt) -> Bool { if self.sign != other.sign || self.len != other.len { return false @@ -591,7 +910,27 @@ pub fn BigInt::op_equal(self : BigInt, other : BigInt) -> Bool { } ///| -/// Returns the decimal string representation of the BigInt. +/// Converts a `BigInt` value to its decimal string representation. +/// +/// Parameters: +/// +/// * `self` : The `BigInt` value to convert to a string. +/// +/// Returns a string containing the decimal representation of the number, with a +/// leading minus sign for negative numbers. +/// +/// Example: +/// +/// ```moonbit +/// test "BigInt::to_string" { +/// let n = 12345678901234567890N +/// inspect!(n.to_string(), content="12345678901234567890") +/// let neg = -42N +/// inspect!(neg.to_string(), content="-42") +/// let zero = 0N +/// inspect!(zero.to_string(), content="0") +/// } +/// ``` pub fn BigInt::to_string(self : BigInt) -> String { // This function first converts the BigInt to a decimal representation, with a radix of 2^(`decimal_radix_bit_len`). // Then it converts the decimal representation to a string slot by slot. @@ -640,12 +979,64 @@ pub fn BigInt::to_string(self : BigInt) -> String { } ///| +/// Formats and writes a `BigInt` value to a logger by converting it to a string +/// representation. +/// +/// Implements the `Show` trait for `BigInt` type, allowing `BigInt` values to be +/// converted to strings and used in string interpolation. +/// +/// Parameters: +/// +/// * `self` : The `BigInt` value to be formatted. +/// * `logger` : A logger that implements the `Logger` trait, which will receive +/// the formatted string output. +/// +/// Example: +/// +/// ```moonbit +/// test "BigInt::output" { +/// let n = 12345678901234567890N +/// inspect!(n, content="12345678901234567890") +/// let neg = -42N +/// inspect!(neg, content="-42") +/// } +/// ``` pub impl Show for BigInt with output(self, logger) { logger.write_string(self.to_string()) } ///| -/// Converts decimal string to a BigInt. +/// Converts a decimal string representation to a BigInt value. The string can +/// optionally start with a minus sign (-) to indicate a negative number, +/// followed by one or more decimal digits. +/// +/// Parameters: +/// +/// * `input` : The string to be converted. Must be a valid decimal number string +/// consisting of optional leading minus sign followed by decimal digits (0-9). +/// +/// Returns a `BigInt` value representing the decimal number in the input string. +/// +/// Throws a panic if: +/// +/// * The input string is empty +/// * The input string contains non-decimal digits +/// +/// Example: +/// +/// ```moonbit +/// test "BigInt::from_string" { +/// let pos = BigInt::from_string("12345") +/// let neg = BigInt::from_string("-12345") +/// inspect!(pos, content="12345") +/// inspect!(neg, content="-12345") +/// } +/// +/// test "panic BigInt::from_string/invalid" { +/// ignore(BigInt::from_string("")) // Empty string +/// ignore(BigInt::from_string("12a34")) // Invalid character +/// } +/// ``` pub fn BigInt::from_string(input : String) -> BigInt { let len = input.length() if len == 0 { @@ -682,9 +1073,39 @@ pub fn BigInt::from_string(input : String) -> BigInt { } ///| -/// Converts a hex string to a BigInt. +/// Converts a hexadecimal string to a `BigInt`. The string can be prefixed with +/// a minus sign (`-`) to indicate a negative number. The string must contain +/// only hexadecimal digits (`0-9`, `a-f`, or `A-F`). +/// +/// Parameters: +/// +/// * `input` : A string containing the hexadecimal representation of an integer. +/// Must be non-empty and contain only valid hexadecimal digits. May be prefixed +/// with a minus sign to indicate a negative number. +/// +/// Returns a `BigInt` value representing the hexadecimal number. +/// +/// Throws a runtime error if: +/// +/// * The input string is empty. +/// * The input string contains characters other than hexadecimal digits (0-9, +/// a-f, A-F) or a leading minus sign. +/// +/// Example: +/// +/// ```moonbit +/// test "BigInt::from_hex" { +/// inspect!(BigInt::from_hex("ff"), content="255") +/// inspect!(BigInt::from_hex("-ff"), content="-255") +/// inspect!(BigInt::from_hex("DEADBEEF"), content="3735928559") +/// } /// -/// The input string must be a valid hex string with no extra `0x` prefix. +/// test "panic BigInt::from_hex/invalid_input" { +/// ignore(BigInt::from_hex("")) // Empty string +/// ignore(BigInt::from_hex("0x123")) // Invalid prefix +/// ignore(BigInt::from_hex("12g")) // Invalid character +/// } +/// ``` pub fn BigInt::from_hex(input : String) -> BigInt { // WARN: this implementation assumes that `radix_bit_len` is a multiple of 4. fn char_from_hex(c : Char) -> UInt { @@ -733,7 +1154,31 @@ pub fn BigInt::from_hex(input : String) -> BigInt { } ///| -/// Converts a BigInt to a hex string. +/// Converts a big integer to its hexadecimal string representation. The output +/// string has no prefix (like "0x") and uses uppercase letters A-F by default +/// for digits above 9. +/// +/// Parameters: +/// +/// * `self` : The `BigInt` value to be converted. +/// * `uppercase` : Whether to use uppercase (A-F) or lowercase (a-f) letters for +/// hexadecimal digits above 9. Defaults to `true`. +/// +/// Returns a string representing the number in hexadecimal format. For negative +/// numbers, the string is prefixed with a minus sign. +/// +/// Example: +/// +/// ```moonbit +/// test "BigInt::to_hex" { +/// let pos = BigInt::from_string("255") +/// let neg = BigInt::from_string("-255") +/// inspect!(pos.to_hex(), content="FF") +/// inspect!(neg.to_hex(), content="-FF") +/// inspect!(pos.to_hex(uppercase=false), content="ff") +/// inspect!(0N.to_hex(), content="0") +/// } +/// ``` pub fn BigInt::to_hex(self : BigInt, uppercase~ : Bool = true) -> String { // WARN: this implementation assumes that `radix_bit_len` is a multiple of 4. let mut result = "" @@ -943,6 +1388,35 @@ pub fn BigInt::to_octets(self : BigInt, length? : Int) -> Bytes { } ///| +/// Performs a bitwise AND operation between two arbitrary-precision integers. +/// +/// The operation is performed using two's complement representation, which means +/// it handles both positive and negative numbers correctly. For negative +/// numbers, the function first converts them to their two's complement form, +/// performs the AND operation, and then converts the result back if necessary. +/// +/// Parameters: +/// +/// * `self` : The first arbitrary-precision integer operand. +/// * `other` : The second arbitrary-precision integer operand. +/// +/// Returns a new `BigInt` representing the result of the bitwise AND operation. +/// +/// Example: +/// +/// ```moonbit +/// test "BigInt::land" { +/// let a = BigInt::from_string("42") // 0b101010 +/// let b = BigInt::from_string("-12") // ~0b1011 + 1 +/// inspect!(a & b, content="32") // 0b100000 +/// } +/// +/// test "BigInt::land/negative" { +/// let a = BigInt::from_string("-8") // ~0b111 + 1 +/// let b = BigInt::from_string("-4") // ~0b11 + 1 +/// inspect!(a & b, content="-12") // ~0b1011 + 1 +/// } +/// ``` pub fn BigInt::land(self : BigInt, other : BigInt) -> BigInt { let max_length = if self.limbs.length() < other.limbs.length() { other.limbs.length() + 1 @@ -1030,6 +1504,28 @@ pub fn BigInt::land(self : BigInt, other : BigInt) -> BigInt { } ///| +/// Performs a bitwise OR operation between two arbitrary-precision integers, +/// following two's complement representation for negative numbers. +/// +/// Parameters: +/// +/// * `self` : The first arbitrary-precision integer operand. +/// * `other` : The second arbitrary-precision integer operand. +/// +/// Returns a new `BigInt` representing the result of the bitwise OR operation. +/// +/// Example: +/// +/// ```moonbit +/// test "BigInt::lor" { +/// let a = BigInt::from_string("42") +/// let b = BigInt::from_string("-12") +/// inspect!(a | b, content="-2") +/// let c = BigInt::from_string("-8") +/// let d = BigInt::from_string("-4") +/// inspect!(c | d, content="-4") +/// } +/// ``` pub fn BigInt::lor(self : BigInt, other : BigInt) -> BigInt { let max_length = if self.limbs.length() < other.limbs.length() { other.limbs.length() + 1 @@ -1117,6 +1613,31 @@ pub fn BigInt::lor(self : BigInt, other : BigInt) -> BigInt { } ///| +/// Performs a bitwise XOR operation between two `BigInt` values, treating them +/// as two's complement binary numbers. +/// +/// Parameters: +/// +/// * `self` : The first `BigInt` operand. +/// * `other` : The second `BigInt` operand. +/// +/// Returns a new `BigInt` value representing the bitwise XOR of the two +/// operands. +/// +/// Example: +/// +/// ```moonbit +/// test "BigInt::lxor" { +/// let a = BigInt::from_string("42") +/// let b = BigInt::from_string("-7") +/// inspect!(a ^ b, content="-45") +/// } +/// +/// test "BigInt::lxor/zero" { +/// let a = BigInt::from_string("42") +/// inspect!(a ^ a, content="0") // XOR with self gives 0 +/// } +/// ``` pub fn BigInt::lxor(self : BigInt, other : BigInt) -> BigInt { let max_length = if self.limbs.length() < other.limbs.length() { other.limbs.length() + 1 diff --git a/builtin/byte.mbt b/builtin/byte.mbt index fccb370fa..a329c8642 100644 --- a/builtin/byte.mbt +++ b/builtin/byte.mbt @@ -13,11 +13,58 @@ // limitations under the License. ///| +/// Performs multiplication between two byte values. The result is truncated to +/// fit within the byte range. +/// +/// Parameters: +/// +/// * `self` : The first byte operand in the multiplication. +/// * `that` : The second byte operand in the multiplication. +/// +/// Returns the product of the two bytes, truncated to fit within the byte range +/// (0-255). +/// +/// Example: +/// +/// ```moonbit +/// test "Byte::op_mul" { +/// let a = b'\x02' +/// let b = b'\x03' +/// inspect!(a * b, content="b'\\x06'") // 2 * 3 = 6 +/// let c = b'\xFF' +/// inspect!(c * c, content="b'\\x01'") // 255 * 255 = 65025, truncated to 1 +/// } +/// ``` pub fn Byte::op_mul(self : Byte, that : Byte) -> Byte { (self.to_int() * that.to_int()).to_byte() } ///| +/// Performs division operation between two bytes by converting them to integers, +/// performing the division, and converting the result back to a byte. +/// +/// Parameters: +/// +/// * `self` : The dividend byte value. +/// * `that` : The divisor byte value. +/// +/// Returns the quotient of the division as a byte. +/// +/// Example: +/// +/// ```moonbit +/// test "Byte::op_div" { +/// let a = b'\xFF' // 255 +/// let b = b'\x03' // 3 +/// inspect!(a / b, content="b'\\x55'") // 255 / 3 = 85 (0x55) +/// } +/// +/// test "panic Byte::op_div/division_by_zero" { +/// let a = b'\x01' +/// let b = b'\x00' +/// ignore(a / b) // Division by zero +/// } +/// ``` pub fn Byte::op_div(self : Byte, that : Byte) -> Byte { (self.to_int() / that.to_int()).to_byte() } @@ -119,9 +166,44 @@ pub fn Byte::to_string(self : Byte) -> String { } ///| +/// Implements the `Hash` trait for `Byte` type by converting the byte to an +/// integer and using it as the hash value. +/// +/// Parameters: +/// +/// * `self` : The byte value to be hashed. +/// +/// Returns an integer representing the hash value of the byte. +/// +/// Example: +/// +/// ```moonbit +/// test "Byte::hash" { +/// let b = b'\x42' +/// inspect!(Hash::hash(b), content="66") // ASCII value of 'B' +/// } +/// ``` pub impl Hash for Byte with hash(self) { self.to_int() } ///| +/// Implements the `Hash` trait for `Byte` type by providing a `hash_combine` +/// method that combines a byte value with a hasher. +/// +/// Parameters: +/// +/// * `self` : The byte value to be hashed. +/// * `hasher` : The hasher object that will be used to combine the byte value +/// into its internal state. +/// +/// Example: +/// +/// ```moonbit +/// test "Byte::hash_combine" { +/// let hasher = Hasher::new() +/// hasher.combine_byte(b'\xFF') +/// inspect!(hasher.finalize(), content="3735928559") +/// } +/// ``` pub impl Hash for Byte with hash_combine(self, hasher) { hasher.combine_byte(self) } diff --git a/builtin/bytes.mbt b/builtin/bytes.mbt index 11296184b..fd7d45cd7 100644 --- a/builtin/bytes.mbt +++ b/builtin/bytes.mbt @@ -50,7 +50,24 @@ pub fn Bytes::makei(length : Int, value : (Int) -> Byte) -> Bytes { } ///| -/// Create byte sequence from String. +/// Creates a byte sequence from a UTF-16 encoded string. Each character in the +/// string is encoded as a pair of bytes in little-endian order. +/// +/// Parameters: +/// +/// * `string` : The input string to be converted to a byte sequence. +/// +/// Returns a new byte sequence containing the UTF-16LE encoded representation of +/// the input string. +/// +/// Example: +/// +/// ```moonbit +/// test "Bytes::of_string" { +/// let bytes = Bytes::of_string("ABC") +/// inspect!(bytes, content="b\"\\x41\\x00\\x42\\x00\\x43\\x00\"") +/// } +/// ``` pub fn Bytes::of_string(str : String) -> Bytes { FixedArray::make(str.length() * 2, Byte::default()) ..blit_from_string(0, str, 0, str.length()) @@ -80,8 +97,27 @@ pub fn Bytes::sub_string( } ///| -/// Create a new unchecked string from byte sequence. -/// +/// Creates a new string from the given byte sequence without encoding +/// validation. The byte sequence must be a valid UTF-16LE encoded string, +/// otherwise the behavior is undefined. +/// +/// Parameters: +/// +/// * `bytes` : The byte sequence to be converted to a string. Must be a valid +/// UTF-16LE encoded string. +/// +/// Returns a string containing the decoded characters from the byte sequence. +/// +/// Example: +/// +/// ```moonbit +/// test "Bytes::to_string" { +/// let bytes = Bytes::of_string("Hello") +/// let s = bytes.to_unchecked_string() // Use the new API instead +/// inspect!(s, content="Hello") +/// } +/// ``` +/// /// @alert deprecated "Use `to_unchecked_string` instead" /// @coverage.skip pub fn Bytes::to_string(self : Bytes) -> String { @@ -106,8 +142,40 @@ pub fn Bytes::to_unchecked_string( } ///| -/// Copy `length` chars from string `str`, starting at `str_offset`, -/// into byte sequence `self`, starting at `bytes_offset`. +/// Copies characters from a string to a byte sequence in UTF-16LE encoding. Each +/// character is converted into two bytes, with the lower byte stored first. +/// +/// Parameters: +/// +/// * `self` : The destination byte array to copy the characters into. +/// * `bytes_offset` : The starting position in the destination array where bytes +/// will be written. +/// * `str` : The source string containing the characters to copy. +/// * `str_offset` : The starting position in the source string from which +/// characters will be read. +/// * `length` : The number of characters to copy. +/// +/// Throws a runtime error if: +/// +/// * `length` is negative +/// * `bytes_offset` is negative +/// * `str_offset` is negative +/// * The range `[bytes_offset, bytes_offset + length * 2)` exceeds the length of +/// the destination array +/// * The range `[str_offset, str_offset + length)` exceeds the length of the +/// source string +/// +/// Example: +/// +/// ```moonbit +/// test "FixedArray::blit_from_string" { +/// let bytes = FixedArray::make(6, b'\x00') +/// bytes.blit_from_string(0, "ABC", 0, 3) +/// inspect!(bytes[0], content="b'\\x41'") // 'A' +/// inspect!(bytes[1], content="b'\\x00'") +/// inspect!(bytes[2], content="b'\\x42'") // 'B' +/// } +/// ``` pub fn FixedArray::blit_from_string( self : FixedArray[Byte], bytes_offset : Int, @@ -154,14 +222,64 @@ pub fn FixedArray::blit_from_bytes( } ///| -/// Return a new Bytes that contains the same byte sequence. +/// Creates a new byte sequence by copying all bytes from the input sequence. +/// +/// Parameters: +/// +/// * `bytes` : The byte sequence to be copied. +/// +/// Returns a new `Bytes` containing the same sequence of bytes as the input. +/// +/// Example: +/// +/// ```moonbit +/// test "Bytes::copy" { +/// let original = b"\x01\x02\x03" +/// let copy = original.copy() +/// inspect!(copy, content="b\"\\x01\\x02\\x03\"") +/// } +/// ``` pub fn Bytes::copy(self : Bytes) -> Bytes { Bytes::new(self.length())..blit(0, self, 0, self.length()) } ///| -/// Fill UTF8 encoded char `value` into byte sequence `self`, starting at `offset`. -/// It return the length of bytes has been written. +/// Encodes a Unicode character into UTF-8 bytes and writes them into a fixed +/// array of bytes at the specified offset. +/// +/// Parameters: +/// +/// * `array` : The fixed array of bytes to write into. +/// * `offset` : The starting position in the array where the encoded bytes will +/// be written. +/// * `char` : The Unicode character to be encoded. +/// +/// Returns the number of bytes written (1 to 4 bytes depending on the +/// character's code point). +/// +/// Throws a panic if: +/// +/// * The character's code point is greater than 0x10FFFF. +/// * The array's size is insufficient to store the encoded bytes at the given +/// offset. +/// +/// Example: +/// +/// ```moonbit +/// test "FixedArray::set_utf8_char" { +/// let buf = FixedArray::make(4, b'\x00') +/// let written = buf.set_utf8_char(0, '€') // Euro symbol (U+20AC) +/// inspect!(written, content="3") // UTF-8 encoding takes 3 bytes +/// inspect!(buf[0], content="b'\\xE2'") +/// inspect!(buf[1], content="b'\\x82'") +/// inspect!(buf[2], content="b'\\xAC'") +/// } +/// +/// test "panic FixedArray::set_utf8_char/invalid_char" { +/// let buf = FixedArray::make(4, b'\x00') +/// ignore(buf.set_utf8_char(0, Char::from_int(0x110000))) // Invalid Unicode code point +/// } +/// ``` pub fn FixedArray::set_utf8_char( self : FixedArray[Byte], offset : Int, @@ -282,6 +400,27 @@ pub fn FixedArray::set_utf16be_char( } ///| +/// Compares two byte sequences for equality. Returns true only if both sequences +/// have the same length and contain identical bytes in the same order. +/// +/// Parameters: +/// +/// * `self` : The first byte sequence to compare. +/// * `other` : The second byte sequence to compare. +/// +/// Returns `true` if the byte sequences are equal, `false` otherwise. +/// +/// Example: +/// +/// ```moonbit +/// test "Bytes::op_equal" { +/// let bytes1 = b"\x01\x02\x03" +/// let bytes2 = b"\x01\x02\x03" +/// let bytes3 = b"\x01\x02\x04" +/// inspect!(bytes1 == bytes2, content="true") +/// inspect!(bytes1 == bytes3, content="false") +/// } +/// ``` pub fn Bytes::op_equal(self : Bytes, other : Bytes) -> Bool { if self.length() != other.length() { false diff --git a/builtin/bytes_block.mbt b/builtin/bytes_block.mbt index fd471019c..ee43ab4e4 100644 --- a/builtin/bytes_block.mbt +++ b/builtin/bytes_block.mbt @@ -22,16 +22,44 @@ fn Bytes::unsafe_blit( ) = "$moonbit.unsafe_bytes_blit" ///| -/// Transfer bytes. +/// Copies a sequence of bytes from a source byte sequence to a destination byte +/// sequence. /// -/// It copies `length` bytes from `src` begin at `src_offset`, to destination byte sequence `self` begin at `dst_offset`. +/// Parameters: /// -/// # Usage -/// ``` -/// let b1 = Bytes::of_string("abcdef") -/// let b2 = Bytes::of_string("ABCDEF") -/// b1.blit(2, b2, 2, 2) -/// assert_eq!(b1.to_unchecked_string(), "aBcdef") +/// * `self` : The destination byte sequence where bytes will be copied to. +/// * `dst_offset` : The starting position in the destination sequence where +/// bytes will be written. +/// * `src` : The source byte sequence from which bytes will be copied. +/// * `src_offset` : The starting position in the source sequence from which +/// bytes will be read. +/// * `length` : The number of bytes to copy. +/// +/// Throws a runtime error if: +/// +/// * `length` is negative +/// * `dst_offset` is negative +/// * `src_offset` is negative +/// * The range `[dst_offset, dst_offset + length)` exceeds the length of the +/// destination sequence +/// * The range `[src_offset, src_offset + length)` exceeds the length of the +/// source sequence +/// +/// Example: +/// +/// ```moonbit +/// test "Bytes::blit" { +/// let dst = Bytes::of_string("Hello, world!") +/// let src = Bytes::of_string("MOONBIT") +/// dst.blit(7, src, 0, 4) +/// inspect!(dst.to_unchecked_string(), content="Hello, MOON!") +/// } +/// +/// test "panic Bytes::blit/out_of_bounds" { +/// let dst = Bytes::of_string("Hello") +/// let src = Bytes::of_string("World") +/// ignore(dst.blit(3, src, 0, 10)) // Range exceeds destination length +/// } /// ``` pub fn Bytes::blit( self : Bytes, diff --git a/builtin/bytesview.mbt b/builtin/bytesview.mbt index 3498558f4..c49b546f5 100644 --- a/builtin/bytesview.mbt +++ b/builtin/bytesview.mbt @@ -32,13 +32,54 @@ struct BytesView { } ///| -/// Returns the length of the BytesView. +/// Returns the number of bytes in the view. +/// +/// Parameters: +/// +/// * `bytes_view` : The view of a byte sequence. +/// +/// Returns an integer representing the length of the view. +/// +/// Example: +/// +/// ```moonbit +/// test "BytesView::length" { +/// let bytes = b"\x00\x01\x02\x03\x04" +/// let view = bytes[2:4] +/// inspect!(view.length(), content="2") +/// } +/// ``` pub fn BytesView::length(self : BytesView) -> Int { self.len } ///| -/// Returns the byte at the given index. +/// Retrieves a byte from the view at the specified index. +/// +/// Parameters: +/// +/// * `self` : The bytes view to retrieve the byte from. +/// * `index` : The position in the view from which to retrieve the byte. +/// +/// Returns the byte at the specified index. +/// +/// Throws a runtime error if the index is out of bounds (negative or greater +/// than or equal to the length of the view). +/// +/// Example: +/// +/// ```moonbit +/// test "BytesView::op_get" { +/// let bytes = b"\x01\x02\x03\x04\x05" +/// let view = bytes[1:4] // view contains [0x02, 0x03, 0x04] +/// inspect!(view[1], content="b'\\x03'") +/// } +/// +/// test "panic BytesView::op_get/out_of_bounds" { +/// let view = b"\x01\x02\x03"[:] +/// ignore(view[3]) // Index out of bounds +/// } +/// ``` pub fn BytesView::op_get(self : BytesView, index : Int) -> Byte { guard index >= 0 && index < self.len else { abort( @@ -49,6 +90,35 @@ pub fn BytesView::op_get(self : BytesView, index : Int) -> Byte { } ///| +/// Retrieves a byte at the specified index from a bytes view without performing +/// bounds checking. +/// +/// Parameters: +/// +/// * `self` : The bytes view to retrieve the byte from. +/// * `index` : The position in the view from which to retrieve the byte. The +/// index is relative to the start of the view, not the underlying bytes. +/// +/// Returns a single byte from the specified position in the view. +/// +/// Throws a panic if the index is out of bounds (less than 0 or greater than or +/// equal to the length of the view). +/// +/// Example: +/// +/// ```moonbit +/// test "BytesView::unsafe_get" { +/// let bytes = b"\x01\x02\x03\x04\x05" +/// let view = bytes[2:4] // view contains [0x03, 0x04] +/// inspect!(view.unsafe_get(0), content="b'\\x03'") +/// } +/// +/// test "panic BytesView::unsafe_get/out_of_bounds" { +/// let view = b"\x01\x02\x03"[:] +/// ignore(view.unsafe_get(3)) // Panic: index out of bounds +/// } +/// ``` +/// /// @alert unsafe "Panic if index is out of bounds" pub fn BytesView::unsafe_get(self : BytesView, index : Int) -> Byte { self.bytes[self.start + index] @@ -134,7 +204,30 @@ pub fn BytesView::iter(self : BytesView) -> Iter[Byte] { }) } -///| Converts the 4 bytes long BytesView to a UInt in big-endian byte order. +///| +/// Converts a 4-byte sequence to an unsigned 32-bit integer using big-endian +/// byte order. The first byte is treated as the most significant byte, and the +/// last byte as the least significant byte. +/// +/// Parameters: +/// +/// * `self` : A byte view containing exactly 4 bytes to be converted. +/// +/// Returns an unsigned 32-bit integer representing the byte sequence. +/// +/// Example: +/// +/// ```moonbit +/// test "BytesView::to_uint_be" { +/// let bytes = b"\x12\x34\x56\x78"[:] +/// inspect!(bytes.to_uint_be(), content="305419896") // 0x12345678 +/// } +/// +/// test "panic BytesView::to_uint_be/out_of_bounds" { +/// let bytes = b"\x12\x34\x56"[:] // Less than 4 bytes +/// ignore(bytes.to_uint_be()) // Panics with index out of bounds +/// } +/// ``` pub fn BytesView::to_uint_be(self : BytesView) -> UInt { (self[0].to_uint() << 24) + (self[1].to_uint() << 16) + @@ -142,7 +235,30 @@ pub fn BytesView::to_uint_be(self : BytesView) -> UInt { self[3].to_uint() } -///| Converts the 4 bytes long BytesView to a UInt in little-endian byte order. +///| +/// Converts a sequence of 4 bytes into an unsigned 32-bit integer using +/// little-endian byte order. Each byte in the view contributes 8 bits to the +/// final integer, with the least significant byte at index 0. +/// +/// Parameters: +/// +/// * `view` : A `BytesView` containing exactly 4 bytes to be interpreted as a +/// little-endian unsigned integer. +/// +/// Returns an unsigned 32-bit integer (`UInt`) formed by interpreting the bytes +/// in little-endian order. +/// +/// Throws a panic if the view does not contain exactly 4 bytes. +/// +/// Example: +/// +/// ```moonbit +/// test "BytesView::to_uint_le" { +/// let bytes = b"\x01\x02\x03\x04" +/// let view = bytes[:] +/// inspect!(view.to_uint_le(), content="67305985") // 0x04030201 +/// } +/// ``` pub fn BytesView::to_uint_le(self : BytesView) -> UInt { self[0].to_uint() + (self[1].to_uint() << 8) + @@ -150,7 +266,36 @@ pub fn BytesView::to_uint_le(self : BytesView) -> UInt { (self[3].to_uint() << 24) } -///| Converts the 8 bytes long BytesView to a UInt64 in big-endian byte order. +///| +/// Converts a sequence of 8 bytes into a 64-bit unsigned integer using +/// big-endian byte order. The most significant byte is at index 0, and the least +/// significant byte is at index 7. +/// +/// Parameters: +/// +/// * `bytes` : A view into a byte sequence that must be at least 8 bytes long. +/// The bytes are interpreted in big-endian order, where the first byte is the +/// most significant byte. +/// +/// Returns a 64-bit unsigned integer constructed by concatenating the bytes in +/// big-endian order. +/// +/// Throws a runtime error if the byte sequence view is less than 8 bytes long or +/// if attempting to access an index beyond the view's bounds. +/// +/// Example: +/// +/// ```moonbit +/// test "BytesView::to_uint64_be" { +/// let bytes = b"\x01\x23\x45\x67\x89\xAB\xCD\xEF"[:] +/// inspect!(bytes.to_uint64_be(), content="81985529216486895") +/// } +/// +/// test "panic BytesView::to_uint64_be/short_input" { +/// let bytes = b"\x01\x02\x03"[:] +/// ignore(bytes.to_uint64_be()) // Throws error: index out of bounds +/// } +/// ``` pub fn BytesView::to_uint64_be(self : BytesView) -> UInt64 { (self[0].to_uint().to_uint64() << 56) + (self[1].to_uint().to_uint64() << 48) + @@ -162,7 +307,37 @@ pub fn BytesView::to_uint64_be(self : BytesView) -> UInt64 { self[7].to_uint().to_uint64() } -///| Converts the 8 bytes long BytesView to a UInt64 in little-endian byte order. +///| +/// Converts an 8-byte sequence to an unsigned 64-bit integer using little-endian +/// byte order. Each byte in the view is treated as an 8-bit unsigned integer and +/// combined to form the final 64-bit value, with the least significant byte +/// first. +/// +/// Parameters: +/// +/// * `bytes_view` : A view into a byte sequence that must be exactly 8 bytes +/// long. Each byte represents one byte of the resulting 64-bit integer, with the +/// first byte being the least significant. +/// +/// Returns an unsigned 64-bit integer assembled from the bytes in little-endian +/// order. +/// +/// Throws a panic if the BytesView is less than 8 bytes long or if trying to +/// access a byte beyond the view's bounds. +/// +/// Example: +/// +/// ```moonbit +/// test "BytesView::to_uint64_le" { +/// let bytes = b"\x01\x02\x03\x04\x05\x06\x07\x08"[:] +/// inspect!(bytes.to_uint64_le(), content="578437695752307201") +/// } +/// +/// test "panic BytesView::to_uint64_le/short_view" { +/// let bytes = b"\x01\x02\x03"[:] +/// ignore(bytes.to_uint64_le()) // Panics: view is too short +/// } +/// ``` pub fn BytesView::to_uint64_le(self : BytesView) -> UInt64 { self[0].to_uint().to_uint64() + (self[1].to_uint().to_uint64() << 8) + @@ -174,42 +349,211 @@ pub fn BytesView::to_uint64_le(self : BytesView) -> UInt64 { (self[7].to_uint().to_uint64() << 56) } -///| Converts the 4 bytes long BytesView to a Int in big-endian byte order. +///| +/// Converts a 4-byte view of bytes to a 32-bit signed integer by interpreting +/// the bytes in big-endian order (most significant byte first). Interprets the +/// resulting unsigned integer as a signed integer using two's complement +/// representation. +/// +/// Parameters: +/// +/// * `bytesView` : A view into a byte sequence that must be exactly 4 bytes +/// long. The bytes are interpreted in big-endian order, where the first byte is +/// the most significant byte and the last byte is the least significant byte. +/// +/// Returns a 32-bit signed integer constructed from the bytes in big-endian +/// order. +/// +/// Example: +/// +/// ```moonbit +/// test "BytesView::to_int_be" { +/// let bytes = b"\x80\x00\x00\x00"[:] // Represents -2147483648 in two's complement +/// inspect!(bytes.to_int_be(), content="-2147483648") +/// } +/// ``` pub fn BytesView::to_int_be(self : BytesView) -> Int { self.to_uint_be().reinterpret_as_int() } -///| Converts the 4 bytes long BytesView to a Int in little-endian byte order. +///| +/// Converts 4 bytes from a byte sequence into a 32-bit signed integer using +/// little-endian byte order. The bytes are interpreted as follows: the least +/// significant byte is at the lowest address (first position), and the most +/// significant byte is at the highest address (last position). +/// +/// Parameters: +/// +/// * `bytes_view` : A view into a byte sequence that must be exactly 4 bytes +/// long. The bytes are interpreted as a little-endian representation of a 32-bit +/// integer. +/// +/// Returns a 32-bit signed integer (`Int`) constructed from the 4 bytes in +/// little-endian order. +/// +/// Example: +/// +/// ```moonbit +/// test "BytesView::to_int_le" { +/// let bytes = b"\x78\x56\x34\x12" +/// let view = bytes[:] +/// inspect!(view.to_int_le(), content="305419896") // 0x12345678 in decimal +/// } +/// ``` pub fn BytesView::to_int_le(self : BytesView) -> Int { self.to_uint_le().reinterpret_as_int() } -///| Converts the 8 bytes long BytesView to a Int64 in big-endian byte order. +///| +/// Interprets an 8-byte view as a signed 64-bit integer in big-endian byte +/// order. The highest byte (index 0) is treated as the most significant byte. +/// +/// Parameters: +/// +/// * `bytes_view` : A view containing exactly 8 bytes to be interpreted as a +/// big-endian signed 64-bit integer. +/// +/// Returns a 64-bit signed integer (`Int64`) value constructed by interpreting +/// the bytes in big-endian order. +/// +/// Example: +/// +/// ```moonbit +/// test "BytesView::to_int64_be" { +/// let bytes = b"\x80\x00\x00\x00\x00\x00\x00\x00"[:] // Most negative 64-bit integer +/// inspect!(bytes.to_int64_be(), content="-9223372036854775808") +/// } +/// ``` pub fn BytesView::to_int64_be(self : BytesView) -> Int64 { self.to_uint64_be().reinterpret_as_int64() } -///| Converts the 8 bytes long BytesView to a Int64 in little-endian byte order. +///| +/// Converts a sequence of 8 bytes into a signed 64-bit integer using +/// little-endian byte order. In little-endian order, the least significant byte +/// is stored at the lowest address (first byte). +/// +/// Parameters: +/// +/// * `bytes_view` : A view into a sequence of exactly 8 bytes. The first byte +/// represents the least significant byte of the resulting integer. +/// +/// Returns a 64-bit signed integer (`Int64`) constructed from the bytes in +/// little-endian order. +/// +/// Example: +/// +/// ```moonbit +/// test "BytesView::to_int64_le" { +/// let bytes = b"\x01\x02\x03\x04\x05\x06\x07\x08" +/// let view = bytes[:] +/// inspect!(view.to_int64_le(), content="578437695752307201") +/// } +/// ``` pub fn BytesView::to_int64_le(self : BytesView) -> Int64 { self.to_uint64_le().reinterpret_as_int64() } -///| Converts the 4 bytes long BytesView to a Float in big-endian byte order. +///| +/// Converts a 4-byte sequence to a 32-bit floating-point number using big-endian +/// byte order. +/// +/// Parameters: +/// +/// * `bytes_view` : A view into a byte sequence that must be exactly 4 bytes +/// long. The bytes are interpreted in big-endian order (most significant byte +/// first). +/// +/// Returns a 32-bit floating-point number obtained by interpreting the 4 bytes +/// as an IEEE 754 single-precision value. +/// +/// Example: +/// +/// ```moonbit +/// test "BytesView::to_float_be" { +/// let bytes = b"\x40\x48\xF5\xC3" // Represents 3.14 in IEEE 754 format +/// let view = bytes[:] +/// let float = view.to_float_be() +/// // Convert to double for comparison since Float doesn't implement Show +/// inspect!(float.to_double(), content="3.140000104904175") +/// } +/// ``` pub fn BytesView::to_float_be(self : BytesView) -> Float { self.to_uint_be().reinterpret_as_float() } -///| Converts the 4 bytes long BytesView to a Float in little-endian byte order. +///| +/// Converts 4 bytes from a bytes view to a 32-bit floating-point number, +/// interpreting the bytes in little-endian order (least significant byte first). +/// +/// Parameters: +/// +/// * `self` : A bytes view containing at least 4 bytes to be interpreted as a +/// floating-point number. +/// +/// Returns a 32-bit floating-point value constructed from the bytes. +/// +/// Example: +/// +/// ```moonbit +/// test "BytesView::to_float_le" { +/// let bytes = b"\x00\x00\x80\x3F" // Represents 1.0 in little-endian IEEE-754 +/// let f = bytes[:].to_float_le() +/// inspect!(f.to_double(), content="1") +/// } +/// ``` pub fn BytesView::to_float_le(self : BytesView) -> Float { self.to_uint_le().reinterpret_as_float() } -///| Converts the 8 bytes long BytesView to a Double in big-endian byte order. +///| +/// Converts the bytes in a byte view to a double-precision floating-point number +/// using big-endian byte order. The byte view must contain exactly 8 bytes, +/// which represent the IEEE 754 double-precision format. +/// +/// Parameters: +/// +/// * `byte_view` : The byte view containing exactly 8 bytes to be interpreted as +/// a double-precision floating-point number in big-endian order. +/// +/// Returns a double-precision floating-point number reconstructed from the +/// bytes. +/// +/// Example: +/// +/// ```moonbit +/// test "BytesView::to_double_be" { +/// // Bytes representing 1.0 in IEEE 754 double-precision format (big-endian) +/// let bytes = b"\x3F\xF0\x00\x00\x00\x00\x00\x00" +/// let view = bytes[:] +/// inspect!(view.to_double_be(), content="1") +/// } +/// ``` pub fn BytesView::to_double_be(self : BytesView) -> Double { self.to_uint64_be().reinterpret_as_double() } -///| Converts the 8 bytes long BytesView to a Double in little-endian byte order. +///| +/// Converts the bytes in the view to a double-precision floating-point number +/// using little-endian byte order. Interprets the first 8 bytes as a IEEE 754 +/// double-precision binary floating-point format (binary64) value. +/// +/// Parameters: +/// +/// * `bytes` : The byte view to be converted. Must contain at least 8 bytes. +/// +/// Returns a `Double` value representing the bytes interpreted in little-endian +/// order. +/// +/// Example: +/// +/// ```moonbit +/// test "BytesView::to_double_le" { +/// let bytes = b"\x00\x00\x00\x00\x00\x00\xF0\x3F" // represents 1.0 in little-endian +/// let view = bytes[:] +/// inspect!(view.to_double_le(), content="1") +/// } +/// ``` pub fn BytesView::to_double_le(self : BytesView) -> Double { self.to_uint64_le().reinterpret_as_double() }