diff options
Diffstat (limited to 'vendor/rust-analyzer-salsa/examples')
9 files changed, 356 insertions, 0 deletions
diff --git a/vendor/rust-analyzer-salsa/examples/compiler/compiler.rs b/vendor/rust-analyzer-salsa/examples/compiler/compiler.rs new file mode 100644 index 000000000..194599a63 --- /dev/null +++ b/vendor/rust-analyzer-salsa/examples/compiler/compiler.rs @@ -0,0 +1,72 @@ +use std::sync::Arc;
+
+use crate::{interner::Interner, values::*};
+
+#[salsa::query_group(CompilerDatabase)]
+pub trait Compiler: Interner {
+ #[salsa::input]
+ fn input_string(&self) -> Arc<String>;
+
+ /// Get the fields.
+ fn fields(&self, class: Class) -> Arc<Vec<Field>>;
+
+ /// Get the list of all classes
+ fn all_classes(&self) -> Arc<Vec<Class>>;
+
+ /// Get the list of all fields
+ fn all_fields(&self) -> Arc<Vec<Field>>;
+}
+
+/// This function parses a dummy language with the following structure:
+///
+/// Classes are defined one per line, consisting of a comma-separated list of fields.
+///
+/// Example:
+///
+/// ```
+/// lorem,ipsum
+/// dolor,sit,amet,
+/// consectetur,adipiscing,elit
+/// ```
+fn all_classes(db: &dyn Compiler) -> Arc<Vec<Class>> {
+ let string = db.input_string();
+
+ let rows = string.split('\n');
+ let classes: Vec<_> = rows
+ .filter(|string| !string.is_empty())
+ .map(|string| {
+ let fields = string
+ .trim()
+ .split(',')
+ .filter(|string| !string.is_empty())
+ .map(|name_str| {
+ let name = name_str.to_owned();
+ let field_data = FieldData { name };
+ db.intern_field(field_data)
+ })
+ .collect();
+ let class_data = ClassData { fields };
+ db.intern_class(class_data)
+ })
+ .collect();
+
+ Arc::new(classes)
+}
+
+fn fields(db: &dyn Compiler, class: Class) -> Arc<Vec<Field>> {
+ let class = db.lookup_intern_class(class);
+ Arc::new(class.fields)
+}
+
+fn all_fields(db: &dyn Compiler) -> Arc<Vec<Field>> {
+ Arc::new(
+ db.all_classes()
+ .iter()
+ .cloned()
+ .flat_map(|class| {
+ let fields = db.fields(class);
+ (0..fields.len()).map(move |i| fields[i])
+ })
+ .collect(),
+ )
+}
diff --git a/vendor/rust-analyzer-salsa/examples/compiler/implementation.rs b/vendor/rust-analyzer-salsa/examples/compiler/implementation.rs new file mode 100644 index 000000000..34a1e1f2e --- /dev/null +++ b/vendor/rust-analyzer-salsa/examples/compiler/implementation.rs @@ -0,0 +1,23 @@ +use crate::compiler::CompilerDatabase;
+use crate::interner::InternerDatabase;
+
+/// Our "database" will be threaded through our application (though
+/// 99% of the application only interacts with it through traits and
+/// never knows its real name). It contains all the values for all of
+/// our memoized queries and encapsulates **all mutable state that
+/// persists longer than a single query execution.**
+///
+/// Databases can contain whatever you want them to, but salsa
+/// requires you to add a `salsa::Runtime` member. Note
+/// though: you should be very careful if adding shared, mutable state
+/// to your context (e.g., a shared counter or some such thing). If
+/// mutations to that shared state affect the results of your queries,
+/// that's going to mess up the incremental results.
+#[salsa::database(InternerDatabase, CompilerDatabase)]
+#[derive(Default)]
+pub struct DatabaseImpl {
+ storage: salsa::Storage<DatabaseImpl>,
+}
+
+/// This impl tells salsa where to find the salsa runtime.
+impl salsa::Database for DatabaseImpl {}
diff --git a/vendor/rust-analyzer-salsa/examples/compiler/interner.rs b/vendor/rust-analyzer-salsa/examples/compiler/interner.rs new file mode 100644 index 000000000..8edf1e0ee --- /dev/null +++ b/vendor/rust-analyzer-salsa/examples/compiler/interner.rs @@ -0,0 +1,10 @@ +use crate::values::*;
+
+#[salsa::query_group(InternerDatabase)]
+pub trait Interner {
+ #[salsa::interned]
+ fn intern_field(&self, field: FieldData) -> Field;
+
+ #[salsa::interned]
+ fn intern_class(&self, class: ClassData) -> Class;
+}
diff --git a/vendor/rust-analyzer-salsa/examples/compiler/main.rs b/vendor/rust-analyzer-salsa/examples/compiler/main.rs new file mode 100644 index 000000000..ed659ef26 --- /dev/null +++ b/vendor/rust-analyzer-salsa/examples/compiler/main.rs @@ -0,0 +1,40 @@ +use std::sync::Arc;
+
+mod compiler;
+mod implementation;
+mod interner;
+mod values;
+
+use self::compiler::Compiler;
+use self::implementation::DatabaseImpl;
+use self::interner::Interner;
+
+static INPUT_STR: &str = r#"
+lorem,ipsum
+dolor,sit,amet,
+consectetur,adipiscing,elit
+"#;
+
+#[test]
+fn test() {
+ let mut db = DatabaseImpl::default();
+
+ db.set_input_string(Arc::new(INPUT_STR.to_owned()));
+
+ let all_fields = db.all_fields();
+ assert_eq!(
+ format!("{:?}", all_fields),
+ "[Field(0), Field(1), Field(2), Field(3), Field(4), Field(5), Field(6), Field(7)]"
+ );
+}
+
+fn main() {
+ let mut db = DatabaseImpl::default();
+
+ db.set_input_string(Arc::new(INPUT_STR.to_owned()));
+
+ for field in db.all_fields().iter() {
+ let field_data = db.lookup_intern_field(*field);
+ println!("{:?} => {:?}", field, field_data);
+ }
+}
diff --git a/vendor/rust-analyzer-salsa/examples/compiler/values.rs b/vendor/rust-analyzer-salsa/examples/compiler/values.rs new file mode 100644 index 000000000..2649029ea --- /dev/null +++ b/vendor/rust-analyzer-salsa/examples/compiler/values.rs @@ -0,0 +1,35 @@ +#[derive(Clone, Debug, Hash, PartialEq, Eq)]
+pub struct ClassData {
+ pub fields: Vec<Field>,
+}
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub struct Class(salsa::InternId);
+
+impl salsa::InternKey for Class {
+ fn from_intern_id(id: salsa::InternId) -> Self {
+ Self(id)
+ }
+
+ fn as_intern_id(&self) -> salsa::InternId {
+ self.0
+ }
+}
+
+#[derive(Clone, Debug, Hash, PartialEq, Eq)]
+pub struct FieldData {
+ pub name: String,
+}
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub struct Field(salsa::InternId);
+
+impl salsa::InternKey for Field {
+ fn from_intern_id(id: salsa::InternId) -> Self {
+ Self(id)
+ }
+
+ fn as_intern_id(&self) -> salsa::InternId {
+ self.0
+ }
+}
diff --git a/vendor/rust-analyzer-salsa/examples/hello_world/main.rs b/vendor/rust-analyzer-salsa/examples/hello_world/main.rs new file mode 100644 index 000000000..154c2af0d --- /dev/null +++ b/vendor/rust-analyzer-salsa/examples/hello_world/main.rs @@ -0,0 +1,104 @@ +use std::sync::Arc;
+
+///////////////////////////////////////////////////////////////////////////
+// Step 1. Define the query group
+
+// A **query group** is a collection of queries (both inputs and
+// functions) that are defined in one particular spot. Each query
+// group is defined by a trait decorated with the
+// `#[salsa::query_group]` attribute. The trait defines one method per
+// query, with the arguments to the method being the query **keys** and
+// the return value being the query's **value**.
+//
+// Along with the trait, each query group has an associated
+// "storage struct". The name of this struct is specified in the `query_group`
+// attribute -- for a query group `Foo`, it is conventionally `FooStorage`.
+//
+// When we define the final database (see below), we will list out the
+// storage structs for each query group that it contains. The database
+// will then automatically implement the traits.
+//
+// Note that one query group can "include" another by listing the
+// trait for that query group as a supertrait.
+// ANCHOR:trait
+#[salsa::query_group(HelloWorldStorage)]
+trait HelloWorld {
+ // For each query, we give the name, some input keys (here, we
+ // have one key, `()`) and the output type `Arc<String>`. We can
+ // use attributes to give other configuration:
+ //
+ // - `salsa::input` indicates that this is an "input" to the system,
+ // which must be explicitly set. The `salsa::query_group` method
+ // will autogenerate a `set_input_string` method that can be
+ // used to set the input.
+ #[salsa::input]
+ fn input_string(&self, key: ()) -> Arc<String>;
+
+ // This is a *derived query*, meaning its value is specified by
+ // a function (see Step 2, below).
+ fn length(&self, key: ()) -> usize;
+}
+// ANCHOR_END:trait
+
+///////////////////////////////////////////////////////////////////////////
+// Step 2. Define the queries.
+
+// Define the **function** for the `length` query. This function will
+// be called whenever the query's value must be recomputed. After it
+// is called once, its result is typically memoized, unless we think
+// that one of the inputs may have changed. Its first argument (`db`)
+// is the "database". This is always a `&dyn` version of the query group
+// trait, so that you can invoke all the queries you know about.
+// We never know the concrete type here, as the full database may contain
+// methods from other query groups that we don't know about.
+fn length(db: &dyn HelloWorld, (): ()) -> usize {
+ // Read the input string:
+ let input_string = db.input_string(());
+
+ // Return its length:
+ input_string.len()
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Step 3. Define the database struct
+
+// Define the actual database struct. This struct needs to be annotated with
+// `#[salsa::database(..)]`. The list `..` will be the paths leading to the
+// storage structs for each query group that this database supports. This
+// attribute macro will generate the necessary impls so that the database
+// implements the corresponding traits as well (so, here, `DatabaseStruct` will
+// implement the `HelloWorld` trait).
+//
+// The database struct must have a field `storage: salsa::Storage<Self>`, but it
+// can have any number of additional fields beyond that. The
+// `#[salsa::database]` macro will generate glue code that accesses this
+// `storage` field (but other fields are ignored). The `Storage<Self>` type
+// contains all the actual hashtables and the like used to store query results
+// and dependency information.
+//
+// In addition to including the `storage` field, you must also implement the
+// `salsa::Database` trait (as shown below). This gives you a chance to define
+// the callback methods within if you want to (in this example, we don't).
+// ANCHOR:database
+#[salsa::database(HelloWorldStorage)]
+#[derive(Default)]
+struct DatabaseStruct {
+ storage: salsa::Storage<Self>,
+}
+
+impl salsa::Database for DatabaseStruct {}
+// ANCHOR_END:database
+
+// This shows how to use a query.
+fn main() {
+ let mut db = DatabaseStruct::default();
+
+ // You cannot access input_string yet, because it does not have a
+ // value. If you do, it will panic. You could create an Option
+ // interface by maintaining a HashSet of inserted keys.
+ // println!("Initially, the length is {}.", db.length(()));
+
+ db.set_input_string((), Arc::new("Hello, world".to_string()));
+
+ println!("Now, the length is {}.", db.length(()));
+}
diff --git a/vendor/rust-analyzer-salsa/examples/selection/main.rs b/vendor/rust-analyzer-salsa/examples/selection/main.rs new file mode 100644 index 000000000..2b31ede5b --- /dev/null +++ b/vendor/rust-analyzer-salsa/examples/selection/main.rs @@ -0,0 +1,36 @@ +/// Sources for the [selection pattern chapter][c] of the salsa book.
+///
+/// [c]: https://salsa-rs.github.io/salsa/common_patterns/selection.html
+
+// ANCHOR: request
+#[derive(Clone, Debug, PartialEq, Eq)]
+struct ParsedResult {
+ header: Vec<ParsedHeader>,
+ body: String,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+struct ParsedHeader {
+ key: String,
+ value: String,
+}
+
+#[salsa::query_group(Request)]
+trait RequestParser {
+ /// The base text of the request.
+ #[salsa::input]
+ fn request_text(&self) -> String;
+
+ /// The parsed form of the request.
+ fn parse(&self) -> ParsedResult;
+}
+// ANCHOR_END: request
+
+fn parse(_db: &dyn RequestParser) -> ParsedResult {
+ panic!()
+}
+
+mod util1;
+mod util2;
+
+fn main() {}
diff --git a/vendor/rust-analyzer-salsa/examples/selection/util1.rs b/vendor/rust-analyzer-salsa/examples/selection/util1.rs new file mode 100644 index 000000000..6b2ad91c7 --- /dev/null +++ b/vendor/rust-analyzer-salsa/examples/selection/util1.rs @@ -0,0 +1,16 @@ +use super::*;
+
+// ANCHOR: util1
+#[salsa::query_group(Request)]
+trait RequestUtil: RequestParser {
+ fn content_type(&self) -> Option<String>;
+}
+
+fn content_type(db: &dyn RequestUtil) -> Option<String> {
+ db.parse()
+ .header
+ .iter()
+ .find(|header| header.key == "content-type")
+ .map(|header| header.value.clone())
+}
+// ANCHOR_END: util1
diff --git a/vendor/rust-analyzer-salsa/examples/selection/util2.rs b/vendor/rust-analyzer-salsa/examples/selection/util2.rs new file mode 100644 index 000000000..b8f6e532f --- /dev/null +++ b/vendor/rust-analyzer-salsa/examples/selection/util2.rs @@ -0,0 +1,20 @@ +use super::*;
+
+// ANCHOR: util2
+#[salsa::query_group(Request)]
+trait RequestUtil: RequestParser {
+ fn header(&self) -> Vec<ParsedHeader>;
+ fn content_type(&self) -> Option<String>;
+}
+
+fn header(db: &dyn RequestUtil) -> Vec<ParsedHeader> {
+ db.parse().header
+}
+
+fn content_type(db: &dyn RequestUtil) -> Option<String> {
+ db.header()
+ .iter()
+ .find(|header| header.key == "content-type")
+ .map(|header| header.value.clone())
+}
+// ANCHOR_END: util2
|