-
Notifications
You must be signed in to change notification settings - Fork 9
Introduce boolean-like value types (fixes #13) - wip. #15
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 |
---|---|---|
|
@@ -33,9 +33,16 @@ pub enum Type { | |
/// has reached 0 or that a device is ready. | ||
Unit, | ||
|
||
/// A boolean. Used for instance for on-off switches, presence | ||
/// detectors, etc. | ||
Bool, | ||
/// | ||
/// # Boolean values | ||
/// | ||
|
||
/// A boolean on/off state. Used for various two-states switches. | ||
OnOff, | ||
|
||
/// A boolean open/closed state. Used for instance for doors, | ||
/// windows, etc. | ||
OpenClosed, | ||
|
||
/// | ||
/// # Time | ||
|
@@ -56,6 +63,8 @@ pub enum Type { | |
Color, | ||
Json, | ||
Binary, | ||
|
||
ExtBool, | ||
ExtNumeric, | ||
} | ||
|
||
|
@@ -67,11 +76,68 @@ impl Type { | |
use self::Type::*; | ||
match *self { | ||
Duration | TimeStamp | Temperature | ExtNumeric | Color => false, | ||
Unit | Bool | String | Json | Binary => true, | ||
Unit | String | Json | Binary | OnOff | OpenClosed | ExtBool => true, | ||
} | ||
} | ||
} | ||
|
||
/// An on/off state. Internal representation may be either On or Off. | ||
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] | ||
pub enum OnOff { | ||
On, | ||
Off, | ||
} | ||
|
||
impl OnOff { | ||
fn as_bool(&self) -> bool { | ||
match *self { | ||
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. I see two different approaches in the code [1] https://github.com/rust-lang/rust/blob/master/src/doc/style/features/match.md 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. Yes, I generally do the former. I seem to remember stumbling upon a case in which it didn't work, so falling back to the latter. If you wish to fix it, you're more than welcome :) |
||
OnOff::On => true, | ||
OnOff::Off => false, | ||
} | ||
} | ||
} | ||
|
||
impl PartialOrd for OnOff { | ||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { | ||
Some(self.cmp(other)) | ||
} | ||
} | ||
|
||
impl Ord for OnOff { | ||
fn cmp(&self, other: &Self) -> Ordering { | ||
self.as_bool().cmp(&other.as_bool()) | ||
} | ||
} | ||
|
||
/// An open/closed state. Internal representation may be either | ||
/// Open or Closed. | ||
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] | ||
pub enum OpenClosed { | ||
Open, | ||
Closed, | ||
} | ||
|
||
impl OpenClosed { | ||
fn as_bool(&self) -> bool { | ||
match *self { | ||
OpenClosed::Open => true, | ||
OpenClosed::Closed => false, | ||
} | ||
} | ||
} | ||
|
||
impl PartialOrd for OpenClosed { | ||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { | ||
Some(self.cmp(other)) | ||
} | ||
} | ||
|
||
impl Ord for OpenClosed { | ||
fn cmp(&self, other: &Self) -> Ordering { | ||
self.as_bool().cmp(&other.as_bool()) | ||
} | ||
} | ||
|
||
/// A temperature. Internal representation may be either Fahrenheit or | ||
/// Celcius. The FoxBox adapters are expected to perform conversions | ||
/// to the format requested by their devices. | ||
|
@@ -123,6 +189,40 @@ impl PartialOrd for Json { | |
} | ||
} | ||
|
||
/// A data structure holding a boolean value of a type that has not | ||
/// been standardized yet. | ||
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] | ||
pub struct ExtBool { | ||
pub value: bool, | ||
|
||
/// The vendor. Used for namespacing purposes, to avoid | ||
/// confusing two incompatible extensions with similar | ||
/// names. For instance, "[email protected]". | ||
pub vendor: String, | ||
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. Side-note: as part of #11, these strings should become atoms. Otherwise, we're going to lose lots of space. 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 :) |
||
|
||
/// Identification of the adapter introducing this value. | ||
/// Designed to aid with tracing and debugging. | ||
pub adapter: String, | ||
|
||
/// A string describing the nature of the value, designed to | ||
/// aid with type-checking. | ||
/// | ||
/// Examples: `"PresenceDetected"`. | ||
pub kind: String, | ||
} | ||
|
||
impl PartialOrd for ExtBool { | ||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { | ||
if self.vendor != other.vendor { | ||
return None; | ||
} else if self.kind != other.kind { | ||
return None; | ||
} | ||
|
||
self.value.partial_cmp(&other.value) | ||
} | ||
} | ||
|
||
/// A data structure holding a numeric value of a type that has not | ||
/// been standardized yet. | ||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] | ||
|
@@ -162,7 +262,8 @@ impl PartialOrd for ExtNumeric { | |
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] | ||
pub enum Value { | ||
Unit, | ||
Bool(bool), | ||
OnOff(OnOff), | ||
OpenClosed(OpenClosed), | ||
Duration(ValDuration), | ||
TimeStamp(TimeStamp), | ||
Temperature(Temperature), | ||
|
@@ -171,18 +272,22 @@ pub enum Value { | |
|
||
// FIXME: Add more as we identify needs | ||
|
||
/// A boolean value representing a unit that has not been | ||
/// standardized yet into the API. | ||
ExtBool(ExtBool), | ||
|
||
/// A numeric value representing a unit that has not been | ||
/// standardized yet into the API. | ||
ExtNumeric(ExtNumeric), | ||
|
||
/// A Json value. We put it behind an `Arc` to make sure that | ||
/// cloning remains unexpensive. | ||
/// cloning remains inexpensive. | ||
Json(Arc<Json>), | ||
|
||
/// Binary data. | ||
Binary { | ||
/// The actual data. We put it behind an `Arc` to make sure | ||
/// that cloning remains unexpensive. | ||
/// that cloning remains inexpensive. | ||
data: Arc<Vec<u8>>, | ||
mimetype: String | ||
} | ||
|
@@ -192,14 +297,16 @@ impl Value { | |
pub fn get_type(&self) -> Type { | ||
match *self { | ||
Value::Unit => Type::Unit, | ||
Value::Bool(_) => Type::Bool, | ||
Value::OnOff => Type::OnOff, | ||
Value::OpenClosed => Type::OpenClosed, | ||
Value::String(_) => Type::String, | ||
Value::Duration(_) => Type::Duration, | ||
Value::TimeStamp(_) => Type::TimeStamp, | ||
Value::Temperature(_) => Type::Temperature, | ||
Value::Color(_) => Type::Color, | ||
Value::Json(_) => Type::Json, | ||
Value::Binary{..} => Type::Binary, | ||
Value::ExtBool(_) => Type::ExtBool, | ||
Value::ExtNumeric(_) => Type::ExtNumeric, | ||
} | ||
} | ||
|
@@ -230,8 +337,11 @@ impl PartialOrd for Value { | |
(&Unit, &Unit) => Some(Equal), | ||
(&Unit, _) => None, | ||
|
||
(&Bool(a), &Bool(b)) => a.partial_cmp(&b), | ||
(&Bool(_), _) => None, | ||
(&OnOff(ref a), &OnOff(ref b)) => a.partial_cmp(b), | ||
(&OnOff(_), _) => None, | ||
|
||
(&OpenClosed(ref a), &OpenClosed(ref b)) => a.partial_cmp(b), | ||
(&OpenClosed(_), _) => None, | ||
|
||
(&Duration(ref a), &Duration(ref b)) => a.partial_cmp(b), | ||
(&Duration(_), _) => None, | ||
|
@@ -245,6 +355,9 @@ impl PartialOrd for Value { | |
(&Color(ref a), &Color(ref b)) => a.partial_cmp(b), | ||
(&Color(_), _) => None, | ||
|
||
(&ExtBool(ref a), &ExtBool(ref b)) => a.partial_cmp(b), | ||
(&ExtBool(_), _) => None, | ||
|
||
(&ExtNumeric(ref a), &ExtNumeric(ref b)) => a.partial_cmp(b), | ||
(&ExtNumeric(_), _) => 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.
Hey @Yoric I need your help/advise here :)
I'm trying to better understand
PartialOrd
for different types, and I was thinking that boolean-like enums should implement the same traits as real bool -Eq
in addition toPartialEq
andPartialOrd
, also I found that havingas_bool
method can be handy (maybe there should beBoolValue {fn as_bool}
trait), but still not everything clear in my head - so please let me know if I over-complicating things or introducing bloat.Thanks!
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 agree that they should implement
Eq
andPartialEq
. SinceValue
implementsPartialOrd
, we should also implement it for these new values. And since they are booleans, we might as well go for a fullOrd
, indeed.I'm not sure that
as_bool
is very useful. I think that we prefer pattern-matching againstOn
/Off
(which offers no ambiguity) to checking whetheras_bool()
istrue
/false
(which does). So I wouldn't implement it for the time being.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, no
as_bool
, but we still needPartialOrd
andOrd
right? :)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.
Yep :)
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.
Aaand few more
best practices
questions for you (sorry for too many, just want to have common ground) :)PartialOrd
andOrd
implementation to#derive
it won't behave like boolean (true > false
, butOnOff::On < OnOff::Off
), I suspect we want to have boolean-like behavior and should implementOrd
andPartialOrd
manually?PartialOrd
viaOrd
like:Looking at the
Ord
andPartiallyOrd
hierarchy it seems that more naturally would be to implement it the other way around,Ord
viaPartialOrd
, but we'll have additionunwrap
call inself.partal_cmp(other).unwrap()
.catch-all
clause in two-states enum like this, or we should guard ourselves in case one more state will be added?vs
or even something crazy :)
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.
On the contrary, thanks for trying to setup a common ground!
I suppose that this would be the least surprising.
That's how I would do it.
I haven't thought of this in terms of hierarchy. But it seems to me that
PartialOrd
can be derived fromOrd
naturally, so I'd go for it.Ok, ok, I get it, it would be simpler to introduce
as_bool
:) Just don't make that method public.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 for replies! Handling :)