@@ -87,3 +87,109 @@ pub enum EbpfError {
87
87
#[ error( "Syscall error: {0}" ) ]
88
88
SyscallError ( Box < dyn Error > ) ,
89
89
}
90
+
91
+ /// Same as `Result` but provides a stable memory layout
92
+ #[ derive( Debug ) ]
93
+ #[ repr( C , u64 ) ]
94
+ pub enum StableResult < T , E > {
95
+ /// Success
96
+ Ok ( T ) ,
97
+ /// Failure
98
+ Err ( E ) ,
99
+ }
100
+
101
+ impl < T : std:: fmt:: Debug , E : std:: fmt:: Debug > StableResult < T , E > {
102
+ /// `true` if `Ok`
103
+ pub fn is_ok ( & self ) -> bool {
104
+ match self {
105
+ Self :: Ok ( _) => true ,
106
+ Self :: Err ( _) => false ,
107
+ }
108
+ }
109
+
110
+ /// `true` if `Err`
111
+ pub fn is_err ( & self ) -> bool {
112
+ match self {
113
+ Self :: Ok ( _) => false ,
114
+ Self :: Err ( _) => true ,
115
+ }
116
+ }
117
+
118
+ /// Returns the inner value if `Ok`, panics otherwise
119
+ pub fn unwrap ( self ) -> T {
120
+ match self {
121
+ Self :: Ok ( value) => value,
122
+ Self :: Err ( error) => panic ! ( "unwrap {:?}" , error) ,
123
+ }
124
+ }
125
+
126
+ /// Returns the inner error if `Err`, panics otherwise
127
+ pub fn unwrap_err ( self ) -> E {
128
+ match self {
129
+ Self :: Ok ( value) => panic ! ( "unwrap_err {:?}" , value) ,
130
+ Self :: Err ( error) => error,
131
+ }
132
+ }
133
+
134
+ /// Maps ok values, leaving error values untouched
135
+ pub fn map < U , O : FnOnce ( T ) -> U > ( self , op : O ) -> StableResult < U , E > {
136
+ match self {
137
+ Self :: Ok ( value) => StableResult :: < U , E > :: Ok ( op ( value) ) ,
138
+ Self :: Err ( error) => StableResult :: < U , E > :: Err ( error) ,
139
+ }
140
+ }
141
+
142
+ /// Maps error values, leaving ok values untouched
143
+ pub fn map_err < F , O : FnOnce ( E ) -> F > ( self , op : O ) -> StableResult < T , F > {
144
+ match self {
145
+ Self :: Ok ( value) => StableResult :: < T , F > :: Ok ( value) ,
146
+ Self :: Err ( error) => StableResult :: < T , F > :: Err ( op ( error) ) ,
147
+ }
148
+ }
149
+
150
+ #[ cfg_attr(
151
+ any(
152
+ not( feature = "jit" ) ,
153
+ target_os = "windows" ,
154
+ not( target_arch = "x86_64" )
155
+ ) ,
156
+ allow( dead_code)
157
+ ) ]
158
+ pub ( crate ) fn discriminant ( & self ) -> u64 {
159
+ unsafe { * ( self as * const _ as * const u64 ) }
160
+ }
161
+ }
162
+
163
+ impl < T , E > From < StableResult < T , E > > for Result < T , E > {
164
+ fn from ( result : StableResult < T , E > ) -> Self {
165
+ match result {
166
+ StableResult :: Ok ( value) => Ok ( value) ,
167
+ StableResult :: Err ( value) => Err ( value) ,
168
+ }
169
+ }
170
+ }
171
+
172
+ impl < T , E > From < Result < T , E > > for StableResult < T , E > {
173
+ fn from ( result : Result < T , E > ) -> Self {
174
+ match result {
175
+ Ok ( value) => Self :: Ok ( value) ,
176
+ Err ( value) => Self :: Err ( value) ,
177
+ }
178
+ }
179
+ }
180
+
181
+ /// Return value of programs and syscalls
182
+ pub type ProgramResult = StableResult < u64 , EbpfError > ;
183
+
184
+ #[ cfg( test) ]
185
+ mod tests {
186
+ use super :: * ;
187
+
188
+ #[ test]
189
+ fn test_program_result_is_stable ( ) {
190
+ let ok = ProgramResult :: Ok ( 42 ) ;
191
+ assert_eq ! ( ok. discriminant( ) , 0 ) ;
192
+ let err = ProgramResult :: Err ( EbpfError :: JitNotCompiled ) ;
193
+ assert_eq ! ( err. discriminant( ) , 1 ) ;
194
+ }
195
+ }
0 commit comments