summaryrefslogtreecommitdiffstats
path: root/third_party/rust/uniffi-example-todolist
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/uniffi-example-todolist
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/uniffi-example-todolist')
-rw-r--r--third_party/rust/uniffi-example-todolist/.cargo-checksum.json1
-rw-r--r--third_party/rust/uniffi-example-todolist/Cargo.toml40
-rw-r--r--third_party/rust/uniffi-example-todolist/build.rs7
-rw-r--r--third_party/rust/uniffi-example-todolist/src/lib.rs150
-rw-r--r--third_party/rust/uniffi-example-todolist/src/todolist.udl38
-rw-r--r--third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.kts83
-rw-r--r--third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.py44
-rw-r--r--third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.rb47
-rw-r--r--third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.swift69
-rw-r--r--third_party/rust/uniffi-example-todolist/tests/test_generated_bindings.rs6
10 files changed, 485 insertions, 0 deletions
diff --git a/third_party/rust/uniffi-example-todolist/.cargo-checksum.json b/third_party/rust/uniffi-example-todolist/.cargo-checksum.json
new file mode 100644
index 0000000000..0f7516a258
--- /dev/null
+++ b/third_party/rust/uniffi-example-todolist/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.toml":"2cadeccd37f54f3fe48ee85eeed4acdf6e7299acb6b43ed026d16695150cbab7","build.rs":"696168e6dd8a1f181748cb36161bee14a7523b9e5d9b2e3938f02cf24d374e45","src/lib.rs":"338494783dbbcd8abbc7a1b5206f52296064091faa0a04e2d622a0d370ad12fe","src/todolist.udl":"1f8a24049c2340b9184e95facfc191ecdcb91541729ae7f20b4625d67685f13c","tests/bindings/test_todolist.kts":"f3d29b48e0193563fc4f131d91ea697f758174dcdb80ea554f233949e575bf55","tests/bindings/test_todolist.py":"f7430af9347df0daa954d38bc2203ce400affbb9a53fced4bb67a6796afa0664","tests/bindings/test_todolist.rb":"6524b5271a9cc0e2d78ca9f86ccb6973889926688a0843b4505a4f62d48f6dcb","tests/bindings/test_todolist.swift":"d1911b85fe0c8c0b42e5421b5af5d7359c9a65bba477d23560eb4b0f52e80662","tests/test_generated_bindings.rs":"46ef1fbedaac0c4867812ef2632a641eab36ab0ee12f5757567dd037aeddcbd3"},"package":null} \ No newline at end of file
diff --git a/third_party/rust/uniffi-example-todolist/Cargo.toml b/third_party/rust/uniffi-example-todolist/Cargo.toml
new file mode 100644
index 0000000000..a6f4895972
--- /dev/null
+++ b/third_party/rust/uniffi-example-todolist/Cargo.toml
@@ -0,0 +1,40 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2021"
+name = "uniffi-example-todolist"
+version = "0.22.0"
+authors = ["Firefox Sync Team <sync-team@mozilla.com>"]
+publish = false
+license = "MPL-2.0"
+
+[lib]
+name = "uniffi_todolist"
+crate-type = [
+ "lib",
+ "cdylib",
+]
+
+[dependencies]
+once_cell = "1.12"
+thiserror = "1.0"
+
+[dependencies.uniffi]
+path = "../../uniffi"
+
+[dev-dependencies.uniffi]
+path = "../../uniffi"
+features = ["bindgen-tests"]
+
+[build-dependencies.uniffi]
+path = "../../uniffi"
+features = ["build"]
diff --git a/third_party/rust/uniffi-example-todolist/build.rs b/third_party/rust/uniffi-example-todolist/build.rs
new file mode 100644
index 0000000000..7376ae1a20
--- /dev/null
+++ b/third_party/rust/uniffi-example-todolist/build.rs
@@ -0,0 +1,7 @@
+/* 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/. */
+
+fn main() {
+ uniffi::generate_scaffolding("./src/todolist.udl").unwrap();
+}
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"));
diff --git a/third_party/rust/uniffi-example-todolist/src/todolist.udl b/third_party/rust/uniffi-example-todolist/src/todolist.udl
new file mode 100644
index 0000000000..5c923314cd
--- /dev/null
+++ b/third_party/rust/uniffi-example-todolist/src/todolist.udl
@@ -0,0 +1,38 @@
+namespace todolist {
+ TodoList? get_default_list();
+ undefined set_default_list(TodoList list);
+
+ [Throws=TodoError]
+ TodoEntry create_entry_with(string todo);
+};
+
+dictionary TodoEntry {
+ string text;
+};
+
+[Error]
+enum TodoError {
+ "TodoDoesNotExist", "EmptyTodoList", "DuplicateTodo", "EmptyString", "DeligatedError"
+};
+
+interface TodoList {
+ constructor();
+ [Throws=TodoError]
+ void add_item(string todo);
+ [Throws=TodoError]
+ void add_entry(TodoEntry entry);
+ sequence<TodoEntry> get_entries();
+ sequence<string> get_items();
+ void add_entries(sequence<TodoEntry> entries);
+ void add_items(sequence<string> items);
+ [Throws=TodoError]
+ TodoEntry get_last_entry();
+ [Throws=TodoError]
+ string get_last();
+ [Throws=TodoError]
+ string get_first();
+ [Throws=TodoError]
+ void clear_item(string todo);
+ [Self=ByArc]
+ undefined make_default();
+};
diff --git a/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.kts b/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.kts
new file mode 100644
index 0000000000..bb2b292224
--- /dev/null
+++ b/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.kts
@@ -0,0 +1,83 @@
+import uniffi.todolist.*
+
+val todo = TodoList()
+
+// This throws an exception:
+try {
+ todo.getLast()
+ throw RuntimeException("Should have thrown a TodoError!")
+} catch (e: TodoException.EmptyTodoList) {
+ // It's okay, we don't have any items yet!
+}
+
+try {
+ createEntryWith("")
+ throw RuntimeException("Should have thrown a TodoError!")
+} catch (e: TodoException) {
+ // It's okay, the string was empty!
+ assert(e is TodoException.EmptyString)
+ assert(e !is TodoException.EmptyTodoList)
+}
+
+todo.addItem("Write strings support")
+
+assert(todo.getLast() == "Write strings support")
+
+todo.addItem("Write tests for strings support")
+
+assert(todo.getLast() == "Write tests for strings support")
+
+val entry = createEntryWith("Write bindings for strings as record members")
+
+todo.addEntry(entry)
+assert(todo.getLast() == "Write bindings for strings as record members")
+assert(todo.getLastEntry().text == "Write bindings for strings as record members")
+
+todo.addItem("Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣")
+assert(todo.getLast() == "Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣")
+
+val entry2 = TodoEntry("Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣")
+todo.addEntry(entry2)
+assert(todo.getLastEntry().text == "Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣")
+
+assert(todo.getEntries().size == 5)
+
+todo.addEntries(listOf(TodoEntry("foo"), TodoEntry("bar")))
+assert(todo.getEntries().size == 7)
+assert(todo.getLastEntry().text == "bar")
+
+todo.addItems(listOf("bobo", "fofo"))
+assert(todo.getItems().size == 9)
+assert(todo.getItems()[7] == "bobo")
+
+assert(getDefaultList() == null)
+
+// Note that each individual object instance needs to be explicitly destroyed,
+// either by using the `.use` helper or explicitly calling its `.destroy` method.
+// Failure to do so will leak the underlying Rust object.
+TodoList().use { todo2 ->
+ setDefaultList(todo)
+ getDefaultList()!!.use { default ->
+ assert(todo.getEntries() == default.getEntries())
+ assert(todo2.getEntries() != default.getEntries())
+ }
+
+ todo2.makeDefault()
+ getDefaultList()!!.use { default ->
+ assert(todo.getEntries() != default.getEntries())
+ assert(todo2.getEntries() == default.getEntries())
+ }
+
+ todo.addItem("Test liveness after being demoted from default")
+ assert(todo.getLast() == "Test liveness after being demoted from default")
+
+ todo2.addItem("Test shared state through local vs default reference")
+ getDefaultList()!!.use { default ->
+ assert(default.getLast() == "Test shared state through local vs default reference")
+ }
+}
+
+// Ensure the kotlin version of deinit doesn't crash, and is idempotent.
+todo.destroy()
+todo.destroy()
+
diff --git a/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.py b/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.py
new file mode 100644
index 0000000000..017e999fb2
--- /dev/null
+++ b/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.py
@@ -0,0 +1,44 @@
+from todolist import *
+
+todo = TodoList()
+
+entry = TodoEntry("Write bindings for strings in records")
+
+todo.add_item("Write python bindings")
+
+assert(todo.get_last() == "Write python bindings")
+
+todo.add_item("Write tests for bindings")
+
+assert(todo.get_last() == "Write tests for bindings")
+
+todo.add_entry(entry)
+
+assert(todo.get_last() == "Write bindings for strings in records")
+assert(todo.get_last_entry().text == "Write bindings for strings in records")
+
+todo.add_item("Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣")
+assert(todo.get_last() == "Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣")
+
+entry2 = TodoEntry("Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣")
+todo.add_entry(entry2)
+assert(todo.get_last_entry().text == "Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣")
+
+todo2 = TodoList()
+assert(todo != todo2)
+assert(todo is not todo2)
+
+assert(get_default_list() is None)
+
+set_default_list(todo)
+assert(todo.get_items() == get_default_list().get_items())
+
+todo2.make_default()
+assert(todo2.get_items() == get_default_list().get_items())
+
+todo.add_item("Test liveness after being demoted from default")
+assert(todo.get_last() == "Test liveness after being demoted from default")
+
+todo2.add_item("Test shared state through local vs default reference")
+assert(get_default_list().get_last() == "Test shared state through local vs default reference")
+
diff --git a/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.rb b/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.rb
new file mode 100644
index 0000000000..d9e04f92e7
--- /dev/null
+++ b/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+require 'test/unit'
+require 'todolist'
+
+include Test::Unit::Assertions
+include Todolist
+
+todo = TodoList.new
+entry = TodoEntry.new 'Write bindings for strings in records'
+
+todo.add_item('Write ruby bindings')
+
+assert_equal todo.get_last, 'Write ruby bindings'
+
+todo.add_item('Write tests for bindings')
+
+assert_equal todo.get_last, 'Write tests for bindings'
+
+todo.add_entry(entry)
+
+assert_equal todo.get_last, 'Write bindings for strings in records'
+assert_equal todo.get_last_entry.text, 'Write bindings for strings in records'
+
+todo.add_item("Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣")
+assert_equal todo.get_last, "Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣"
+
+entry2 = TodoEntry.new("Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣")
+todo.add_entry(entry2)
+assert_equal todo.get_last_entry.text, "Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣"
+
+todo2 = TodoList.new
+assert todo2.get_items != todo.get_items
+
+assert Todolist.get_default_list == nil
+
+Todolist.set_default_list todo
+assert todo.get_items == Todolist.get_default_list.get_items
+
+todo2.make_default
+assert todo2.get_items == Todolist.get_default_list.get_items
+
+todo.add_item "Test liveness after being demoted from default"
+assert todo.get_last == "Test liveness after being demoted from default"
+
+todo2.add_item "Test shared state through local vs default reference"
+assert Todolist.get_default_list.get_last == "Test shared state through local vs default reference" \ No newline at end of file
diff --git a/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.swift b/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.swift
new file mode 100644
index 0000000000..6ce72cadb2
--- /dev/null
+++ b/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.swift
@@ -0,0 +1,69 @@
+import todolist
+
+
+let todo = TodoList()
+do {
+ let _ = try todo.getLast()
+ fatalError("Should have thrown an EmptyTodoList error!")
+} catch TodoError.EmptyTodoList{
+ //It's okay! There are not todos!
+}
+try! todo.addItem(todo: "Write swift bindings")
+assert( try! todo.getLast() == "Write swift bindings")
+
+try! todo.addItem(todo: "Write tests for bindings")
+assert(try! todo.getLast() == "Write tests for bindings")
+
+let entry = TodoEntry(text: "Write bindings for strings as record members")
+try! todo.addEntry(entry: entry)
+assert(try! todo.getLast() == "Write bindings for strings as record members")
+
+try! todo.addItem(todo: "Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣")
+assert(try! todo.getLast() == "Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣")
+
+do {
+ let _ = try createEntryWith(todo: "")
+ fatalError("Should have thrown an EmptyString error!")
+} catch TodoError.EmptyString {
+ // It's okay! It was an empty string
+}
+
+let entry2 = TodoEntry(text: "Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣")
+try! todo.addEntry(entry: entry2)
+assert(try! todo.getLastEntry() == entry2)
+
+assert(todo.getEntries().count == 5)
+
+todo.addEntries(entries: [TodoEntry(text: "foo"), TodoEntry(text: "bar")])
+assert(todo.getEntries().count == 7)
+assert(todo.getItems().count == 7)
+assert(try! todo.getLast() == "bar")
+
+todo.addItems(items: ["bobo", "fofo"])
+assert(todo.getItems().count == 9)
+assert(todo.getItems()[7] == "bobo")
+
+// Ensure deinit doesn't crash.
+for _ in 0..<10 {
+ let list = TodoList()
+ try! list.addItem(todo: "todo")
+}
+
+let todo2 = TodoList()
+
+assert(getDefaultList() == nil)
+
+setDefaultList(list: todo)
+assert(todo.getItems() == getDefaultList()!.getItems())
+assert(todo2.getItems() != getDefaultList()!.getItems())
+
+todo2.makeDefault()
+assert(todo.getItems() != getDefaultList()!.getItems())
+assert(todo2.getItems() == getDefaultList()!.getItems())
+
+try! todo.addItem(todo: "Test liveness after being demoted from default")
+assert(try! todo.getLast() == "Test liveness after being demoted from default")
+
+try! todo2.addItem(todo: "Test shared state through local vs default reference")
+assert(try! getDefaultList()!.getLast() == "Test shared state through local vs default reference")
+
diff --git a/third_party/rust/uniffi-example-todolist/tests/test_generated_bindings.rs b/third_party/rust/uniffi-example-todolist/tests/test_generated_bindings.rs
new file mode 100644
index 0000000000..cefdbfe1dc
--- /dev/null
+++ b/third_party/rust/uniffi-example-todolist/tests/test_generated_bindings.rs
@@ -0,0 +1,6 @@
+uniffi::build_foreign_language_testcases!(
+ "tests/bindings/test_todolist.kts",
+ "tests/bindings/test_todolist.swift",
+ "tests/bindings/test_todolist.rb",
+ "tests/bindings/test_todolist.py"
+);