[cmgr][ws] Refactor: `WorkItem` in its own file

This is the first of several maneuvers to implement
dispatching work from outside the oversized
`work_scheduler.rs` file.

Bug: 35214
Bug: 35215

Change-Id: I9cc73641aee0b214218ca3d1c012e03ec96c700d
diff --git a/src/sys/component_manager/src/work_scheduler/mod.rs b/src/sys/component_manager/src/work_scheduler/mod.rs
index 1e0a9b5..99a18e7 100644
--- a/src/sys/component_manager/src/work_scheduler/mod.rs
+++ b/src/sys/component_manager/src/work_scheduler/mod.rs
@@ -4,5 +4,7 @@
 
 pub mod work_scheduler;
 
+mod work_item;
+
 #[cfg(test)]
 mod routing_tests;
diff --git a/src/sys/component_manager/src/work_scheduler/work_item.rs b/src/sys/component_manager/src/work_scheduler/work_item.rs
new file mode 100644
index 0000000..fe72715
--- /dev/null
+++ b/src/sys/component_manager/src/work_scheduler/work_item.rs
@@ -0,0 +1,75 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use {crate::model::AbsoluteMoniker, fidl_fuchsia_sys2 as fsys, std::cmp::Ordering};
+
+/// `WorkItem` is a single item in the ordered-by-deadline collection maintained by `WorkScheduler`.
+#[derive(Clone, Debug, Eq)]
+pub(super) struct WorkItem {
+    // TODO(markdittmer): Document.
+    pub(super) abs_moniker: AbsoluteMoniker,
+    /// Unique identifier for this unit of work **relative to others with the same
+    /// `abs_moniker`**.
+    pub(super) id: String,
+    /// Next deadline for this unit of work, in monotonic time.
+    pub(super) next_deadline_monotonic: i64,
+    /// Period between repeating this unit of work (if any), measure in nanoseconds.
+    pub(super) period: Option<i64>,
+}
+
+/// WorkItem default equality: identical `abs_moniker` and `id`.
+impl PartialEq for WorkItem {
+    fn eq(&self, other: &Self) -> bool {
+        self.id == other.id && self.abs_moniker == other.abs_moniker
+    }
+}
+
+impl WorkItem {
+    pub(super) fn new(
+        abs_moniker: &AbsoluteMoniker,
+        id: &str,
+        next_deadline_monotonic: i64,
+        period: Option<i64>,
+    ) -> Self {
+        WorkItem {
+            abs_moniker: abs_moniker.clone(),
+            id: id.to_string(),
+            next_deadline_monotonic,
+            period,
+        }
+    }
+
+    /// Produce a canonical `WorkItem` from its identifying information: `abs_moniker` + `id`. Note
+    /// that other fields are ignored in equality testing.
+    pub(super) fn new_by_identity(abs_moniker: &AbsoluteMoniker, id: &str) -> Self {
+        WorkItem {
+            abs_moniker: abs_moniker.clone(),
+            id: id.to_string(),
+            next_deadline_monotonic: 0,
+            period: None,
+        }
+    }
+
+    /// Attempt to unpack identifying info (`abs_moniker`, `id`) + `WorkRequest` into a `WorkItem`.
+    /// Errors:
+    /// - INVALID_ARGUMENTS: Missing or invalid `work_request.start` value.
+    pub(super) fn try_new(
+        abs_moniker: &AbsoluteMoniker,
+        id: &str,
+        work_request: &fsys::WorkRequest,
+    ) -> Result<Self, fsys::Error> {
+        let next_deadline_monotonic = match &work_request.start {
+            None => Err(fsys::Error::InvalidArguments),
+            Some(start) => match start {
+                fsys::Start::MonotonicTime(monotonic_time) => Ok(monotonic_time),
+                _ => Err(fsys::Error::InvalidArguments),
+            },
+        }?;
+        Ok(WorkItem::new(abs_moniker, id, *next_deadline_monotonic, work_request.period))
+    }
+
+    pub(super) fn deadline_order(left: &Self, right: &Self) -> Ordering {
+        left.next_deadline_monotonic.cmp(&right.next_deadline_monotonic)
+    }
+}
diff --git a/src/sys/component_manager/src/work_scheduler/work_scheduler.rs b/src/sys/component_manager/src/work_scheduler/work_scheduler.rs
index 1cd4960..ea5ca71b 100644
--- a/src/sys/component_manager/src/work_scheduler/work_scheduler.rs
+++ b/src/sys/component_manager/src/work_scheduler/work_scheduler.rs
@@ -17,6 +17,7 @@
     crate::{
         framework::FrameworkCapability,
         model::{error::ModelError, hooks::*, AbsoluteMoniker, Realm},
+        work_scheduler::work_item::WorkItem,
     },
     cm_rust::{CapabilityPath, ExposeDecl, ExposeTarget, FrameworkCapabilityDecl},
     failure::{format_err, Error},
@@ -31,7 +32,7 @@
     },
     lazy_static::lazy_static,
     log::warn,
-    std::{cmp::Ordering, convert::TryInto, sync::Arc},
+    std::{convert::TryInto, sync::Arc},
 };
 
 lazy_static! {
@@ -45,75 +46,6 @@
         Arc::new(Mutex::new(WorkScheduler::new()));
 }
 
-/// `WorkItem` is a single item in the ordered-by-deadline collection maintained by `WorkScheduler`.
-#[derive(Clone, Debug, Eq)]
-struct WorkItem {
-    /// The `AbsoluteMoniker` of the realm/component instance that owns this `WorkItem`.
-    abs_moniker: AbsoluteMoniker,
-    /// Unique identifier for this unit of work **relative to others with the same `abs_moniker`**.
-    id: String,
-    /// Next deadline for this unit of work, in monotonic time.
-    next_deadline_monotonic: i64,
-    /// Period between repeating this unit of work (if any), measure in nanoseconds.
-    period: Option<i64>,
-}
-
-/// WorkItem default equality: identical `abs_moniker` and `id`.
-impl PartialEq for WorkItem {
-    fn eq(&self, other: &Self) -> bool {
-        self.id == other.id && self.abs_moniker == other.abs_moniker
-    }
-}
-
-impl WorkItem {
-    fn new(
-        abs_moniker: &AbsoluteMoniker,
-        id: &str,
-        next_deadline_monotonic: i64,
-        period: Option<i64>,
-    ) -> Self {
-        WorkItem {
-            abs_moniker: abs_moniker.clone(),
-            id: id.to_string(),
-            next_deadline_monotonic,
-            period,
-        }
-    }
-
-    /// Produce a canonical `WorkItem` from its identifying information: `abs_moniker` + `id`. Note
-    /// that other fields are ignored in equality testing.
-    fn new_by_identity(abs_moniker: &AbsoluteMoniker, id: &str) -> Self {
-        WorkItem {
-            abs_moniker: abs_moniker.clone(),
-            id: id.to_string(),
-            next_deadline_monotonic: 0,
-            period: None,
-        }
-    }
-
-    /// Attempt to unpack identifying info (`abs_moniker`, `id`) + `WorkRequest` into a `WorkItem`.
-    /// Errors:
-    /// - INVALID_ARGUMENTS: Missing or invalid `work_request.start` value.
-    fn try_new(
-        abs_moniker: &AbsoluteMoniker,
-        id: &str,
-        work_request: &fsys::WorkRequest,
-    ) -> Result<Self, fsys::Error> {
-        let next_deadline_monotonic = match &work_request.start {
-            None => Err(fsys::Error::InvalidArguments),
-            Some(start) => match start {
-                fsys::Start::MonotonicTime(monotonic_time) => Ok(monotonic_time),
-                _ => Err(fsys::Error::InvalidArguments),
-            },
-        }?;
-        Ok(WorkItem::new(abs_moniker, id, *next_deadline_monotonic, work_request.period))
-    }
-
-    fn deadline_order(left: &Self, right: &Self) -> Ordering {
-        left.next_deadline_monotonic.cmp(&right.next_deadline_monotonic)
-    }
-}
-
 /// A self-managed timer instantiated by `WorkScheduler` to implement the "wakeup" part of its
 /// wakeup, batch, and dispatch cycles.
 struct WorkSchedulerTimer {