diff --git a/package.json b/package.json index ebfb879..fb9a741 100644 --- a/package.json +++ b/package.json @@ -26,8 +26,8 @@ "lint:fix": "eslint . --fix", "pre-commit": "lint-staged", "prepare": "husky install", - "test": "node scripts/unit-test.js --color", - "test-full": "node scripts/unit-test.js --color", + "test": "node scripts/unit-test.js", + "test-full": "node scripts/unit-test.js", "typecheck": "tsc --project tsconfig.json --noEmit --incremental false" }, "devDependencies": { diff --git a/src/__tests__/result.test.ts b/src/__tests__/result.test.ts index 58372b4..edfd6b0 100644 --- a/src/__tests__/result.test.ts +++ b/src/__tests__/result.test.ts @@ -264,6 +264,18 @@ describe(`Test method \`${RustlikeResult.name}.prototype.${RustlikeResult.protot }); }); +describe(`Test method \`${RustlikeResult.name}.prototype.${RustlikeResult.prototype.unwrapUnchecked.name}\``, () => { + it('should unwrap itself to get the contained `Ok` value', () => { + expect(Ok(100).unwrapUnchecked()).toBe(100); + }); +}); + +describe(`Test method \`${RustlikeResult.name}.prototype.${RustlikeResult.prototype.unwrapErrUnchecked.name}\``, () => { + it('should unwrap itself to get the contained `Err` value', () => { + expect(Err('Err').unwrapErrUnchecked()).toBe('Err'); + }); +}); + describe(`Test method \`${RustlikeResult.name}.prototype.${RustlikeResult.prototype.and.name}\``, () => { it('should return `res`', () => { expect(op1().and(Ok(667)).ok()).toBe(667); diff --git a/src/result.class.ts b/src/result.class.ts index 645c7cc..5ec4ccb 100644 --- a/src/result.class.ts +++ b/src/result.class.ts @@ -216,6 +216,32 @@ export class RustlikeResult implements Result { return this.isOk() ? this._value! : op(this._error!); } + /** + * Returns the contained `Ok` value, without checking that the value is not an `Err`. + * + * **SAFETY**: Calling this method on an `Err` is undefined behavior. + * The safety contract must be upheld by the caller. + * + * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap_unchecked + */ + // TODO: find a way to do the check in debug/development mode. + unwrapUnchecked(): T { + return this._value!; + } + + /** + * Returns the contained `Err` value, without checking that the value is not an `Ok`. + * + * **SAFETY**: Calling this method on an `Ok` is undefined behavior. + * The safety contract must be upheld by the caller. + * + * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap_err_unchecked + */ + // TODO: find a way to do the check in debug/development mode. + unwrapErrUnchecked(): E { + return this._error!; + } + /** * Returns `res` if itself is `Ok`, otherwise returns the `Err` value of itself. * @@ -278,15 +304,21 @@ export class RustlikeResult implements Result { } private static _equal(self: unknown, other: unknown): boolean { + // TODO: find a better way to check if `self` and `other` is `Result` + // to support user customized `Result` implementation. + const isSelfResult = self instanceof RustlikeResult; const isOtherResult = other instanceof RustlikeResult; if (isSelfResult && isOtherResult) { - const isOk = self.isOk(); - if (isOk !== other.isOk()) return false; + const _self: Result = self; + const _other: Result = other; + + const isOk = _self.isOk(); + if (isOk !== _other.isOk()) return false; return isOk - ? RustlikeResult._equal(self._value, other._value) - : RustlikeResult._equal(self._error, other._error); + ? RustlikeResult._equal(_self.unwrapUnchecked(), _other.unwrapUnchecked()) + : RustlikeResult._equal(_self.unwrapErrUnchecked(), _other.unwrapErrUnchecked()); } return self === other || (Number.isNaN(self) && Number.isNaN(other)); @@ -295,11 +327,11 @@ export class RustlikeResult implements Result { /** * Returns `true` if `self` equals to `other`. */ - equal(other: RustlikeResult): boolean { + equal(other: Result): boolean { const isOk = this.isOk(); if (isOk !== other.isOk()) return false; return isOk - ? RustlikeResult._equal(this._value, other._value!) - : RustlikeResult._equal(this._error, other._error!); + ? RustlikeResult._equal(this._value, other.unwrapUnchecked()) + : RustlikeResult._equal(this._error, other.unwrapErrUnchecked()); } } diff --git a/src/result.interface.ts b/src/result.interface.ts index d43e641..0ad9277 100644 --- a/src/result.interface.ts +++ b/src/result.interface.ts @@ -166,6 +166,26 @@ export interface Result { */ unwrapOrElse(op: (err: E) => T): T; + /** + * Returns the contained `Ok` value, without checking that the value is not an `Err`. + * + * **SAFETY**: Calling this method on an `Err` is undefined behavior. + * The safety contract must be upheld by the caller. + * + * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap_unchecked + */ + unwrapUnchecked(): T; + + /** + * Returns the contained `Err` value, without checking that the value is not an `Ok`. + * + * **SAFETY**: Calling this method on an `Ok` is undefined behavior. + * The safety contract must be upheld by the caller. + * + * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap_err_unchecked + */ + unwrapErrUnchecked(): E; + /** * Returns `res` if itself is `Ok`, otherwise returns the `Err` value of itself. *