Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign upConverting between dictionary types #265
Conversation
| impl CFPropertyListSubClass for ::dictionary::CFDictionary {} | ||
| impl<T> CFPropertyListSubClass for ::array::CFArray<T> {} | ||
| impl<K, V> CFPropertyListSubClass for ::dictionary::CFDictionary<K, V> {} | ||
| impl<K, V> CFPropertyListSubClass for ::dictionary::CFMutableDictionary<K, V> {} |
This comment has been minimized.
This comment has been minimized.
faern
Oct 22, 2018
Author
Contributor
I'm not completely sure this is correct or safe, but I think it is. The docs say that a mutable dictionary can be viewed as an immutable one, from my understanding. But not the other way around. So looking at a mutable dictionary as a propertylist should just be an extension of viewing it as an immutable dictionary then?
|
|
||
| /// Borrow self as an immutable dictionary. | ||
| #[inline] | ||
| pub fn as_immutable(&self) -> ItemRef<CFDictionary<K, V>> { |
This comment has been minimized.
This comment has been minimized.
faern
Oct 22, 2018
Author
Contributor
As I wrote in the initial description above, trying to limit this usage so the mutable dictionary acts as borrowed (thus immutable) while the returned value exists might be overkill/false claims. Since it's so easy to go around it anyway. Anyone can just clone their mutable dictionary and make one of them immutable and still have a mutable version.
With the added addition of
impl<K, V> CFPropertyListSubClass for ::dictionary::CFMutableDictionary<K, V> {} below (Which we have not yet debated if it's correct or not), they could also just do
let mut_dict = CFMutableDictionary::new();
let dict = mut_dict.to_CFPropertyList().downcast::<CFDictionary>().unwrap();and that way also have an owned immutable dictionary be live at the same time as a mutable version pointing to the same underlying dictionary.
| /// Returns a `CFDictionary` pointing to the same underlying dictionary as this mutable one. | ||
| #[inline] | ||
| pub fn to_immutable(&self) -> CFDictionary<K, V> { | ||
| unsafe { CFDictionary::wrap_under_get_rule(self.0) } |
This comment has been minimized.
This comment has been minimized.
faern
Oct 22, 2018
Author
Contributor
Since it was so easy to work around the borrowing here anyway I decided to revert that in the last commit. If we allow cloning of CFMutableDictionary I don't see why we would not allow this.
| impl CFPropertyListSubClass for ::array::CFArray {} | ||
| impl CFPropertyListSubClass for ::dictionary::CFDictionary {} | ||
| impl<T> CFPropertyListSubClass for ::array::CFArray<T> {} | ||
| impl<K, V> CFPropertyListSubClass for ::dictionary::CFDictionary<K, V> {} |
This comment has been minimized.
This comment has been minimized.
faern
Oct 23, 2018
Author
Contributor
I reverted the commit where I implemented CFPropertyListSubClass for CFMutableDictionary. I also removed the ConcreteCFType implementation for CFMutableDictionary. I realized these traits are not only for casting up to the more generic parent type, they are also for downcasting from them to the given subclass. Since mutable dictionaries have the same type ID as their immutable counterparts, it became possible to cast any CFType or CFPropertyList that was of CFDictionary type down to a CFMutableDictionary and then modify it, thus causing a segfault without any unsafe code.
This comment has been minimized.
This comment has been minimized.
faern
Oct 23, 2018
Author
Contributor
How stupid of me.. This of course applies to for example impl<T> CFPropertyListSubClass for ::array::CFArray<T> {} as well. That would allow downcasting to a typed array directly, which would not be safe. I removed the generics on these CFPropertyListSubClass implementations again..
|
I agree with your reasoning on all points. I don't think it makes sense to try to enforce Rust's views of immutable/mutable when binding to APIs that can work around it easily. |
|
@bors-servo r+ |
|
|
Converting between dictionary types I'm trying to use the `CFDictionary` and `CFMutableDictionary` types more extensively. But run into problems. They are not very compatible with each other. This crate for example does not expose any clean way of using `CFDictionaryCreateMutableCopy` to create a `CFMutableDictionary` from any `CFDictionary`. I added a `From` implementation for this. It was not possible to, in some safe/simple way, cast a `CFDictionary<K, V>` into the untyped `CFDictionary<*const c_void, *const c_void>` something I added `to_untyped` to be able to do. When it comes to downcasting, it was not possible to downcast a `CFType` into a dictionary, since they don't implement `ConcreteCFType`. Something they probably should, for the case where the keys and values are just void pointers. `CFArray` does exactly this. Lastly, what I needed the most was to be able to convert a `CFMutableDictionary` into a `CFDictionary`. This allows me to borrow an immutable `CFDictionary` via the `ItemRef` type basically. It's possible to work around this and actually have owned instances of a `CFDictionary` and a `CFMutableDictionary` pointing to the same actual dictionary by doing this: ```rust let mut_dict = CFMutableDictionary::new(); let mut_dict2 = mut_dict.clone(); let dict = mut_dict.as_immutable(); // Here one can mutate the dict via `mut_dict2` while `dict` is still in scope/alive. ``` But since we already allow cloning a `CFMutableDictionary` to have two mutable references to the same dictionary I guess someone decided this should be viewed as safe. Both `CFDictionary` and `CFMutableDictionary` does not implement `Send` so we should not end up in any actual thread inconsistencies here. If the above is indeed considered safe, I could get rid of the `ItemRef` juggling and just make it `fn as_immutable(&self) -> CFDictionary` directly maybe? Would simplify usage. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/core-foundation-rs/265) <!-- Reviewable:end -->
|
|
faern commentedOct 22, 2018
•
edited
I'm trying to use the
CFDictionaryandCFMutableDictionarytypes more extensively. But run into problems. They are not very compatible with each other. This crate for example does not expose any clean way of usingCFDictionaryCreateMutableCopyto create aCFMutableDictionaryfrom anyCFDictionary. I added aFromimplementation for this.It was not possible to, in some safe/simple way, cast a
CFDictionary<K, V>into the untypedCFDictionary<*const c_void, *const c_void>something I addedto_untypedto be able to do.When it comes to downcasting, it was not possible to downcast a
CFTypeinto a dictionary, since they don't implementConcreteCFType. Something they probably should, for the case where the keys and values are just void pointers.CFArraydoes exactly this.Lastly, what I needed the most was to be able to convert a
CFMutableDictionaryinto aCFDictionary. This allows me to borrow an immutableCFDictionaryvia theItemReftype basically. It's possible to work around this and actually have owned instances of aCFDictionaryand aCFMutableDictionarypointing to the same actual dictionary by doing this:But since we already allow cloning a
CFMutableDictionaryto have two mutable references to the same dictionary I guess someone decided this should be viewed as safe. BothCFDictionaryandCFMutableDictionarydoes not implementSendso we should not end up in any actual thread inconsistencies here.If the above is indeed considered safe, I could get rid of the
ItemRefjuggling and just make itfn as_immutable(&self) -> CFDictionarydirectly maybe? Would simplify usage.This change is