// Copyright (c) 2025 GeWuYou
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.Diagnostics.Contracts;
using System.Runtime.InteropServices;
namespace GFramework.Core.Functional;
///
/// 表示一个无值的操作结果,仅包含成功或失败状态
///
[StructLayout(LayoutKind.Auto)]
public readonly struct Result : IEquatable
{
private readonly Exception? _exception;
private readonly bool _isSuccess;
///
/// 私有构造函数,用于创建 Result 实例
///
/// 是否为成功状态
/// 失败时的异常信息
private Result(bool isSuccess, Exception? exception)
{
// 强制不变式:失败状态必须携带非空异常
if (!isSuccess && exception is null)
throw new ArgumentException("Failure Result must have a non-null exception.", nameof(exception));
_isSuccess = isSuccess;
_exception = exception;
}
///
/// 判断结果是否为成功状态
///
[Pure]
public bool IsSuccess => _isSuccess;
///
/// 判断结果是否为失败状态
///
[Pure]
public bool IsFailure => !_isSuccess;
///
/// 获取失败时的异常信息,若为成功状态则抛出 InvalidOperationException
///
[Pure]
public Exception Error => IsFailure
? _exception!
: throw new InvalidOperationException("Cannot access Error on a successful Result.");
///
/// 创建成功结果
///
/// 成功结果
[Pure]
public static Result Success() => new(true, null);
///
/// 创建失败结果
///
/// 失败的异常
/// 失败结果
[Pure]
public static Result Failure(Exception ex)
{
ArgumentNullException.ThrowIfNull(ex);
return new(false, ex);
}
///
/// 根据错误消息创建失败结果
///
/// 错误消息
/// 失败结果
[Pure]
public static Result Failure(string message)
{
ArgumentException.ThrowIfNullOrWhiteSpace(message);
return new Result(false, new InvalidOperationException(message));
}
///
/// 根据成功或失败状态分别执行不同的处理逻辑
///
/// 返回值类型
/// 成功时执行的函数
/// 失败时执行的函数
/// 处理后的结果
public R Match(Func onSuccess, Func onFailure) =>
IsSuccess ? onSuccess() : onFailure(_exception!);
///
/// 将当前无值的 Result 提升为带值的 Result
///
/// 值的类型
/// 成功时关联的值
/// 带值的 Result
[Pure]
public Result ToResult(A value) =>
IsSuccess ? Result.Success(value) : Result.Failure(_exception!);
///
/// 判断当前 Result 是否与另一个 Result 相等
///
/// 另一个 Result
/// 若相等返回 true,否则返回 false
[Pure]
public bool Equals(Result other)
{
if (_isSuccess != other._isSuccess)
return false;
if (_isSuccess)
return true;
return _exception!.GetType() == other._exception!.GetType() &&
_exception.Message == other._exception.Message;
}
///
/// 判断当前对象是否与另一个对象相等
///
/// 另一个对象
/// 若相等返回 true,否则返回 false
[Pure]
public override bool Equals(object? obj) => obj is Result other && Equals(other);
///
/// 获取当前 Result 的哈希码
///
/// 哈希码
[Pure]
public override int GetHashCode()
{
return _isSuccess ? 1 : HashCode.Combine(_exception!.GetType(), _exception.Message);
}
///
/// 判断两个 Result 是否相等
///
/// 第一个 Result
/// 第二个 Result
/// 若相等返回 true,否则返回 false
[Pure]
public static bool operator ==(Result a, Result b) => a.Equals(b);
///
/// 判断两个 Result 是否不相等
///
/// 第一个 Result
/// 第二个 Result
/// 若不相等返回 true,否则返回 false
[Pure]
public static bool operator !=(Result a, Result b) => !a.Equals(b);
///
/// 返回当前 Result 的字符串表示
///
/// Result 的字符串表示
[Pure]
public override string ToString() =>
_isSuccess ? "Success" : $"Fail({_exception!.Message})";
///
/// 尝试执行一个无返回值的操作,并根据执行结果返回成功或失败的 Result
///
/// 要执行的无返回值操作
/// 若操作成功执行返回成功的 Result,若执行过程中抛出异常则返回失败的 Result
[Pure]
public static Result Try(Action action)
{
ArgumentNullException.ThrowIfNull(action);
try
{
action();
return Success();
}
catch (Exception ex)
{
return Failure(ex);
}
}
///
/// 将当前 Result 的成功结果映射为另一种类型的 Result
///
/// 映射后的目标类型
/// 用于转换值的函数
/// 若当前为成功状态,返回包含转换后值的成功 Result;若为失败状态,返回保持原有错误的失败 Result
public Result Map(Func func)
{
ArgumentNullException.ThrowIfNull(func);
return IsSuccess ? Result.Success(func()) : Result.Failure(_exception!);
}
///
/// 将当前 Result 绑定到一个返回 Result 的函数上
///
/// Result 中值的类型
/// 返回 Result 的函数
/// 若当前为成功状态,返回函数执行的结果;若为失败状态,返回保持原有错误的失败 Result
public Result Bind(Func> func)
{
ArgumentNullException.ThrowIfNull(func);
return IsSuccess ? func() : Result.Failure(_exception!);
}
}