1
1
use crate :: singledispatch:: builtins:: Builtins ;
2
2
use crate :: singledispatch:: typeref:: PyTypeReference ;
3
3
use crate :: singledispatch:: typing:: TypingModule ;
4
+ use pyo3:: exceptions:: PyRuntimeError ;
4
5
use pyo3:: prelude:: * ;
5
6
use pyo3:: types:: PyTuple ;
6
7
use pyo3:: { intern, Bound , PyObject , PyResult , Python } ;
@@ -18,6 +19,20 @@ pub(crate) fn get_obj_mro(cls: &Bound<'_, PyAny>) -> PyResult<HashSet<PyTypeRefe
18
19
Ok ( mro)
19
20
}
20
21
22
+ fn get_obj_bases ( cls : & Bound < ' _ , PyAny > ) -> PyResult < Vec < PyTypeReference > > {
23
+ match cls. getattr_opt ( intern ! ( cls. py( ) , "__bases__" ) ) {
24
+ Ok ( opt) => match opt {
25
+ Some ( b) => Ok ( b
26
+ . downcast :: < PyTuple > ( ) ?
27
+ . iter ( )
28
+ . map ( |item| PyTypeReference :: new ( item. unbind ( ) ) )
29
+ . collect ( ) ) ,
30
+ None => Ok ( Vec :: new ( ) ) ,
31
+ } ,
32
+ Err ( e) => Err ( e) ,
33
+ }
34
+ }
35
+
21
36
fn get_obj_subclasses ( cls : & Bound < ' _ , PyAny > ) -> PyResult < HashSet < PyTypeReference > > {
22
37
let subclasses: HashSet < _ > = cls
23
38
. call_method0 ( intern ! ( cls. py( ) , "__subclasses__" ) ) ?
@@ -28,12 +43,165 @@ fn get_obj_subclasses(cls: &Bound<'_, PyAny>) -> PyResult<HashSet<PyTypeReferenc
28
43
Ok ( subclasses)
29
44
}
30
45
46
+ fn find_merge_candidate ( py : Python , seqs : & [ & mut Vec < PyTypeReference > ] ) -> Option < PyTypeReference > {
47
+ let mut candidate: Option < & PyTypeReference > = None ;
48
+ for i1 in 0 ..seqs. len ( ) {
49
+ let s1 = & seqs[ i1] ;
50
+ candidate = Some ( & s1[ 0 ] ) ;
51
+ for i2 in 0 ..seqs. len ( ) {
52
+ let s2 = & seqs[ i2] ;
53
+ if s2[ 1 ..] . contains ( candidate. unwrap ( ) ) {
54
+ candidate = None ;
55
+ break ;
56
+ }
57
+ }
58
+ if candidate. is_some ( ) {
59
+ break ;
60
+ }
61
+ }
62
+ candidate. map ( |c| c. clone_ref ( py) )
63
+ }
64
+
65
+ struct C3Mro < ' a > {
66
+ seqs : & ' a mut Vec < & ' a mut Vec < PyTypeReference > > ,
67
+ }
68
+
69
+ impl C3Mro < ' _ > {
70
+ fn for_abcs < ' a > (
71
+ py : Python ,
72
+ abcs : & ' a mut Vec < & ' a mut Vec < PyTypeReference > > ,
73
+ ) -> PyResult < Vec < PyTypeReference > > {
74
+ C3Mro { seqs : abcs } . merge ( py)
75
+ }
76
+
77
+ fn merge ( & mut self , py : Python ) -> PyResult < Vec < PyTypeReference > > {
78
+ let mut result: Vec < PyTypeReference > = Vec :: new ( ) ;
79
+ loop {
80
+ let seqs = & mut self . seqs ;
81
+ seqs. retain ( |seq| !seq. is_empty ( ) ) ;
82
+ if seqs. is_empty ( ) {
83
+ return Ok ( result) ;
84
+ }
85
+ match find_merge_candidate ( py, seqs. as_slice ( ) ) {
86
+ Some ( c) => {
87
+ for i in 0 ..seqs. len ( ) {
88
+ let seq = & mut self . seqs [ i] ;
89
+ if seq[ 0 ] . eq ( & c) {
90
+ seq. remove ( 0 ) ;
91
+ }
92
+ }
93
+ result. push ( c) ;
94
+ }
95
+ None => return Err ( PyRuntimeError :: new_err ( "Inconsistent hierarchy" ) ) ,
96
+ }
97
+ }
98
+ }
99
+ }
100
+
101
+ fn c3_boundary ( py : Python , bases : & [ PyTypeReference ] ) -> usize {
102
+ let mut boundary = 0 ;
103
+
104
+ for ( i, base) in bases. iter ( ) . rev ( ) . enumerate ( ) {
105
+ if base
106
+ . wrapped ( )
107
+ . bind ( py)
108
+ . hasattr ( intern ! ( py, "__abstractmethods__" ) )
109
+ . unwrap ( )
110
+ {
111
+ boundary = bases. len ( ) - i;
112
+ break ;
113
+ }
114
+ }
115
+
116
+ boundary
117
+ }
118
+
31
119
fn c3_mro (
32
120
py : Python ,
33
- cls : Bound < ' _ , PyAny > ,
121
+ cls : & Bound < ' _ , PyAny > ,
34
122
abcs : Vec < PyTypeReference > ,
35
123
) -> PyResult < Vec < PyTypeReference > > {
36
- Ok ( abcs)
124
+ let bases = match get_obj_bases ( cls) {
125
+ Ok ( b) => {
126
+ if !b. is_empty ( ) {
127
+ b
128
+ } else {
129
+ return Ok ( Vec :: new ( ) ) ;
130
+ }
131
+ }
132
+ Err ( e) => return Err ( e) ,
133
+ } ;
134
+ let boundary = c3_boundary ( py, & bases) ;
135
+ eprintln ! ( "boundary = {boundary}" ) ;
136
+ let base = & bases[ boundary] ;
137
+
138
+ let ( explicit_bases, other_bases) = bases. split_at ( boundary) ;
139
+ let abstract_bases: Vec < _ > = abcs
140
+ . iter ( )
141
+ . flat_map ( |abc| {
142
+ if Builtins :: cached ( py)
143
+ . issubclass ( py, cls, base. wrapped ( ) . bind ( py) )
144
+ . unwrap ( )
145
+ && !bases. iter ( ) . any ( |b| {
146
+ Builtins :: cached ( py)
147
+ . issubclass ( py, b. wrapped ( ) . bind ( py) , base. wrapped ( ) . bind ( py) )
148
+ . unwrap ( )
149
+ } )
150
+ {
151
+ vec ! [ abc]
152
+ } else {
153
+ vec ! [ ]
154
+ }
155
+ } )
156
+ . collect ( ) ;
157
+
158
+ let new_abcs: Vec < _ > = abcs. iter ( ) . filter ( |c| abstract_bases. contains ( c) ) . collect ( ) ;
159
+
160
+ let mut mros: Vec < & mut Vec < PyTypeReference > > = Vec :: new ( ) ;
161
+
162
+ let mut cls_ref = vec ! [ PyTypeReference :: new( cls. clone( ) . unbind( ) ) ] ;
163
+ mros. push ( & mut cls_ref) ;
164
+
165
+ let mut explicit_bases_mro = Vec :: from_iter ( explicit_bases. iter ( ) . map ( |b| {
166
+ c3_mro (
167
+ py,
168
+ b. wrapped ( ) . bind ( py) ,
169
+ new_abcs. iter ( ) . map ( |abc| abc. clone_ref ( py) ) . collect ( ) ,
170
+ )
171
+ . unwrap ( )
172
+ } ) ) ;
173
+ mros. extend ( & mut explicit_bases_mro) ;
174
+
175
+ let mut abstract_bases_mro = Vec :: from_iter ( abstract_bases. iter ( ) . map ( |b| {
176
+ c3_mro (
177
+ py,
178
+ b. wrapped ( ) . bind ( py) ,
179
+ new_abcs. iter ( ) . map ( |abc| abc. clone_ref ( py) ) . collect ( ) ,
180
+ )
181
+ . unwrap ( )
182
+ } ) ) ;
183
+ mros. extend ( & mut abstract_bases_mro) ;
184
+
185
+ let mut other_bases_mro = Vec :: from_iter ( other_bases. iter ( ) . map ( |b| {
186
+ c3_mro (
187
+ py,
188
+ b. wrapped ( ) . bind ( py) ,
189
+ new_abcs. iter ( ) . map ( |abc| abc. clone_ref ( py) ) . collect ( ) ,
190
+ )
191
+ . unwrap ( )
192
+ } ) ) ;
193
+ mros. extend ( & mut other_bases_mro) ;
194
+
195
+ let mut explicit_bases_cloned = Vec :: from_iter ( explicit_bases. iter ( ) . map ( |b| b. clone_ref ( py) ) ) ;
196
+ mros. push ( & mut explicit_bases_cloned) ;
197
+
198
+ let mut abstract_bases_cloned = Vec :: from_iter ( abstract_bases. iter ( ) . map ( |b| b. clone_ref ( py) ) ) ;
199
+ mros. push ( & mut abstract_bases_cloned) ;
200
+
201
+ let mut other_bases_cloned = Vec :: from_iter ( other_bases. iter ( ) . map ( |b| b. clone_ref ( py) ) ) ;
202
+ mros. push ( & mut other_bases_cloned) ;
203
+
204
+ C3Mro :: for_abcs ( py, & mut mros)
37
205
}
38
206
39
207
pub ( crate ) fn compose_mro (
@@ -107,5 +275,5 @@ pub(crate) fn compose_mro(
107
275
}
108
276
} ) ;
109
277
110
- c3_mro ( py, cls, mro)
278
+ c3_mro ( py, & cls, mro)
111
279
}
0 commit comments