make encoding return an error instead of panic (#82)
* make encoding return an error instead of panic This also adds support for unsafe.Pointer types. * remove success variables and remove excess var
- commit
- 7b60891325c492c051350418d742c735ec484fe9
- author
- TotallyGamerJet · · 2022-12-16 18:54 UTC
- committer
- GitHub · · 2022-12-16 18:54 UTC
- parent
- 39261b6
- signature
- GPG Unverified
4AEE18F83AFDEB23The key is unknown
1 file · +62 -39
M objc/objc_runtime_darwin.go +62 -39
| @@ -245,8 +245,7 @@ func RegisterClass(object Selector) (Class, error) { | |||
| 245 | 245 | if len(split) > 2 { | |
| 246 | 246 | // Add Protocols | |
| 247 | 247 | for _, n := range split[2:] { | |
| 248 | - | succeed := class.AddProtocol(GetProtocol(n)) | |
| 249 | - | if !succeed { | |
| 248 | + | if !class.AddProtocol(GetProtocol(n)) { | |
| 250 | 249 | return 0, fmt.Errorf("objc: couldn't add Protocol %s", n) | |
| 251 | 250 | } | |
| 252 | 251 | } | |
| @@ -275,8 +274,11 @@ func RegisterClass(object Selector) (Class, error) { | |||
| 275 | 274 | if err != nil { | |
| 276 | 275 | return 0, fmt.Errorf("objc: couldn't add Method %s: %w", met.Name, err) | |
| 277 | 276 | } | |
| 278 | - | succeed := class.AddMethod(sel, imp, encodeFunc(fn)) | |
| 279 | - | if !succeed { | |
| 277 | + | encoding, err := encodeFunc(fn) | |
| 278 | + | if err != nil { | |
| 279 | + | return 0, fmt.Errorf("objc: couldn't add Method %s: %w", met.Name, err) | |
| 280 | + | } | |
| 281 | + | if !class.AddMethod(sel, imp, encoding) { | |
| 280 | 282 | return 0, fmt.Errorf("objc: couldn't add Method %s", met.Name) | |
| 281 | 283 | } | |
| 282 | 284 | } | |
| @@ -286,8 +288,11 @@ func RegisterClass(object Selector) (Class, error) { | |||
| 286 | 288 | f := strct.Field(i) | |
| 287 | 289 | size := f.Type.Size() | |
| 288 | 290 | alignment := uint8(math.Log2(float64(f.Type.Align()))) | |
| 289 | - | succeed := class_addIvar(class, f.Name, size, alignment, encodeType(f.Type)) | |
| 290 | - | if !succeed { | |
| 291 | + | enc, err := encodeType(f.Type, false) | |
| 292 | + | if err != nil { | |
| 293 | + | return 0, fmt.Errorf("objc: couldn't add Ivar %s: %w", f.Name, err) | |
| 294 | + | } | |
| 295 | + | if !class_addIvar(class, f.Name, size, alignment, enc) { | |
| 291 | 296 | return 0, fmt.Errorf("objc: couldn't add Ivar %s", f.Name) | |
| 292 | 297 | } | |
| 293 | 298 | if offset := class.InstanceVariable(f.Name).Offset(); offset != f.Offset { | |
| @@ -321,74 +326,85 @@ const ( | |||
| 321 | 326 | encCharPtr = "*" | |
| 322 | 327 | encStructBegin = "{" | |
| 323 | 328 | encStructEnd = "}" | |
| 329 | + | encUnsafePtr = "^v" | |
| 324 | 330 | ) | |
| 325 | 331 | ||
| 326 | 332 | // encodeType returns a string representing a type as if it was given to @encode(typ) | |
| 327 | 333 | // Source: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100 | |
| 328 | - | func encodeType(typ reflect.Type) string { | |
| 334 | + | func encodeType(typ reflect.Type, insidePtr bool) (string, error) { | |
| 329 | 335 | switch typ { | |
| 330 | 336 | case reflect.TypeOf(Class(0)): | |
| 331 | - | return encClass | |
| 337 | + | return encClass, nil | |
| 332 | 338 | case reflect.TypeOf(ID(0)): | |
| 333 | - | return encId | |
| 339 | + | return encId, nil | |
| 334 | 340 | case reflect.TypeOf(SEL(0)): | |
| 335 | - | return encSelector | |
| 341 | + | return encSelector, nil | |
| 336 | 342 | } | |
| 337 | 343 | ||
| 338 | 344 | kind := typ.Kind() | |
| 339 | 345 | switch kind { | |
| 340 | 346 | case reflect.Bool: | |
| 341 | - | return encBool | |
| 347 | + | return encBool, nil | |
| 342 | 348 | case reflect.Int: | |
| 343 | - | return encLong | |
| 349 | + | return encLong, nil | |
| 344 | 350 | case reflect.Int8: | |
| 345 | - | return encChar | |
| 351 | + | return encChar, nil | |
| 346 | 352 | case reflect.Int16: | |
| 347 | - | return encShort | |
| 353 | + | return encShort, nil | |
| 348 | 354 | case reflect.Int32: | |
| 349 | - | return encInt | |
| 355 | + | return encInt, nil | |
| 350 | 356 | case reflect.Int64: | |
| 351 | - | return encULong | |
| 357 | + | return encULong, nil | |
| 352 | 358 | case reflect.Uint: | |
| 353 | - | return encULong | |
| 359 | + | return encULong, nil | |
| 354 | 360 | case reflect.Uint8: | |
| 355 | - | return encUChar | |
| 361 | + | return encUChar, nil | |
| 356 | 362 | case reflect.Uint16: | |
| 357 | - | return encUShort | |
| 363 | + | return encUShort, nil | |
| 358 | 364 | case reflect.Uint32: | |
| 359 | - | return encUInt | |
| 365 | + | return encUInt, nil | |
| 360 | 366 | case reflect.Uint64: | |
| 361 | - | return encULong | |
| 367 | + | return encULong, nil | |
| 362 | 368 | case reflect.Uintptr: | |
| 363 | - | return encPtr | |
| 369 | + | return encPtr, nil | |
| 364 | 370 | case reflect.Float32: | |
| 365 | - | return encFloat | |
| 371 | + | return encFloat, nil | |
| 366 | 372 | case reflect.Float64: | |
| 367 | - | return encDouble | |
| 373 | + | return encDouble, nil | |
| 368 | 374 | case reflect.Ptr: | |
| 369 | - | return encPtr + encodeType(typ.Elem()) | |
| 375 | + | enc, err := encodeType(typ.Elem(), true) | |
| 376 | + | return encPtr + enc, err | |
| 370 | 377 | case reflect.Struct: | |
| 378 | + | if insidePtr { | |
| 379 | + | return encStructBegin + typ.Name() + encStructEnd, nil | |
| 380 | + | } | |
| 371 | 381 | var encoding = encStructBegin | |
| 372 | 382 | encoding += typ.Name() | |
| 373 | 383 | encoding += "=" | |
| 374 | 384 | for i := 0; i < typ.NumField(); i++ { | |
| 375 | 385 | f := typ.Field(i) | |
| 376 | - | encoding += encodeType(f.Type) | |
| 386 | + | tmp, err := encodeType(f.Type, false) | |
| 387 | + | if err != nil { | |
| 388 | + | return "", err | |
| 389 | + | } | |
| 390 | + | encoding += tmp | |
| 377 | 391 | } | |
| 378 | 392 | encoding = encStructEnd | |
| 379 | - | return encoding | |
| 393 | + | return encoding, nil | |
| 394 | + | case reflect.UnsafePointer: | |
| 395 | + | return encUnsafePtr, nil | |
| 380 | 396 | case reflect.String: | |
| 381 | - | return encCharPtr | |
| 397 | + | return encCharPtr, nil | |
| 382 | 398 | } | |
| 383 | 399 | ||
| 384 | - | panic(fmt.Sprintf("objc: unhandled/invalid kind %v typed %v", kind, typ)) | |
| 400 | + | return "", errors.New(fmt.Sprintf("unhandled/invalid kind %v typed %v", kind, typ)) | |
| 385 | 401 | } | |
| 386 | 402 | ||
| 387 | 403 | // encodeFunc returns a functions type as if it was given to @encode(fn) | |
| 388 | - | func encodeFunc(fn interface{}) string { | |
| 404 | + | func encodeFunc(fn interface{}) (string, error) { | |
| 389 | 405 | typ := reflect.TypeOf(fn) | |
| 390 | 406 | if typ.Kind() != reflect.Func { | |
| 391 | - | panic("objc: not a func") | |
| 407 | + | return "", errors.New("not a func") | |
| 392 | 408 | } | |
| 393 | 409 | ||
| 394 | 410 | encoding := "" | |
| @@ -396,22 +412,29 @@ func encodeFunc(fn interface{}) string { | |||
| 396 | 412 | case 0: | |
| 397 | 413 | encoding += encVoid | |
| 398 | 414 | case 1: | |
| 399 | - | encoding += encodeType(typ.Out(0)) | |
| 415 | + | tmp, err := encodeType(typ.Out(0), false) | |
| 416 | + | if err != nil { | |
| 417 | + | return "", err | |
| 418 | + | } | |
| 419 | + | encoding += tmp | |
| 400 | 420 | default: | |
| 401 | - | panic("objc: too many output parameters") | |
| 421 | + | return "", errors.New("too many output parameters") | |
| 402 | 422 | } | |
| 403 | 423 | ||
| 404 | - | if typ.NumIn() == 0 { | |
| 405 | - | panic("objc: func doesn't take ID and SEL as its first two parameters") | |
| 424 | + | if typ.NumIn() < 2 { | |
| 425 | + | return "", errors.New("func doesn't take ID and SEL as its first two parameters") | |
| 406 | 426 | } | |
| 407 | 427 | ||
| 408 | - | encoding += encodeType(typ.In(0)) | |
| 409 | - | encoding += encSelector | |
| 428 | + | encoding += encId | |
| 410 | 429 | ||
| 411 | 430 | for i := 1; i < typ.NumIn(); i++ { | |
| 412 | - | encoding += encodeType(typ.In(i)) | |
| 431 | + | tmp, err := encodeType(typ.In(i), false) | |
| 432 | + | if err != nil { | |
| 433 | + | return "", err | |
| 434 | + | } | |
| 435 | + | encoding += tmp | |
| 413 | 436 | } | |
| 414 | - | return encoding | |
| 437 | + | return encoding, nil | |
| 415 | 438 | } | |
| 416 | 439 | ||
| 417 | 440 | // SuperClass returns the superclass of a class. | |
| @@ -245,8 +245,7 @@ func RegisterClass(object Selector) (Class, error) { | |||||
| 245 | if len(split) > 2 { | 245 | if len(split) > 2 { | ||
| 246 | // Add Protocols | 246 | // Add Protocols | ||
| 247 | for _, n := range split[2:] { | 247 | for _, n := range split[2:] { | ||
| 248 | - | succeed := class.AddProtocol(GetProtocol(n)) | 248 | + | if !class.AddProtocol(GetProtocol(n)) { |
| 249 | - | if !succeed { | |||
| 250 | return 0, fmt.Errorf("objc: couldn't add Protocol %s", n) | 249 | return 0, fmt.Errorf("objc: couldn't add Protocol %s", n) | ||
| 251 | } | 250 | } | ||
| 252 | } | 251 | } | ||
| @@ -275,8 +274,11 @@ func RegisterClass(object Selector) (Class, error) { | |||||
| 275 | if err != nil { | 274 | if err != nil { | ||
| 276 | return 0, fmt.Errorf("objc: couldn't add Method %s: %w", met.Name, err) | 275 | return 0, fmt.Errorf("objc: couldn't add Method %s: %w", met.Name, err) | ||
| 277 | } | 276 | } | ||
| 278 | - | succeed := class.AddMethod(sel, imp, encodeFunc(fn)) | 277 | + | encoding, err := encodeFunc(fn) |
| 279 | - | if !succeed { | 278 | + | if err != nil { |
| 279 | + | return 0, fmt.Errorf("objc: couldn't add Method %s: %w", met.Name, err) | |||
| 280 | + | } | |||
| 281 | + | if !class.AddMethod(sel, imp, encoding) { | |||
| 280 | return 0, fmt.Errorf("objc: couldn't add Method %s", met.Name) | 282 | return 0, fmt.Errorf("objc: couldn't add Method %s", met.Name) | ||
| 281 | } | 283 | } | ||
| 282 | } | 284 | } | ||
| @@ -286,8 +288,11 @@ func RegisterClass(object Selector) (Class, error) { | |||||
| 286 | f := strct.Field(i) | 288 | f := strct.Field(i) | ||
| 287 | size := f.Type.Size() | 289 | size := f.Type.Size() | ||
| 288 | alignment := uint8(math.Log2(float64(f.Type.Align()))) | 290 | alignment := uint8(math.Log2(float64(f.Type.Align()))) | ||
| 289 | - | succeed := class_addIvar(class, f.Name, size, alignment, encodeType(f.Type)) | 291 | + | enc, err := encodeType(f.Type, false) |
| 290 | - | if !succeed { | 292 | + | if err != nil { |
| 293 | + | return 0, fmt.Errorf("objc: couldn't add Ivar %s: %w", f.Name, err) | |||
| 294 | + | } | |||
| 295 | + | if !class_addIvar(class, f.Name, size, alignment, enc) { | |||
| 291 | return 0, fmt.Errorf("objc: couldn't add Ivar %s", f.Name) | 296 | return 0, fmt.Errorf("objc: couldn't add Ivar %s", f.Name) | ||
| 292 | } | 297 | } | ||
| 293 | if offset := class.InstanceVariable(f.Name).Offset(); offset != f.Offset { | 298 | if offset := class.InstanceVariable(f.Name).Offset(); offset != f.Offset { | ||
| @@ -321,74 +326,85 @@ const ( | |||||
| 321 | encCharPtr = "*" | 326 | encCharPtr = "*" | ||
| 322 | encStructBegin = "{" | 327 | encStructBegin = "{" | ||
| 323 | encStructEnd = "}" | 328 | encStructEnd = "}" | ||
| 329 | + | encUnsafePtr = "^v" | |||
| 324 | ) | 330 | ) | ||
| 325 | 331 | ||||
| 326 | // encodeType returns a string representing a type as if it was given to @encode(typ) | 332 | // encodeType returns a string representing a type as if it was given to @encode(typ) | ||
| 327 | // Source: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100 | 333 | // Source: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100 | ||
| 328 | - | func encodeType(typ reflect.Type) string { | 334 | + | func encodeType(typ reflect.Type, insidePtr bool) (string, error) { |
| 329 | switch typ { | 335 | switch typ { | ||
| 330 | case reflect.TypeOf(Class(0)): | 336 | case reflect.TypeOf(Class(0)): | ||
| 331 | - | return encClass | 337 | + | return encClass, nil |
| 332 | case reflect.TypeOf(ID(0)): | 338 | case reflect.TypeOf(ID(0)): | ||
| 333 | - | return encId | 339 | + | return encId, nil |
| 334 | case reflect.TypeOf(SEL(0)): | 340 | case reflect.TypeOf(SEL(0)): | ||
| 335 | - | return encSelector | 341 | + | return encSelector, nil |
| 336 | } | 342 | } | ||
| 337 | 343 | ||||
| 338 | kind := typ.Kind() | 344 | kind := typ.Kind() | ||
| 339 | switch kind { | 345 | switch kind { | ||
| 340 | case reflect.Bool: | 346 | case reflect.Bool: | ||
| 341 | - | return encBool | 347 | + | return encBool, nil |
| 342 | case reflect.Int: | 348 | case reflect.Int: | ||
| 343 | - | return encLong | 349 | + | return encLong, nil |
| 344 | case reflect.Int8: | 350 | case reflect.Int8: | ||
| 345 | - | return encChar | 351 | + | return encChar, nil |
| 346 | case reflect.Int16: | 352 | case reflect.Int16: | ||
| 347 | - | return encShort | 353 | + | return encShort, nil |
| 348 | case reflect.Int32: | 354 | case reflect.Int32: | ||
| 349 | - | return encInt | 355 | + | return encInt, nil |
| 350 | case reflect.Int64: | 356 | case reflect.Int64: | ||
| 351 | - | return encULong | 357 | + | return encULong, nil |
| 352 | case reflect.Uint: | 358 | case reflect.Uint: | ||
| 353 | - | return encULong | 359 | + | return encULong, nil |
| 354 | case reflect.Uint8: | 360 | case reflect.Uint8: | ||
| 355 | - | return encUChar | 361 | + | return encUChar, nil |
| 356 | case reflect.Uint16: | 362 | case reflect.Uint16: | ||
| 357 | - | return encUShort | 363 | + | return encUShort, nil |
| 358 | case reflect.Uint32: | 364 | case reflect.Uint32: | ||
| 359 | - | return encUInt | 365 | + | return encUInt, nil |
| 360 | case reflect.Uint64: | 366 | case reflect.Uint64: | ||
| 361 | - | return encULong | 367 | + | return encULong, nil |
| 362 | case reflect.Uintptr: | 368 | case reflect.Uintptr: | ||
| 363 | - | return encPtr | 369 | + | return encPtr, nil |
| 364 | case reflect.Float32: | 370 | case reflect.Float32: | ||
| 365 | - | return encFloat | 371 | + | return encFloat, nil |
| 366 | case reflect.Float64: | 372 | case reflect.Float64: | ||
| 367 | - | return encDouble | 373 | + | return encDouble, nil |
| 368 | case reflect.Ptr: | 374 | case reflect.Ptr: | ||
| 369 | - | return encPtr + encodeType(typ.Elem()) | 375 | + | enc, err := encodeType(typ.Elem(), true) |
| 376 | + | return encPtr + enc, err | |||
| 370 | case reflect.Struct: | 377 | case reflect.Struct: | ||
| 378 | + | if insidePtr { | |||
| 379 | + | return encStructBegin + typ.Name() + encStructEnd, nil | |||
| 380 | + | } | |||
| 371 | var encoding = encStructBegin | 381 | var encoding = encStructBegin | ||
| 372 | encoding += typ.Name() | 382 | encoding += typ.Name() | ||
| 373 | encoding += "=" | 383 | encoding += "=" | ||
| 374 | for i := 0; i < typ.NumField(); i++ { | 384 | for i := 0; i < typ.NumField(); i++ { | ||
| 375 | f := typ.Field(i) | 385 | f := typ.Field(i) | ||
| 376 | - | encoding += encodeType(f.Type) | 386 | + | tmp, err := encodeType(f.Type, false) |
| 387 | + | if err != nil { | |||
| 388 | + | return "", err | |||
| 389 | + | } | |||
| 390 | + | encoding += tmp | |||
| 377 | } | 391 | } | ||
| 378 | encoding = encStructEnd | 392 | encoding = encStructEnd | ||
| 379 | - | return encoding | 393 | + | return encoding, nil |
| 394 | + | case reflect.UnsafePointer: | |||
| 395 | + | return encUnsafePtr, nil | |||
| 380 | case reflect.String: | 396 | case reflect.String: | ||
| 381 | - | return encCharPtr | 397 | + | return encCharPtr, nil |
| 382 | } | 398 | } | ||
| 383 | 399 | ||||
| 384 | - | panic(fmt.Sprintf("objc: unhandled/invalid kind %v typed %v", kind, typ)) | 400 | + | return "", errors.New(fmt.Sprintf("unhandled/invalid kind %v typed %v", kind, typ)) |
| 385 | } | 401 | } | ||
| 386 | 402 | ||||
| 387 | // encodeFunc returns a functions type as if it was given to @encode(fn) | 403 | // encodeFunc returns a functions type as if it was given to @encode(fn) | ||
| 388 | - | func encodeFunc(fn interface{}) string { | 404 | + | func encodeFunc(fn interface{}) (string, error) { |
| 389 | typ := reflect.TypeOf(fn) | 405 | typ := reflect.TypeOf(fn) | ||
| 390 | if typ.Kind() != reflect.Func { | 406 | if typ.Kind() != reflect.Func { | ||
| 391 | - | panic("objc: not a func") | 407 | + | return "", errors.New("not a func") |
| 392 | } | 408 | } | ||
| 393 | 409 | ||||
| 394 | encoding := "" | 410 | encoding := "" | ||
| @@ -396,22 +412,29 @@ func encodeFunc(fn interface{}) string { | |||||
| 396 | case 0: | 412 | case 0: | ||
| 397 | encoding += encVoid | 413 | encoding += encVoid | ||
| 398 | case 1: | 414 | case 1: | ||
| 399 | - | encoding += encodeType(typ.Out(0)) | 415 | + | tmp, err := encodeType(typ.Out(0), false) |
| 416 | + | if err != nil { | |||
| 417 | + | return "", err | |||
| 418 | + | } | |||
| 419 | + | encoding += tmp | |||
| 400 | default: | 420 | default: | ||
| 401 | - | panic("objc: too many output parameters") | 421 | + | return "", errors.New("too many output parameters") |
| 402 | } | 422 | } | ||
| 403 | 423 | ||||
| 404 | - | if typ.NumIn() == 0 { | 424 | + | if typ.NumIn() < 2 { |
| 405 | - | panic("objc: func doesn't take ID and SEL as its first two parameters") | 425 | + | return "", errors.New("func doesn't take ID and SEL as its first two parameters") |
| 406 | } | 426 | } | ||
| 407 | 427 | ||||
| 408 | - | encoding += encodeType(typ.In(0)) | 428 | + | encoding += encId |
| 409 | - | encoding += encSelector | |||
| 410 | 429 | ||||
| 411 | for i := 1; i < typ.NumIn(); i++ { | 430 | for i := 1; i < typ.NumIn(); i++ { | ||
| 412 | - | encoding += encodeType(typ.In(i)) | 431 | + | tmp, err := encodeType(typ.In(i), false) |
| 432 | + | if err != nil { | |||
| 433 | + | return "", err | |||
| 434 | + | } | |||
| 435 | + | encoding += tmp | |||
| 413 | } | 436 | } | ||
| 414 | - | return encoding | 437 | + | return encoding, nil |
| 415 | } | 438 | } | ||
| 416 | 439 | ||||
| 417 | // SuperClass returns the superclass of a class. | 440 | // SuperClass returns the superclass of a class. | ||