1
- //! Mapping protocol
2
-
3
- use crate :: { vm:: VirtualMachine , PyObjectRef , PyResult , TryFromBorrowedObject , TypeProtocol } ;
1
+ use crate :: {
2
+ builtins:: dict:: { PyDictKeys , PyDictRef , PyDictValues } ,
3
+ builtins:: list:: PyList ,
4
+ vm:: VirtualMachine ,
5
+ IdProtocol , IntoPyObject , PyObjectRef , PyResult , TryFromBorrowedObject , TryFromObject ,
6
+ TypeProtocol ,
7
+ } ;
8
+ use std:: borrow:: Borrow ;
9
+ use std:: ops:: Deref ;
4
10
11
+ // Mapping protocol
12
+ // https://docs.python.org/3/c-api/mapping.html
5
13
#[ allow( clippy:: type_complexity) ]
6
- pub struct PyMapping {
14
+ pub struct PyMappingMethods {
7
15
pub length : Option < fn ( PyObjectRef , & VirtualMachine ) -> PyResult < usize > > ,
8
16
pub subscript : Option < fn ( PyObjectRef , PyObjectRef , & VirtualMachine ) -> PyResult > ,
9
17
pub ass_subscript :
10
18
Option < fn ( PyObjectRef , PyObjectRef , Option < PyObjectRef > , & VirtualMachine ) -> PyResult < ( ) > > ,
11
19
}
12
20
13
- impl PyMapping {
14
- pub fn check ( cls : & PyObjectRef , vm : & VirtualMachine ) -> bool {
15
- if let Ok ( mapping) = PyMapping :: try_from_borrowed_object ( vm, cls) {
16
- mapping. subscript . is_some ( )
17
- } else {
18
- false
19
- }
20
- }
21
- }
22
-
23
- impl TryFromBorrowedObject for PyMapping {
21
+ impl TryFromBorrowedObject for PyMappingMethods {
24
22
fn try_from_borrowed_object ( vm : & VirtualMachine , obj : & PyObjectRef ) -> PyResult < Self > {
25
23
let obj_cls = obj. class ( ) ;
26
24
for cls in obj_cls. iter_mro ( ) {
@@ -34,3 +32,111 @@ impl TryFromBorrowedObject for PyMapping {
34
32
) ) )
35
33
}
36
34
}
35
+
36
+ #[ derive( Debug , Clone ) ]
37
+ #[ repr( transparent) ]
38
+ pub struct PyMapping < T = PyObjectRef > ( T )
39
+ where
40
+ T : Borrow < PyObjectRef > ;
41
+
42
+ impl PyMapping < PyObjectRef > {
43
+ pub fn into_object ( self ) -> PyObjectRef {
44
+ self . 0
45
+ }
46
+
47
+ pub fn check ( obj : & PyObjectRef , vm : & VirtualMachine ) -> bool {
48
+ if let Ok ( mapping) = PyMappingMethods :: try_from_borrowed_object ( vm, obj) {
49
+ mapping. subscript . is_some ( )
50
+ } else {
51
+ false
52
+ }
53
+ }
54
+ }
55
+
56
+ impl < T > PyMapping < T >
57
+ where
58
+ T : Borrow < PyObjectRef > ,
59
+ {
60
+ pub fn new ( obj : T ) -> Self {
61
+ Self ( obj)
62
+ }
63
+
64
+ pub fn keys ( & self , vm : & VirtualMachine ) -> PyResult {
65
+ if self . 0 . borrow ( ) . is ( & vm. ctx . types . dict_type ) {
66
+ Ok (
67
+ PyDictKeys :: new ( PyDictRef :: try_from_object ( vm, self . 0 . borrow ( ) . clone ( ) ) ?)
68
+ . into_pyobject ( vm) ,
69
+ )
70
+ } else {
71
+ Self :: method_output_as_list ( self . 0 . borrow ( ) , "keys" , vm)
72
+ }
73
+ }
74
+
75
+ pub fn values ( & self , vm : & VirtualMachine ) -> PyResult {
76
+ if self . 0 . borrow ( ) . is ( & vm. ctx . types . dict_type ) {
77
+ Ok (
78
+ PyDictValues :: new ( PyDictRef :: try_from_object ( vm, self . 0 . borrow ( ) . clone ( ) ) ?)
79
+ . into_pyobject ( vm) ,
80
+ )
81
+ } else {
82
+ Self :: method_output_as_list ( self . 0 . borrow ( ) , "values" , vm)
83
+ }
84
+ }
85
+
86
+ fn method_output_as_list (
87
+ obj : & PyObjectRef ,
88
+ method_name : & str ,
89
+ vm : & VirtualMachine ,
90
+ ) -> PyResult {
91
+ let meth_output = vm. call_method ( obj, method_name, ( ) ) ?;
92
+ if meth_output. is ( & vm. ctx . types . list_type ) {
93
+ return Ok ( meth_output) ;
94
+ }
95
+
96
+ let iter = meth_output. clone ( ) . get_iter ( vm) . map_err ( |_| {
97
+ vm. new_type_error ( format ! (
98
+ "{}.{}() returned a non-iterable (type {})" ,
99
+ obj. class( ) ,
100
+ method_name,
101
+ meth_output. class( )
102
+ ) )
103
+ } ) ?;
104
+
105
+ Ok ( PyList :: from ( vm. extract_elements ( & iter) ?) . into_pyobject ( vm) )
106
+ }
107
+ }
108
+
109
+ impl < T > Borrow < PyObjectRef > for PyMapping < T >
110
+ where
111
+ T : Borrow < PyObjectRef > ,
112
+ {
113
+ fn borrow ( & self ) -> & PyObjectRef {
114
+ self . 0 . borrow ( )
115
+ }
116
+ }
117
+
118
+ impl < T > Deref for PyMapping < T >
119
+ where
120
+ T : Borrow < PyObjectRef > ,
121
+ {
122
+ type Target = PyObjectRef ;
123
+ fn deref ( & self ) -> & Self :: Target {
124
+ self . 0 . borrow ( )
125
+ }
126
+ }
127
+
128
+ impl IntoPyObject for PyMapping < PyObjectRef > {
129
+ fn into_pyobject ( self , _vm : & VirtualMachine ) -> PyObjectRef {
130
+ self . into_object ( )
131
+ }
132
+ }
133
+
134
+ impl TryFromObject for PyMapping < PyObjectRef > {
135
+ fn try_from_object ( vm : & VirtualMachine , mapping : PyObjectRef ) -> PyResult < Self > {
136
+ if Self :: check ( & mapping, vm) {
137
+ Ok ( Self :: new ( mapping) )
138
+ } else {
139
+ Err ( vm. new_type_error ( format ! ( "{} is not a mapping object" , mapping. class( ) ) ) )
140
+ }
141
+ }
142
+ }
0 commit comments