-
-
Notifications
You must be signed in to change notification settings - Fork 62
Make ZippyJSONDecoder thread-safe and conform to Sendable #70
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
| objc_sync_enter(self) | ||
| defer { objc_sync_exit(self) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it's safe to use this API from Swift, especially when combined with other primitives which callers of this API may be using. Since I had to make other mutable properties thread-safe, I just used the same @Synchronized primitive for all of them
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
interesting, i'd be curious to see any resources you have indicating it's unsafe, although using a lock does seem simpler
| } | ||
|
|
||
| public final class ZippyJSONDecoder { | ||
| public final class ZippyJSONDecoder: Sendable { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This compiles without having to resort to @unchecked Sendable, so we get a compile-time guarantee of thread-safety :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
very nice!
| case deferredToData | ||
| case base64 | ||
| case custom((Decoder) throws -> Data) | ||
| case custom(@Sendable (Decoder) throws -> Data) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this appears to be a breaking change, but maybe it's worth it
| } | ||
| } | ||
|
|
||
| private final class Lock: LockProtocol { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think we could remove this class and just have a free function that returns a LockProtocol
|
|
||
| @propertyWrapper | ||
| private final class Synchronized<Value>: @unchecked Sendable { | ||
| private let lock: LockProtocol |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so it appears that this design creates like 4 of these per decoder? i believe that should be fast, but i may verify
| public var nonConformingFloatDecodingStrategy: NonConformingFloatDecodingStrategy | ||
| @Synchronized | ||
| private var _nonConformingFloatDecodingStrategy: NonConformingFloatDecodingStrategy | ||
| public var nonConformingFloatDecodingStrategy: NonConformingFloatDecodingStrategy { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why can't public var have @Synchronized on it and we don't need to wrap? is it to avoid exposing @Synchronized?
|
thank you for this pr. i should mention that JSONDecoder is superior to ZippyJSON for iOS 17+, as discussed here: #69 . things may get archived in, say, a year. so if you're doing this change in part for your own code base, i'm curious to know if it supports ios 16 or prior although this pr makes sense with what it's trying to do, i have a high level concern. if someone, say, changes the data decoding strategy of a decoder on thread A while thread B is doing json decoding with it, then although the changeover will be safe, the results are probably undesired. data decoding would behave differently for the first part of the json document than the second. i don't know what the best solution is here, but i'm not sure if people should actually be using it from multiple threads here (it should be noted i haven't done a ton with swift since Sendable came out) |
Hey! Thanks for that :) I was actually just in the process of doing benchmarks in my app. But that is good to hear! May be worth updating the README :)
yeah totally. I wonder what I'm happy to just close this PR though! |
Sure, that's a good idea, I'll update it.
It looks like this: So I guess they use a shared lock. It has that fancy If you want to solve the high level problem and then mark it Sendable, or if you want to merge your current changes minus marking it Sendable, or of course abandon the PR, all are things I'm on board with |
No description provided.