# typed: strict # frozen_string_literal: true require_relative "option/control_signal" require_relative "result" module Mangrove # Option is a type that represents either some value (`Some`) or no value (`None`). module Option extend T::Sig extend T::Generic extend T::Helpers include Kernel sealed! interface! InnerType = type_member class << self extend ::T::Sig sig { type_parameters(:InnerType).params(nilable: T.nilable(T.type_parameter(:InnerType))).returns(Mangrove::Option[T.type_parameter(:InnerType)]) } def from_nilable(nilable) case nilable when NilClass Mangrove::Option::None.new else Mangrove::Option::Some.new(nilable) end end end # Option::Some class Some extend T::Sig extend T::Generic extend T::Helpers include Option InnerType = type_member sig { params(inner: InnerType).void } def initialize(inner) @inner = T.let(inner, InnerType) end sig { override.params(other: BasicObject).returns(T::Boolean) } def ==(other) case other when Option::Some other.instance_variable_get(:@inner) == @inner when Option::None false else # rubocop:disable Lint/DuplicateBranch # Because == is defined on BasicObject, we can't be sure that `other` is an Option false end end sig { returns(InnerType) } def unwrap @inner end sig { override.params(_default: InnerType).returns(InnerType) } def unwrap_or(_default) @inner end sig { override.returns(InnerType) } def unwrap! @inner end sig { override.params(_message: String).returns(InnerType) } def expect!(_message) @inner end sig { override.params(_block: T.proc.returns(T.untyped)).returns(InnerType) } def expect_with!(&_block) @inner end sig { override.returns(T::Boolean) } def some? = true sig { override.returns(T::Boolean) } def none? = false sig { override.type_parameters(:NewInnerType).params(block: T.proc.params(inner: InnerType).returns(Option[T.type_parameter(:NewInnerType)])).returns(::Mangrove::Option[T.type_parameter(:NewInnerType)]) } def map(&block) block.call(@inner) end sig { override.params(_default: Option[InnerType]).returns(Option[InnerType]) } def or(_default) self end sig { override.type_parameters(:ErrType).params(_err: T.type_parameter(:ErrType)).returns(Mangrove::Result[InnerType, T.type_parameter(:ErrType)]) } def transpose(_err) Result::Ok.new(@inner) end private sig { returns(InnerType) } attr_reader :inner end # Option::None class None extend T::Sig extend T::Generic extend T::Helpers include Option InnerType = type_member sig { override.params(other: BasicObject).returns(T::Boolean) } def ==(other) case other when Option::Some false when Option::None true else # rubocop:disable Lint/DuplicateBranch # Because == is defined on BasicObject, we can't be sure that `other` is an Option false end end sig { override.params(default: InnerType).returns(InnerType) } def unwrap_or(default) default end sig { override.returns(InnerType) } def unwrap! raise Option::ControlSignal, "called `Option#unwrap!` on an `None` value: #{self}" end sig { override.params(message: String).returns(InnerType) } def expect!(message) raise Option::ControlSignal, message end sig { override.params(block: T.proc.returns(T.untyped)).returns(InnerType) } def expect_with!(&block) raise Option::ControlSignal, block.call end sig { override.returns(T::Boolean) } def some? = false sig { override.returns(T::Boolean) } def none? = true sig { override.type_parameters(:NewInnerType).params(_block: T.proc.params(inner: InnerType).returns(Option[T.type_parameter(:NewInnerType)])).returns(Option[T.type_parameter(:NewInnerType)]) } def map(&_block) T.cast(self, Option[T.type_parameter(:NewInnerType)]) end sig { override.params(default: Option[InnerType]).returns(Option[InnerType]) } def or(default) default end sig { override.type_parameters(:ErrType).params(err: T.type_parameter(:ErrType)).returns(Mangrove::Result[InnerType, T.type_parameter(:ErrType)]) } def transpose(err) Result::Err.new(err) end end sig { abstract.params(other: BasicObject).returns(T::Boolean) } def ==(other); end sig { abstract.params(default: InnerType).returns(InnerType) } def unwrap_or(default); end sig { abstract.returns(InnerType) } def unwrap!; end sig { abstract.params(message: String).returns(InnerType) } def expect!(message); end sig { abstract.params(block: T.proc.returns(T.untyped)).returns(InnerType) } def expect_with!(&block); end sig { abstract.returns(T::Boolean) } def some?; end sig { abstract.returns(T::Boolean) } def none?; end sig { abstract.type_parameters(:NewInnerType).params(block: T.proc.params(inner: InnerType).returns(Option[T.type_parameter(:NewInnerType)])).returns(::Mangrove::Option[T.type_parameter(:NewInnerType)]) } def map(&block); end sig { abstract.params(default: Option[InnerType]).returns(Option[InnerType]) } def or(default); end sig { abstract.type_parameters(:ErrType).params(err: T.type_parameter(:ErrType)).returns(Mangrove::Result[InnerType, T.type_parameter(:ErrType)]) } def transpose(err); end end end