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

1# vim: set filetype=python fileencoding=utf-8: 

2# -*- coding: utf-8 -*- 

3 

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#============================================================================# 

19 

20 

21''' Generic types. ''' 

22# TODO: Independent package. 

23 

24 

25from . import __ 

26 

27 

28T = __.typx.TypeVar( 'T' ) # generic 

29U = __.typx.TypeVar( 'U' ) # generic 

30E = __.typx.TypeVar( 'E', bound = Exception ) # error 

31 

32 

33class Result( __.immut.Protocol, __.typx.Generic[ T, E ] ): 

34 ''' Either a value or an error. ''' 

35 

36 def is_error( self ) -> bool: 

37 ''' Returns ``True`` if error result. Else ``False``. ''' 

38 return isinstance( self, Error ) 

39 

40 def is_value( self ) -> bool: 

41 ''' Returns ``True`` if value result. Else ``False``. ''' 

42 return isinstance( self, Value ) 

43 

44 @__.abc.abstractmethod 

45 def extract( self ) -> T: 

46 ''' Extracts value from result. Else, raises error from result. 

47 

48 Similar to Result.unwrap in Rust. 

49 ''' 

50 raise NotImplementedError # pragma: no cover 

51 

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. 

57 

58 Similar to Result.map in Rust. 

59 ''' 

60 raise NotImplementedError # pragma: no cover 

61 

62 

63class Value( Result[ T, E ] ): 

64 ''' Result of successful computation. ''' 

65 

66 __match_args__ = ( 'value', ) 

67 __slots__ = ( 'value', ) 

68 

69 value: T 

70 

71 def __init__( self, value: T ): self.value = value 

72 

73 def extract( self ) -> T: return self.value 

74 

75 def transform( 

76 self, function: __.typx.Callable[ [ T ], U ] 

77 ) -> "Result[ U, E ]": return Value( function( self.value ) ) 

78 

79 

80class Error( Result[ T, E ] ): 

81 ''' Result of failed computation. ''' 

82 

83 __match_args__ = ( 'error', ) 

84 __slots__ = ( 'error', ) 

85 

86 error: E 

87 

88 def __init__( self, error: E ): self.error = error 

89 

90 def extract( self ) -> __.typx.Never: raise self.error 

91 

92 def transform( 

93 self, function: __.typx.Callable[ [ T ], U ] 

94 ) -> __.typx.Self: return self 

95 

96 

97GenericResult: __.typx.TypeAlias = Result[ __.typx.Any, Exception ] 

98 

99 

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 ) 

103 

104 

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 )