summaryrefslogtreecommitdiffstats
path: root/third_party/rust/dogear/src/driver.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/dogear/src/driver.rs')
-rw-r--r--third_party/rust/dogear/src/driver.rs212
1 files changed, 212 insertions, 0 deletions
diff --git a/third_party/rust/dogear/src/driver.rs b/third_party/rust/dogear/src/driver.rs
new file mode 100644
index 0000000000..1c98ebdfb1
--- /dev/null
+++ b/third_party/rust/dogear/src/driver.rs
@@ -0,0 +1,212 @@
+// Copyright 2018-2019 Mozilla
+
+// 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.
+
+use std::{fmt::Arguments, time::Duration};
+
+use log::{Level, LevelFilter, Log};
+
+use crate::error::{ErrorKind, Result};
+use crate::guid::Guid;
+use crate::merge::StructureCounts;
+use crate::tree::ProblemCounts;
+
+/// An abort signal is used to abort merging. Implementations of `AbortSignal`
+/// can store an aborted flag, usually as an atomic integer or Boolean, set
+/// the flag on abort, and have `AbortSignal::aborted` return the flag's value.
+///
+/// Since merging is synchronous, it's not possible to interrupt a merge from
+/// the same thread that started it. In practice, this means a signal will
+/// implement `Send` and `Sync`, too, so that another thread can set the
+/// aborted flag.
+///
+/// The name comes from the `AbortSignal` DOM API.
+pub trait AbortSignal {
+ /// Indicates if the caller signaled to abort.
+ fn aborted(&self) -> bool;
+
+ /// Returns an error if the caller signaled to abort. This helper makes it
+ /// easier to use the signal with the `?` operator.
+ fn err_if_aborted(&self) -> Result<()> {
+ if self.aborted() {
+ Err(ErrorKind::Abort.into())
+ } else {
+ Ok(())
+ }
+ }
+}
+
+/// A default signal that can't be aborted.
+pub struct DefaultAbortSignal;
+
+impl AbortSignal for DefaultAbortSignal {
+ fn aborted(&self) -> bool {
+ false
+ }
+}
+
+/// A merge telemetry event.
+pub enum TelemetryEvent {
+ FetchLocalTree(TreeStats),
+ FetchRemoteTree(TreeStats),
+ Merge(Duration, StructureCounts),
+ Apply(Duration),
+}
+
+/// Records the time taken to build a local or remote tree, number of items
+/// in the tree, and structure problem counts.
+pub struct TreeStats {
+ pub time: Duration,
+ pub items: usize,
+ pub deletions: usize,
+ pub problems: ProblemCounts,
+}
+
+/// A merge driver provides methods to customize merging behavior.
+pub trait Driver {
+ /// Generates a new GUID for the given invalid GUID. This is used to fix up
+ /// items with GUIDs that Places can't store (bug 1380606, bug 1313026).
+ ///
+ /// The default implementation returns an error, forbidding invalid GUIDs.
+ ///
+ /// Implementations of `Driver` can either use the `rand` and `base64`
+ /// crates to generate a new, random GUID (9 bytes, Base64url-encoded
+ /// without padding), or use an existing method like Desktop's
+ /// `nsINavHistoryService::MakeGuid`. Dogear doesn't generate new GUIDs
+ /// automatically to avoid depending on those crates.
+ ///
+ /// Implementations can also return `Ok(invalid_guid.clone())` to pass
+ /// through all invalid GUIDs, as the tests do.
+ fn generate_new_guid(&self, invalid_guid: &Guid) -> Result<Guid> {
+ Err(ErrorKind::InvalidGuid(invalid_guid.clone()).into())
+ }
+
+ /// Returns the maximum log level for merge messages. The default
+ /// implementation returns the `log` crate's global maximum level.
+ fn max_log_level(&self) -> LevelFilter {
+ log::max_level()
+ }
+
+ /// Returns a logger for merge messages.
+ ///
+ /// The default implementation returns the `log` crate's global logger.
+ ///
+ /// Implementations can override this method to return a custom logger,
+ /// where using the global logger won't work. For example, Firefox Desktop
+ /// has an existing Sync logging setup outside of the `log` crate.
+ fn logger(&self) -> &dyn Log {
+ log::logger()
+ }
+
+ /// Records a merge telemetry event.
+ ///
+ /// The default implementation is a no-op that discards the event.
+ /// Implementations can override this method to capture event and bookmark
+ /// validation telemetry.
+ fn record_telemetry_event(&self, _: TelemetryEvent) {}
+}
+
+/// A default implementation of the merge driver.
+pub struct DefaultDriver;
+
+impl Driver for DefaultDriver {}
+
+/// Logs a merge message.
+pub fn log<D: Driver>(
+ driver: &D,
+ level: Level,
+ args: Arguments<'_>,
+ module_path: &'static str,
+ file: &'static str,
+ line: u32,
+) {
+ let meta = log::Metadata::builder()
+ .level(level)
+ .target(module_path)
+ .build();
+ if driver.logger().enabled(&meta) {
+ driver.logger().log(
+ &log::Record::builder()
+ .args(args)
+ .metadata(meta)
+ .module_path(Some(module_path))
+ .file(Some(file))
+ .line(Some(line))
+ .build(),
+ );
+ }
+}
+
+#[macro_export]
+macro_rules! error {
+ ($driver:expr, $($args:tt)+) => {
+ if log::Level::Error <= $crate::Driver::max_log_level($driver) {
+ $crate::log(
+ $driver,
+ log::Level::Error,
+ format_args!($($args)+),
+ module_path!(),
+ file!(),
+ line!(),
+ );
+ }
+ }
+}
+
+#[macro_export]
+macro_rules! warn {
+ ($driver:expr, $($args:tt)+) => {
+ if log::Level::Warn <= $crate::Driver::max_log_level($driver) {
+ $crate::log(
+ $driver,
+ log::Level::Warn,
+ format_args!($($args)+),
+ module_path!(),
+ file!(),
+ line!(),
+ );
+ }
+ }
+}
+
+#[macro_export]
+macro_rules! debug {
+ ($driver:expr, $($args:tt)+) => {
+ if log::Level::Debug <= $crate::Driver::max_log_level($driver) {
+ $crate::log(
+ $driver,
+ log::Level::Debug,
+ format_args!($($args)+),
+ module_path!(),
+ file!(),
+ line!(),
+ );
+ }
+ }
+}
+
+#[macro_export]
+macro_rules! trace {
+ ($driver:expr, $($args:tt)+) => {
+ if log::Level::Trace <= $crate::Driver::max_log_level($driver) {
+ $crate::log(
+ $driver,
+ log::Level::Trace,
+ format_args!($($args)+),
+ module_path!(),
+ file!(),
+ line!(),
+ );
+ }
+ }
+}