-
Notifications
You must be signed in to change notification settings - Fork 1.7k
rust: create types module with primitives like Step
#4342
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| /* Copyright 2020 The TensorFlow Authors. All Rights Reserved. | ||
|
|
||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||
| you may not use this file except in compliance with the License. | ||
| You may obtain a copy of the License at | ||
|
|
||
| http://www.apache.org/licenses/LICENSE-2.0 | ||
|
|
||
| Unless required by applicable law or agreed to in writing, software | ||
| distributed under the License is distributed on an "AS IS" BASIS, | ||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| See the License for the specific language governing permissions and | ||
| limitations under the License. | ||
| ==============================================================================*/ | ||
|
|
||
| //! Core simple types. | ||
|
|
||
| use std::borrow::Borrow; | ||
|
|
||
| /// A step associated with a record, strictly increasing over time within a record stream. | ||
| #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)] | ||
| pub struct Step(pub i64); | ||
|
|
||
| /// The wall time of a TensorBoard event. | ||
| /// | ||
| /// Wall times represent floating-point seconds since Unix epoch. They must be finite and non-NaN. | ||
| #[derive(Debug, PartialEq, PartialOrd, Copy, Clone)] | ||
| pub struct WallTime(f64); | ||
|
|
||
| impl WallTime { | ||
| /// Parses a wall time from a time stamp representing seconds since Unix epoch. | ||
| /// | ||
| /// Returns `None` if the given time is infinite or NaN. | ||
| pub fn new(time: f64) -> Option<Self> { | ||
| if time.is_finite() { | ||
| Some(WallTime(time)) | ||
| } else { | ||
| None | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Wall times are totally ordered and have a total equivalence relation, since we guarantee that | ||
| // they are not NaN. | ||
| #[allow(clippy::derive_ord_xor_partial_ord)] // okay because it agrees with `PartialOrd` impl | ||
| impl Ord for WallTime { | ||
| fn cmp(&self, other: &Self) -> std::cmp::Ordering { | ||
| self.partial_cmp(&other) | ||
| .unwrap_or_else(|| unreachable!("{:?} <> {:?}", &self, &other)) | ||
| } | ||
| } | ||
| impl Eq for WallTime {} | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For my education, is this any different than
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It does the same thing that $ git diff -U1
diff --git a/tensorboard/data/server/types.rs b/tensorboard/data/server/types.rs
index 59a764504..755329912 100644
--- a/tensorboard/data/server/types.rs
+++ b/tensorboard/data/server/types.rs
@@ -26,3 +26,3 @@ pub struct Step(pub i64);
/// Wall times represent floating-point seconds since Unix epoch. They must be finite and non-NaN.
-#[derive(Debug, PartialEq, PartialOrd, Copy, Clone)]
+#[derive(Debug, PartialEq, PartialOrd, Copy, Clone, Eq)]
pub struct WallTime(f64);
@@ -51,3 +51,2 @@ impl Ord for WallTime {
}
-impl Eq for WallTime {}
Instead, |
||
|
|
||
| impl From<WallTime> for f64 { | ||
| fn from(wt: WallTime) -> f64 { | ||
| wt.0 | ||
| } | ||
| } | ||
|
|
||
| /// The name of a time series within the context of a run. | ||
| /// | ||
| /// Tag names are valid Unicode text strings. They should be non-empty, though this type does not | ||
| /// enforce that. | ||
| #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)] | ||
| pub struct Tag(pub String); | ||
|
|
||
| impl Borrow<str> for Tag { | ||
| fn borrow(&self) -> &str { | ||
| &self.0 | ||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
|
|
||
| #[test] | ||
| fn test_tag_hash_map_str_access() { | ||
| use std::collections::HashMap; | ||
| let mut m: HashMap<Tag, i32> = HashMap::new(); | ||
| m.insert(Tag("accuracy".to_string()), 1); | ||
| m.insert(Tag("loss".to_string()), 2); | ||
| // We can call `get` given only a `&str`, not an owned `Tag`. | ||
| assert_eq!(m.get("accuracy"), Some(&1)); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Super noob question: What would
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yep! (where the
Nope! It’s like: m.insert(Tag("accuracy".to_string()), 1); // line 81
let tmp = 1;
assert_eq!(m.get("accuracy"), Some(&tmp)); // line 84
// `tmp` is implicitly dropped hereWe can’t get a reference to the
You can get reference equality semantics by casting to pointers. This |
||
| assert_eq!(m.get("xent"), None); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_wall_time() { | ||
| assert_eq!(WallTime::new(f64::INFINITY), None); | ||
| assert_eq!(WallTime::new(-f64::INFINITY), None); | ||
| assert_eq!(WallTime::new(f64::NAN), None); | ||
|
|
||
| assert_eq!(f64::from(WallTime::new(1234.5).unwrap()), 1234.5); | ||
| assert!(WallTime::new(1234.5) < WallTime::new(2345.625)); | ||
|
|
||
| let mut actual = vec![ | ||
| WallTime::new(123.0).unwrap(), | ||
| WallTime::new(-456.0).unwrap(), | ||
| WallTime::new(789.0).unwrap(), | ||
| ]; | ||
| actual.sort(); | ||
| let expected = vec![ | ||
| WallTime::new(-456.0).unwrap(), | ||
| WallTime::new(123.0).unwrap(), | ||
| WallTime::new(789.0).unwrap(), | ||
| ]; | ||
| assert_eq!(actual, expected); | ||
| } | ||
| } | ||
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.
reading this, it looks like PartialOrd can never disagree with
Ord. If so, what is thisderive_ord_xor_partial_ordreally enforcing?After reading a bit more about this https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord, why is the
impl Ordblock required when already given
#[derive(PartialOrd)]?(for my education of course)
Uh oh!
There was an error while loading. Please reload this page.
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.
Correct: the
PartialOrdandOrdimplementations for a given typemust agree, else many operations are undefined. (Not the scary kind of
“undefined behavior”; it’s just a contract violation on basically every
API that cares about orderings.)
This line disables a Clippy lint, whose docs you’ve linked to. I think
that the purpose is to flag code like this:
This
Ordimplementation is fine by itself, and you might think that#[derive(PartialOrd)]would implementPartialOrdfor our type bydelegating to its
Ord. But in fact it would actually delegate to thePartialOrds of its fields, which would make thePartialOrdandOrdinconsistent in this case.
In our case, the derived
PartialOrdis consistent with the manualOrd(which you can tell sincecmpjust callspartial_cmp), so Isuppressed the lint error. We could write it out—
—but I didn’t see much reason to do that.
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.
Here’s a topical upstream request to teach the lint to recognize this
safe pattern:
rust-lang/rust-clippy#6219