Coverage for sources/appcore/generics.py: 100%
32 statements
« prev ^ index » next coverage.py v7.10.7, created at 2025-09-27 22:40 +0000
« prev ^ index » next coverage.py v7.10.7, created at 2025-09-27 22:40 +0000
1# vim: set filetype=python fileencoding=utf-8:
2# -*- coding: utf-8 -*-
4#============================================================================#
5# #
6# Licensed under the Apache License, Version 2.0 (the "License"); #
7# you may not use this file except in compliance with the License. #
8# You may obtain a copy of the License at #
9# #
10# http://www.apache.org/licenses/LICENSE-2.0 #
11# #
12# Unless required by applicable law or agreed to in writing, software #
13# distributed under the License is distributed on an "AS IS" BASIS, #
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
15# See the License for the specific language governing permissions and #
16# limitations under the License. #
17# #
18#============================================================================#
21''' Generic types. '''
22# TODO: Independent package.
25from . import __
28T = __.typx.TypeVar( 'T' ) # generic
29U = __.typx.TypeVar( 'U' ) # generic
30E = __.typx.TypeVar( 'E', bound = Exception ) # error
33class Result( __.immut.Protocol, __.typx.Generic[ T, E ] ):
34 ''' Either a value or an error. '''
36 def is_error( self ) -> bool:
37 ''' Returns ``True`` if error result. Else ``False``. '''
38 return isinstance( self, Error )
40 def is_value( self ) -> bool:
41 ''' Returns ``True`` if value result. Else ``False``. '''
42 return isinstance( self, Value )
44 @__.abc.abstractmethod
45 def extract( self ) -> T:
46 ''' Extracts value from result. Else, raises error from result.
48 Similar to Result.unwrap in Rust.
49 '''
50 raise NotImplementedError # pragma: no cover
52 @__.abc.abstractmethod
53 def transform(
54 self, function: __.typx.Callable[ [ T ], U ]
55 ) -> __.typx.Self | "Result[ U, E ]":
56 ''' Transforms value in value result. Ignores error result.
58 Similar to Result.map in Rust.
59 '''
60 raise NotImplementedError # pragma: no cover
63class Value( Result[ T, E ] ):
64 ''' Result of successful computation. '''
66 __match_args__ = ( 'value', )
67 __slots__ = ( 'value', )
69 value: T
71 def __init__( self, value: T ): self.value = value
73 def extract( self ) -> T: return self.value
75 def transform(
76 self, function: __.typx.Callable[ [ T ], U ]
77 ) -> "Result[ U, E ]": return Value( function( self.value ) )
80class Error( Result[ T, E ] ):
81 ''' Result of failed computation. '''
83 __match_args__ = ( 'error', )
84 __slots__ = ( 'error', )
86 error: E
88 def __init__( self, error: E ): self.error = error
90 def extract( self ) -> __.typx.Never: raise self.error
92 def transform(
93 self, function: __.typx.Callable[ [ T ], U ]
94 ) -> __.typx.Self: return self
97GenericResult: __.typx.TypeAlias = Result[ __.typx.Any, Exception ]
100def is_error( result: Result[ T, E ] ) -> __.typx.TypeIs[ Error[ T, E ] ]:
101 ''' Type guard: Returns ``True`` if result is an error. '''
102 return isinstance( result, Error )
105def is_value( result: Result[ T, E ] ) -> __.typx.TypeIs[ Value[ T, E ] ]:
106 ''' Type guard: Returns ``True`` if result is a value. '''
107 return isinstance( result, Value )