aboutsummaryrefslogtreecommitdiffstats
path: root/lua/mason-core/result.lua
blob: 0a615b8f85c87347a1f59b1948726b3bb7250d0c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
---@class Failure
---@field error any
local Failure = {}
Failure.__index = Failure

function Failure.new(error)
    return setmetatable({ error = error }, Failure)
end

---@class Result
---@field value any
local Result = {}
Result.__index = Result

function Result.new(value)
    return setmetatable({
        value = value,
    }, Result)
end

function Result.success(value)
    return Result.new(value)
end

function Result.failure(error)
    return Result.new(Failure.new(error))
end

function Result:get_or_nil()
    if self:is_success() then
        return self.value
    end
end

function Result:get_or_else(value)
    if self:is_success() then
        return self.value
    else
        return value
    end
end

---@param exception any: (optional) The exception to throw if the result is a failure.
function Result:get_or_throw(exception)
    if self:is_success() then
        return self.value
    else
        if exception ~= nil then
            error(exception, 2)
        else
            error(self.value.error, 2)
        end
    end
end

function Result:err_or_nil()
    if self:is_failure() then
        return self.value.error
    end
end

function Result:is_failure()
    return getmetatable(self.value) == Failure
end

function Result:is_success()
    return getmetatable(self.value) ~= Failure
end

---@param mapper_fn fun(value: any): any
function Result:map(mapper_fn)
    if self:is_success() then
        return Result.success(mapper_fn(self.value))
    else
        return self
    end
end

---@param mapper_fn fun(value: any): any
function Result:map_err(mapper_fn)
    if self:is_failure() then
        return Result.failure(mapper_fn(self.value.error))
    else
        return self
    end
end

---@param mapper_fn fun(value: any): any
function Result:map_catching(mapper_fn)
    if self:is_success() then
        local ok, result = pcall(mapper_fn, self.value)
        if ok then
            return Result.success(result)
        else
            return Result.failure(result)
        end
    else
        return self
    end
end

---@param recover_fn fun(value: any): any
function Result:recover(recover_fn)
    if self:is_failure() then
        return Result.success(recover_fn(self:err_or_nil()))
    else
        return self
    end
end

---@param recover_fn fun(value: any): any
function Result:recover_catching(recover_fn)
    if self:is_failure() then
        local ok, value = pcall(recover_fn, self:err_or_nil())
        if ok then
            return Result.success(value)
        else
            return Result.failure(value)
        end
    else
        return self
    end
end

---@param fn fun(value: any): any
function Result:on_failure(fn)
    if self:is_failure() then
        fn(self.value.error)
    end
    return self
end

---@param fn fun(value: any): any
function Result:on_success(fn)
    if self:is_success() then
        fn(self.value)
    end
    return self
end

---@param fn fun(): any
---@return Result
function Result.run_catching(fn)
    local ok, result = pcall(fn)
    if ok then
        return Result.success(result)
    else
        return Result.failure(result)
    end
end

return Result