summaryrefslogtreecommitdiffstats
path: root/third_party/rust/uniffi-example-todolist/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/uniffi-example-todolist/src/lib.rs')
-rw-r--r--third_party/rust/uniffi-example-todolist/src/lib.rs150
1 files changed, 150 insertions, 0 deletions
diff --git a/third_party/rust/uniffi-example-todolist/src/lib.rs b/third_party/rust/uniffi-example-todolist/src/lib.rs
new file mode 100644
index 0000000000..fb2900e615
--- /dev/null
+++ b/third_party/rust/uniffi-example-todolist/src/lib.rs
@@ -0,0 +1,150 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use std::sync::{Arc, RwLock};
+
+use once_cell::sync::Lazy;
+
+#[derive(Debug, Clone)]
+pub struct TodoEntry {
+ text: String,
+}
+
+// There is a single "default" TodoList that can be shared
+// by all consumers of this component. Depending on requirements,
+// a real app might like to use a `Weak<>` rather than an `Arc<>`
+// here to reduce the risk of circular references.
+static DEFAULT_LIST: Lazy<RwLock<Option<Arc<TodoList>>>> = Lazy::new(|| RwLock::new(None));
+
+#[derive(Debug, thiserror::Error)]
+pub enum TodoError {
+ #[error("The todo does not exist!")]
+ TodoDoesNotExist,
+ #[error("The todolist is empty!")]
+ EmptyTodoList,
+ #[error("That todo already exists!")]
+ DuplicateTodo,
+ #[error("Empty String error!: {0}")]
+ EmptyString(String),
+ #[error("I am a delegated Error: {0}")]
+ DeligatedError(#[from] std::io::Error),
+}
+
+/// Get a reference to the global default TodoList, if set.
+///
+fn get_default_list() -> Option<Arc<TodoList>> {
+ DEFAULT_LIST.read().unwrap().clone()
+}
+
+/// Set the global default TodoList.
+///
+/// This will silently drop any previously set value.
+///
+fn set_default_list(list: Arc<TodoList>) {
+ *DEFAULT_LIST.write().unwrap() = Some(list);
+}
+
+/// Create a new TodoEntry from the given string.
+///
+fn create_entry_with<S: Into<String>>(item: S) -> Result<TodoEntry> {
+ let text = item.into();
+ if text.is_empty() {
+ return Err(TodoError::EmptyString(
+ "Cannot add empty string as entry".to_string(),
+ ));
+ }
+ Ok(TodoEntry { text })
+}
+
+type Result<T, E = TodoError> = std::result::Result<T, E>;
+
+// A simple Todolist.
+// UniFFI requires that we use interior mutability for managing mutable state, so we wrap our `Vec` in a RwLock.
+// (A Mutex would also work, but a RwLock is more appropriate for this use-case, so we use it).
+#[derive(Debug)]
+pub struct TodoList {
+ items: RwLock<Vec<String>>,
+}
+
+impl TodoList {
+ fn new() -> Self {
+ Self {
+ items: RwLock::new(Vec::new()),
+ }
+ }
+
+ fn add_item<S: Into<String>>(&self, item: S) -> Result<()> {
+ let item = item.into();
+ if item.is_empty() {
+ return Err(TodoError::EmptyString(
+ "Cannot add empty string as item".to_string(),
+ ));
+ }
+ let mut items = self.items.write().unwrap();
+ if items.contains(&item) {
+ return Err(TodoError::DuplicateTodo);
+ }
+ items.push(item);
+ Ok(())
+ }
+
+ fn get_last(&self) -> Result<String> {
+ let items = self.items.read().unwrap();
+ items.last().cloned().ok_or(TodoError::EmptyTodoList)
+ }
+
+ fn get_first(&self) -> Result<String> {
+ let items = self.items.read().unwrap();
+ items.first().cloned().ok_or(TodoError::EmptyTodoList)
+ }
+
+ fn add_entries(&self, entries: Vec<TodoEntry>) {
+ let mut items = self.items.write().unwrap();
+ items.extend(entries.into_iter().map(|e| e.text))
+ }
+
+ fn add_entry(&self, entry: TodoEntry) -> Result<()> {
+ self.add_item(entry.text)
+ }
+
+ fn add_items<S: Into<String>>(&self, items: Vec<S>) {
+ let mut my_items = self.items.write().unwrap();
+ my_items.extend(items.into_iter().map(Into::into))
+ }
+
+ fn get_items(&self) -> Vec<String> {
+ let items = self.items.read().unwrap();
+ items.clone()
+ }
+
+ fn get_entries(&self) -> Vec<TodoEntry> {
+ let items = self.items.read().unwrap();
+ items
+ .iter()
+ .map(|text| TodoEntry { text: text.clone() })
+ .collect()
+ }
+
+ fn get_last_entry(&self) -> Result<TodoEntry> {
+ let text = self.get_last()?;
+ Ok(TodoEntry { text })
+ }
+
+ fn clear_item<S: Into<String>>(&self, item: S) -> Result<()> {
+ let item = item.into();
+ let mut items = self.items.write().unwrap();
+ let idx = items
+ .iter()
+ .position(|s| s == &item)
+ .ok_or(TodoError::TodoDoesNotExist)?;
+ items.remove(idx);
+ Ok(())
+ }
+
+ fn make_default(self: Arc<Self>) {
+ set_default_list(self);
+ }
+}
+
+include!(concat!(env!("OUT_DIR"), "/todolist.uniffi.rs"));