-
Notifications
You must be signed in to change notification settings - Fork 22
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
Add kml:Link, kml:Icon #28
Conversation
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.
Thanks so much for the PR and thorough write up! I think this approach makes sense, but I'm a bit worried about needing a setter for kml:Model
. Other than the duplicate code do you see any issues creating separate structs?
Otherwise it would be great to convert the fields with empty string to Option<String>
since that's what we're using for other elements, and thanks for flagging that.
src/writer.rs
Outdated
LinkType::Link(model) => (b"Link", &*model), | ||
}; | ||
self.writer | ||
.write_event(Event::Start(BytesStart::owned_name(tag_name.to_vec())))?; |
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.
We'll need to add this here to capture the attributes
.with_attributes(self.hash_map_as_attrs(&link_model.attrs))
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.
Done.
As much as I like the idea of using an enum, it doesn't make sense from an API ergonomics perspective. If Rust supported enum variants as first-class types, then I think it'd be a clean approach. I'll break the enum into separate structs. |
Instead of using enum variants to represent `kml:Link` and `kml:Icon`, which makes it awkward to use them since enum variants are not first-class types in Rust, they are implemented using two separate structs. Since the library already exports the public type `Kml::Icon` from the `crate::types::style` module, `Kml:LinkTypeLink` and `Kml:LinkTypeIcon` are exported. These are aliases for the internal types `kml::types::link::{Link,Icon}`.
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.
Separate structs feels more Rusty. I left a couple of comments to call out some of the decisions I made that are worth a review.
refresh_mode: Some(types::RefreshMode::OnChange), | ||
view_refresh_mode: Some(types::ViewRefreshMode::OnStop), | ||
view_format: Some(String::new()), | ||
attrs, |
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.
Do we want to store the attributes? I see some other types do, but most ignore them. The spec only allows three here: id
, targetId
, and a user-defined one. Maybe I should ignore them to conform to how it is done for other types?
As an aside, I could see how many attributes could be an issue with memory. Perhaps that's a separate issue to be solved in another PR.
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 enough of the other types include attrs
to keep it for now, but worth flagging for the future
href: Some("/path/to/local/resource".to_string()), | ||
refresh_mode: Some(types::RefreshMode::OnChange), | ||
view_refresh_mode: Some(types::ViewRefreshMode::OnStop), | ||
view_format: Some(String::new()), |
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.
In this test, viewFormat
is an empty element, and this is treated as a value. Any desire to identify this and assign the optional String value to None
?
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 the test and behavior work as-is, since I would assume None
would mean the tag isn't present at all
src/types/mod.rs
Outdated
@@ -36,6 +36,10 @@ mod geometry; | |||
|
|||
pub use geometry::Geometry; | |||
|
|||
mod link; | |||
|
|||
pub use link::{Icon as LinkTypeIcon, Link as LinkTypeLink, RefreshMode, ViewRefreshMode}; |
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.
Not a fan of these aliases, but I couldn't think of anything better. Decided to alias Link
only because Icon
was aliased. WDYT?
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 I'd prefer we only alias Icon
to LinkTypeIcon
and remove the LinkTypeLink
to keep things as consistent with the spec as possible
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 is looking great, thanks for the changes! The last two things to update would be implementing FromStr
for the enums and removing the Link
alias, then I think this is ready to merge
href: Some("/path/to/local/resource".to_string()), | ||
refresh_mode: Some(types::RefreshMode::OnChange), | ||
view_refresh_mode: Some(types::ViewRefreshMode::OnStop), | ||
view_format: Some(String::new()), |
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 the test and behavior work as-is, since I would assume None
would mean the tag isn't present at all
src/types/mod.rs
Outdated
@@ -36,6 +36,10 @@ mod geometry; | |||
|
|||
pub use geometry::Geometry; | |||
|
|||
mod link; | |||
|
|||
pub use link::{Icon as LinkTypeIcon, Link as LinkTypeLink, RefreshMode, ViewRefreshMode}; |
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 I'd prefer we only alias Icon
to LinkTypeIcon
and remove the LinkTypeLink
to keep things as consistent with the spec as possible
src/reader.rs
Outdated
icon.refresh_mode = match self.read_str()?.as_str() { | ||
"onChange" => Some(RefreshMode::OnChange), | ||
"onInterval" => Some(RefreshMode::OnInterval), | ||
"onExpire" => Some(RefreshMode::OnExpire), | ||
_ => None, | ||
} | ||
} |
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.
Instead of including this here, could we implement FromStr
for RefreshMode
as well as the other added enums? We've done this for AltitudeMode
and ColorMode
as well and it keeps things a little cleaner
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.
Done.
|
||
/// `kml:viewRefreshModeEnumType`, [16.27](https://docs.opengeospatial.org/is/12-007r2/12-007r2.html#1270) in the KML specification. | ||
#[derive(Clone, Debug, PartialEq)] | ||
pub enum ViewRefreshMode { |
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.
It would be great to implement FromStr
here as well
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.
Done.
024e424
to
5f70a96
Compare
Enable and simplify reading these types using str's `parse` method.
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 looks great, thanks again!
Attempt to add support for
kml:Link
andkml:Icon
.A couple of points to discuss.
First
Since the spec's
kml:Icon
(orkml:BasicLinkType
) is already implemented and exported by the library asKml::Icon
, I used an enum to model the spec'skml:LinkType
. Its variants areKml::Link
andKml:Icon
. Both are constructed withkml::types::LinkModel
, the common data model used by the spec'skml:LinkType
.If
kml:Model
was to be implemented using this PR, then it'slink
field would be of typekml::types::LinkType
and it would need to be guarded so as not to have it be set tokml::types::LinkType::Icon
:Let me know how you feel about this approach.
Alternatively, I could use two identical structs with different names. I could expose Icon as
Kml::LinkIcon
to not have it interfere with the existingKml::Icon
.What makes the most sense for an approachable, intuitive API?
Second
I used empty strings for the optional String fields that have no default value. Let me know if you'd prefer to have them be
Option
s instead.Closes #10.