1/* 2 * NOTE: the implementation uses PyDict_* APIs whenever possible and falls 3 * back to the generic PyObject_* APIs otherwise. We don't use the PyMapping_* 4 * APIs because those are incomplete(!). 5 */ 6#include "pyobjc.h" 7#import "OC_PythonDictionary.h" 8 9static PyObject* mapTypes = NULL; 10 11/* 12 * OC_PythonDictionaryEnumerator - Enumerator for Python dictionaries 13 * 14 * This class implements an NSEnumerator for proxied Python dictionaries. 15 */ 16@interface OC_PythonDictionaryEnumerator : NSEnumerator 17{ 18 OC_PythonDictionary* value; 19 BOOL valid; 20 Py_ssize_t pos; 21} 22+ newWithWrappedDictionary:(OC_PythonDictionary*)value; 23- initWithWrappedDictionary:(OC_PythonDictionary*)value; 24-(void)dealloc; 25 26-(id)nextObject; 27 28@end /* interface OC_PythonDictionaryEnumerator */ 29 30 31 32@implementation OC_PythonDictionaryEnumerator 33 34+newWithWrappedDictionary:(OC_PythonDictionary*)v; 35{ 36 return [[[self alloc] initWithWrappedDictionary:v] autorelease]; 37} 38 39-initWithWrappedDictionary:(OC_PythonDictionary*)v; 40{ 41 self = [super init]; 42 if (unlikely(self == nil)) return nil; 43 44 value = [v retain]; 45 valid = YES; 46 pos = 0; 47 return self; 48} 49 50-(void)dealloc 51{ 52 [value release]; 53 [super dealloc]; 54} 55 56-(id)nextObject 57{ 58 id key = nil; 59 60 if (valid) { 61 valid = [value wrappedKey:&key value:nil atPosition:&pos]; 62 } 63 return key; 64} 65 66@end // implementation OC_PythonDictionaryEnumerator 67 68 69@implementation OC_PythonDictionary 70 71+ depythonifyObject:(PyObject*)object 72{ 73 Py_ssize_t i, len; 74 75 if (mapTypes == NULL) return NULL; 76 77 len = PyList_GET_SIZE(mapTypes); 78 79 for (i = 0; i < len; i++) { 80 PyObject* tp = PyList_GET_ITEM(mapTypes, i); 81 int r = PyObject_IsInstance(object, tp); 82 if (r == -1) { 83 return NULL; 84 } 85 86 if (!r) continue; 87 88 /* Instance of this type should be pythonifyed as a sequence */ 89 return [OC_PythonArray newWithPythonObject:object]; 90 } 91 92 return NULL; 93} 94 95+ depythonifyTable 96{ 97 NSObject* result; 98 99 PyObjC_BEGIN_WITH_GIL 100 101 if (mapTypes == NULL) { 102 mapTypes = PyList_New(0); 103 if (mapTypes == NULL) { 104 PyObjC_GIL_FORWARD_EXC(); 105 } 106 } 107 result = PyObjC_PythonToId(mapTypes); 108 if (result == NULL) { 109 PyObjC_GIL_FORWARD_EXC(); 110 } 111 112 PyObjC_END_WITH_GIL 113 114 return result; 115} 116 117+newWithPythonObject:(PyObject*)v; 118{ 119 OC_PythonDictionary* res = 120 [[OC_PythonDictionary alloc] initWithPythonObject:v]; 121 [res autorelease]; 122 return res; 123} 124 125-initWithPythonObject:(PyObject*)v; 126{ 127 self = [super init]; 128 if (unlikely(self == nil)) return nil; 129 130 Py_INCREF(v); 131 Py_XDECREF(value); 132 value = v; 133 return self; 134} 135 136-(void)release 137{ 138 /* See comment in OC_PythonUnicode */ 139 PyObjC_BEGIN_WITH_GIL 140 [super release]; 141 PyObjC_END_WITH_GIL 142} 143 144 145 146-(void)dealloc 147{ 148 PyObjC_BEGIN_WITH_GIL 149 PyObjC_UnregisterObjCProxy(value, self); 150 Py_XDECREF(value); 151 152 PyObjC_END_WITH_GIL 153 154 [super dealloc]; 155} 156 157-(PyObject*)__pyobjc_PythonObject__ 158{ 159 Py_INCREF(value); 160 return value; 161} 162-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie 163{ 164 *cookie = 0; 165 Py_INCREF(value); 166 return value; 167} 168 169-(NSUInteger)count 170{ 171 Py_ssize_t result; 172 173 PyObjC_BEGIN_WITH_GIL 174 if (likely(PyDict_CheckExact(value))) { 175 result = PyDict_Size(value); 176 } else { 177 result = PyObject_Length(value); 178 } 179 180 PyObjC_END_WITH_GIL 181 182 if (sizeof(Py_ssize_t) > sizeof(NSUInteger)) { 183 if (result > (Py_ssize_t)NSUIntegerMax) { 184 return NSUIntegerMax; 185 } 186 } 187 return result; 188} 189 190-(int)depythonify:(PyObject*)v toId:(id*)datum 191{ 192 if (unlikely(depythonify_c_value(@encode(id), v, datum) == -1)) { 193 return -1; 194 } 195 if (unlikely(*datum == nil)) { 196 *datum = [NSNull null]; 197 } 198 return 0; 199} 200 201-objectForKey:key 202{ 203 PyObject* v; 204 PyObject* k; 205 id result; 206 207 PyObjC_BEGIN_WITH_GIL 208 209 if (unlikely(key == [NSNull null])) { 210 Py_INCREF(Py_None); 211 k = Py_None; 212 } else { 213 k = PyObjC_IdToPython(key); 214 if (k == NULL) { 215 PyObjC_GIL_FORWARD_EXC(); 216 } 217 } 218 219 if (likely(PyDict_CheckExact(value))) { 220 v = PyDict_GetItem(value, k); 221 Py_XINCREF(v); 222 } else { 223 v = PyObject_GetItem(value, k); 224 } 225 Py_DECREF(k); 226 227 if (unlikely(v == NULL)) { 228 PyErr_Clear(); 229 PyObjC_GIL_RETURN(nil); 230 } 231 232 if (unlikely([self depythonify:v toId:&result] == -1)) { 233 Py_DECREF(v); 234 PyObjC_GIL_FORWARD_EXC(); 235 } 236 Py_DECREF(v); 237 238 PyObjC_END_WITH_GIL 239 240 return result; 241} 242 243 244-(void)setObject:val forKey:key 245{ 246 PyObject* v = NULL; 247 PyObject* k = NULL; 248 id null = [NSNull null]; 249 250 PyObjC_BEGIN_WITH_GIL 251 if (unlikely(val == null)) { 252 Py_INCREF(Py_None); 253 v = Py_None; 254 } else { 255 v = PyObjC_IdToPython(val); 256 if (unlikely(v == NULL)) { 257 PyObjC_GIL_FORWARD_EXC(); 258 } 259 } 260 261 if (unlikely(key == nil)) { 262 Py_INCREF(Py_None); 263 k = Py_None; 264 } else { 265 k = PyObjC_IdToPython(key); 266 if (k == NULL) { 267 Py_XDECREF(v); 268 PyObjC_GIL_FORWARD_EXC(); 269 } 270 } 271 272 if (likely(PyDict_CheckExact(value))) { 273 if (unlikely(PyDict_SetItem(value, k, v) < 0)) { 274 Py_XDECREF(v); 275 Py_XDECREF(k); 276 PyObjC_GIL_FORWARD_EXC(); 277 } 278 279 } else { 280 if (unlikely(PyObject_SetItem(value, k, v) < 0)) { 281 Py_XDECREF(v); 282 Py_XDECREF(k); 283 PyObjC_GIL_FORWARD_EXC(); 284 } 285 286 } 287 288 Py_DECREF(v); 289 Py_DECREF(k); 290 291 PyObjC_END_WITH_GIL 292} 293 294-(BOOL)wrappedKey:(id*)keyPtr value:(id*)valuePtr atPosition:(Py_ssize_t*)positionPtr 295{ 296 PyObject *pykey = NULL; 297 PyObject *pyvalue = NULL; 298 PyObject **pykeyptr = (keyPtr == nil) ? NULL : &pykey; 299 PyObject **pyvalueptr = (valuePtr == nil) ? NULL : &pyvalue; 300 301 PyObjC_BEGIN_WITH_GIL 302 if (unlikely(!PyDict_Next(value, positionPtr, pykeyptr, pyvalueptr))) { 303 PyObjC_GIL_RETURN(NO); 304 } 305 if (keyPtr) { 306 if (unlikely([self depythonify:pykey toId:keyPtr] == -1)) { 307 PyObjC_GIL_FORWARD_EXC(); 308 } 309 } 310 if (likely(valuePtr)) { 311 if (unlikely([self depythonify:pyvalue toId:valuePtr] == -1)) { 312 PyObjC_GIL_FORWARD_EXC(); 313 } 314 } 315 PyObjC_END_WITH_GIL 316 return YES; 317} 318 319-(void)removeObjectForKey:key 320{ 321 PyObject* k; 322 323 PyObjC_BEGIN_WITH_GIL 324 if (unlikely(key == [NSNull null])) { 325 Py_INCREF(Py_None); 326 k = Py_None; 327 } else { 328 k = PyObjC_IdToPython(key); 329 if (unlikely(k == NULL)) { 330 PyObjC_GIL_FORWARD_EXC(); 331 } 332 } 333 334 if (PyDict_CheckExact(value)) { 335 if (unlikely(PyDict_DelItem(value, k) < 0)) { 336 Py_DECREF(k); 337 PyObjC_GIL_FORWARD_EXC(); 338 } 339 } else { 340 if (unlikely(PyObject_DelItem(value, k) < 0)) { 341 Py_DECREF(k); 342 PyObjC_GIL_FORWARD_EXC(); 343 } 344 } 345 Py_DECREF(k); 346 347 PyObjC_END_WITH_GIL 348} 349 350-(NSEnumerator *)keyEnumerator 351{ 352 if (PyDict_CheckExact(value)) { 353 return [OC_PythonDictionaryEnumerator newWithWrappedDictionary:self]; 354 } else { 355 PyObjC_BEGIN_WITH_GIL 356 PyObject* keys = PyObject_CallMethod(value, "keys", NULL); 357 if (keys == NULL) { 358 PyObjC_GIL_FORWARD_EXC(); 359 } 360 361 PyObject* iter = PyObject_GetIter(keys); 362 Py_DECREF(keys); 363 if (iter == NULL) { 364 PyObjC_GIL_FORWARD_EXC(); 365 } 366 367 NSEnumerator* result = [OC_PythonEnumerator newWithPythonObject:iter]; 368 PyObjC_GIL_RETURN(result); 369 370 PyObjC_END_WITH_GIL 371 } 372} 373 374 375- initWithObjects:(NSObject**)objects 376 forKeys:(NSObject**)keys 377 count:(NSUInteger)count 378{ 379 /* This implementation is needed for our support for the NSCoding 380 * protocol, NSDictionary's initWithCoder: will call this method. 381 */ 382 NSUInteger i; 383 384 PyObjC_BEGIN_WITH_GIL 385 for (i = 0; i < count; i++) { 386 PyObject* k; 387 PyObject* v; 388 int r; 389 390 if (objects[i] == [NSNull null]) { 391 v = Py_None; 392 Py_INCREF(Py_None); 393 } else { 394 v = PyObjC_IdToPython(objects[i]); 395 if (v == NULL) { 396 PyObjC_GIL_FORWARD_EXC(); 397 } 398 } 399 400 if (keys[i] == [NSNull null]) { 401 k = Py_None; 402 Py_INCREF(Py_None); 403 } else { 404 k = PyObjC_IdToPython(keys[i]); 405 if (k == NULL) { 406 PyObjC_GIL_FORWARD_EXC(); 407 } 408 } 409 410 r = PyDict_SetItem(value, k, v); 411 Py_DECREF(k); Py_DECREF(v); 412 413 if (r == -1) { 414 PyObjC_GIL_FORWARD_EXC(); 415 } 416 } 417 PyObjC_END_WITH_GIL 418 return self; 419} 420 421/* 422 * Helper method for initWithCoder, needed to deal with 423 * recursive objects (e.g. o.value = o) 424 */ 425-(void)pyobjcSetValue:(NSObject*)other 426{ 427 PyObject* v = PyObjC_IdToPython(other); 428 Py_XDECREF(value); 429 value = v; 430} 431 432- initWithCoder:(NSCoder*)coder 433{ 434 int code; 435 if ([coder allowsKeyedCoding]) { 436 code = [coder decodeInt32ForKey:@"pytype"]; 437 } else { 438 [coder decodeValueOfObjCType:@encode(int) at:&code]; 439 } 440 switch (code) { 441 case 1: 442 PyObjC_BEGIN_WITH_GIL 443 value = PyDict_New(); 444 if (value == NULL) { 445 PyObjC_GIL_FORWARD_EXC(); 446 } 447 PyObjC_END_WITH_GIL 448 449 self = [super initWithCoder:coder]; 450 return self; 451 452 case 2: 453 if (PyObjC_Decoder != NULL) { 454 PyObjC_BEGIN_WITH_GIL 455 PyObject* cdr = PyObjC_IdToPython(coder); 456 if (cdr == NULL) { 457 PyObjC_GIL_FORWARD_EXC(); 458 } 459 460 PyObject* setValue; 461 PyObject* selfAsPython = PyObjCObject_New(self, 0, YES); 462 setValue = PyObject_GetAttrString(selfAsPython, "pyobjcSetValue_"); 463 464 PyObject* v = PyObject_CallFunction(PyObjC_Decoder, "OO", cdr, setValue); 465 Py_DECREF(cdr); 466 Py_DECREF(setValue); 467 Py_DECREF(selfAsPython); 468 469 if (v == NULL) { 470 PyObjC_GIL_FORWARD_EXC(); 471 } 472 473 Py_XDECREF(value); 474 value = v; 475 476 NSObject* proxy = PyObjC_FindObjCProxy(value); 477 if (proxy == NULL) { 478 PyObjC_RegisterObjCProxy(value, self); 479 } else { 480 [self release]; 481 [proxy retain]; 482 self = (OC_PythonDictionary*)proxy; 483 } 484 485 486 PyObjC_END_WITH_GIL 487 488 return self; 489 490 } else { 491 [NSException raise:NSInvalidArgumentException 492 format:@"decoding Python objects is not supported"]; 493 return nil; 494 495 } 496 } 497 [NSException raise:NSInvalidArgumentException 498 format:@"decoding Python objects is not supported"]; 499 [self release]; 500 return nil; 501} 502 503-(Class)classForCoder 504{ 505 return [OC_PythonDictionary class]; 506} 507 508 509- (void)encodeWithCoder:(NSCoder*)coder 510{ 511 if (1 && PyDict_CheckExact(value)) { 512 if ([coder allowsKeyedCoding]) { 513 [coder encodeInt32:1 forKey:@"pytype"]; 514 } else { 515 int v = 1; 516 [coder encodeValueOfObjCType:@encode(int) at:&v]; 517 } 518 [super encodeWithCoder:coder]; 519 520 } else { 521 if ([coder allowsKeyedCoding]) { 522 [coder encodeInt32:2 forKey:@"pytype"]; 523 } else { 524 int v = 2; 525 [coder encodeValueOfObjCType:@encode(int) at:&v]; 526 } 527 PyObjC_encodeWithCoder(value, coder); 528 529 } 530} 531 532-(id)copyWithZone:(NSZone*)zone 533{ 534 if (PyObjC_CopyFunc) { 535 PyObjC_BEGIN_WITH_GIL 536 PyObject* copy = PyObject_CallFunctionObjArgs(PyObjC_CopyFunc, 537 value, NULL); 538 if (copy == NULL) { 539 PyObjC_GIL_FORWARD_EXC(); 540 } 541 542 NSObject* result = PyObjC_PythonToId(copy); 543 Py_DECREF(copy); 544 545 if (PyErr_Occurred()) { 546 PyObjC_GIL_FORWARD_EXC(); 547 } 548 549 [result retain]; 550 551 PyObjC_GIL_RETURN(result); 552 553 PyObjC_END_WITH_GIL 554 } else { 555 return [super copyWithZone:zone]; 556 } 557} 558 559-(id)mutableCopyWithZone:(NSZone*)zone 560{ 561 if (PyObjC_CopyFunc) { 562 PyObjC_BEGIN_WITH_GIL 563 PyObject* copy = PyDict_New(); 564 if (copy == NULL) { 565 PyObjC_GIL_FORWARD_EXC(); 566 } 567 568 int r = PyDict_Update(copy, value); 569 if (r == -1) { 570 PyObjC_GIL_FORWARD_EXC(); 571 } 572 573 NSObject* result = PyObjC_PythonToId(copy); 574 Py_DECREF(copy); 575 576 if (PyErr_Occurred()) { 577 PyObjC_GIL_FORWARD_EXC(); 578 } 579 580 [result retain]; 581 582 PyObjC_GIL_RETURN(result); 583 584 PyObjC_END_WITH_GIL 585 } else { 586 return [super mutableCopyWithZone:zone]; 587 } 588} 589 590 591@end // interface OC_PythonDictionary 592