diff options
Diffstat (limited to 'third_party/rust/uniffi-example-todolist/src/lib.rs')
-rw-r--r-- | third_party/rust/uniffi-example-todolist/src/lib.rs | 150 |
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")); |