1
1
use crate :: {
2
2
AsObject , Py , PyObjectRef , PyPayload , PyRef , PyResult , VirtualMachine ,
3
- builtins:: { PyTuple , PyTupleRef , PyType } ,
3
+ builtins:: { PyBaseExceptionRef , PyTuple , PyTupleRef , PyType } ,
4
4
class:: { PyClassImpl , StaticType } ,
5
5
vm:: Context ,
6
6
} ;
7
7
8
8
#[ pyclass]
9
9
pub trait PyStructSequence : StaticType + PyClassImpl + Sized + ' static {
10
- const FIELD_NAMES : & ' static [ & ' static str ] ;
10
+ const REQUIRED_FIELD_NAMES : & ' static [ & ' static str ] ;
11
+ const OPTIONAL_FIELD_NAMES : & ' static [ & ' static str ] ;
11
12
12
13
fn into_tuple ( self , vm : & VirtualMachine ) -> PyTuple ;
13
14
@@ -17,10 +18,16 @@ pub trait PyStructSequence: StaticType + PyClassImpl + Sized + 'static {
17
18
. unwrap ( )
18
19
}
19
20
20
- fn try_elements_from < const FIELD_LEN : usize > (
21
- obj : PyObjectRef ,
22
- vm : & VirtualMachine ,
23
- ) -> PyResult < [ PyObjectRef ; FIELD_LEN ] > {
21
+ fn try_elements_from ( obj : PyObjectRef , vm : & VirtualMachine ) -> PyResult < Vec < PyObjectRef > > {
22
+ #[ cold]
23
+ fn sequence_length_error (
24
+ name : & str ,
25
+ len : usize ,
26
+ vm : & VirtualMachine ,
27
+ ) -> PyBaseExceptionRef {
28
+ vm. new_type_error ( format ! ( "{name} takes a sequence of length {len}" ) )
29
+ }
30
+
24
31
let typ = Self :: static_type ( ) ;
25
32
// if !obj.fast_isinstance(typ) {
26
33
// return Err(vm.new_type_error(format!(
@@ -30,13 +37,13 @@ pub trait PyStructSequence: StaticType + PyClassImpl + Sized + 'static {
30
37
// )));
31
38
// }
32
39
let seq: Vec < PyObjectRef > = obj. try_into_value ( vm) ?;
33
- let seq: [ PyObjectRef ; FIELD_LEN ] = seq . try_into ( ) . map_err ( |_| {
34
- vm . new_type_error ( format ! (
35
- "{} takes a sequence of length {}" ,
36
- typ . name ( ) ,
37
- FIELD_LEN
38
- ) )
39
- } ) ? ;
40
+ if seq. len ( ) < Self :: REQUIRED_FIELD_NAMES . len ( ) {
41
+ return Err ( sequence_length_error (
42
+ & typ . name ( ) ,
43
+ Self :: REQUIRED_FIELD_NAMES . len ( ) ,
44
+ vm ,
45
+ ) ) ;
46
+ }
40
47
Ok ( seq)
41
48
}
42
49
@@ -49,14 +56,14 @@ pub trait PyStructSequence: StaticType + PyClassImpl + Sized + 'static {
49
56
let ( body, suffix) = if let Some ( _guard) =
50
57
rustpython_vm:: recursion:: ReprGuard :: enter ( vm, zelf. as_object ( ) )
51
58
{
52
- if Self :: FIELD_NAMES . len ( ) == 1 {
59
+ if Self :: REQUIRED_FIELD_NAMES . len ( ) == 1 {
53
60
let value = zelf. first ( ) . unwrap ( ) ;
54
- let formatted = format_field ( ( value, Self :: FIELD_NAMES [ 0 ] ) ) ?;
61
+ let formatted = format_field ( ( value, Self :: REQUIRED_FIELD_NAMES [ 0 ] ) ) ?;
55
62
( formatted, "," )
56
63
} else {
57
64
let fields: PyResult < Vec < _ > > = zelf
58
65
. iter ( )
59
- . zip ( Self :: FIELD_NAMES . iter ( ) . copied ( ) )
66
+ . zip ( Self :: REQUIRED_FIELD_NAMES . iter ( ) . copied ( ) )
60
67
. map ( format_field)
61
68
. collect ( ) ;
62
69
( fields?. join ( ", " ) , "" )
@@ -74,7 +81,7 @@ pub trait PyStructSequence: StaticType + PyClassImpl + Sized + 'static {
74
81
75
82
#[ extend_class]
76
83
fn extend_pyclass ( ctx : & Context , class : & ' static Py < PyType > ) {
77
- for ( i, & name) in Self :: FIELD_NAMES . iter ( ) . enumerate ( ) {
84
+ for ( i, & name) in Self :: REQUIRED_FIELD_NAMES . iter ( ) . enumerate ( ) {
78
85
// cast i to a u8 so there's less to store in the getter closure.
79
86
// Hopefully there's not struct sequences with >=256 elements :P
80
87
let i = i as u8 ;
@@ -90,7 +97,7 @@ pub trait PyStructSequence: StaticType + PyClassImpl + Sized + 'static {
90
97
class. set_attr (
91
98
identifier ! ( ctx, __match_args__) ,
92
99
ctx. new_tuple (
93
- Self :: FIELD_NAMES
100
+ Self :: REQUIRED_FIELD_NAMES
94
101
. iter ( )
95
102
. map ( |& name| ctx. new_str ( name) . into ( ) )
96
103
. collect :: < Vec < _ > > ( ) ,
0 commit comments