aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--.gitignore1
-rw-r--r--Cargo.lock273
-rw-r--r--Cargo.toml11
-rw-r--r--README.md14
-rw-r--r--src/element.rs55
-rw-r--r--src/error.rs1
-rw-r--r--src/event.rs1
-rw-r--r--src/lexer.rs9
-rw-r--r--src/lib.rs15
-rw-r--r--src/parser.rs1
-rw-r--r--src/reader.rs32
-rw-r--r--src/writer.rs47
12 files changed, 460 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/target
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..431cbcc
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,273 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "addr2line"
+version = "0.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
+dependencies = [
+ "gimli",
+]
+
+[[package]]
+name = "adler"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
+name = "backtrace"
+version = "0.3.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
+dependencies = [
+ "addr2line",
+ "cc",
+ "cfg-if",
+ "libc",
+ "miniz_oxide",
+ "object",
+ "rustc-demangle",
+]
+
+[[package]]
+name = "cc"
+version = "1.0.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0ba8f7aaa012f30d5b2861462f6708eccd49c3c39863fe083a308035f63d723"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "futures"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
+
+[[package]]
+name = "futures-executor"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-io"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
+
+[[package]]
+name = "futures-macro"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
+
+[[package]]
+name = "futures-task"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
+
+[[package]]
+name = "futures-util"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-macro",
+ "futures-sink",
+ "futures-task",
+ "memchr",
+ "pin-project-lite",
+ "pin-utils",
+ "slab",
+]
+
+[[package]]
+name = "gimli"
+version = "0.28.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
+
+[[package]]
+name = "libc"
+version = "0.2.153"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
+
+[[package]]
+name = "memchr"
+version = "2.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
+
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
+dependencies = [
+ "adler",
+]
+
+[[package]]
+name = "nom"
+version = "7.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
+[[package]]
+name = "object"
+version = "0.32.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "peanuts"
+version = "0.1.0"
+dependencies = [
+ "futures",
+ "nom",
+ "tokio",
+]
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
+
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.78"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rustc-demangle"
+version = "0.1.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
+
+[[package]]
+name = "slab"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.52"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "tokio"
+version = "1.36.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931"
+dependencies = [
+ "backtrace",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..ca9d389
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "peanuts"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+futures = "0.3.30"
+nom = "7.1.3"
+tokio = "1.36.0"
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..b8a861f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,14 @@
+# peanuts
+
+an ergonomic async-first xml reader/writer library focusing on streams
+
+features:
+[ ] CoW
+[ ] namespace support
+[ ] serialization
+[ ] deserialization
+
+## reader:
+read -> lexer -> parser -> events -> elements -> deserialize
+## writer:
+serialize -> elements -> events -> write
diff --git a/src/element.rs b/src/element.rs
new file mode 100644
index 0000000..3273ba0
--- /dev/null
+++ b/src/element.rs
@@ -0,0 +1,55 @@
+// elements resemble a final tree, including inherited namespace information
+
+use std::collections::HashMap;
+
+// when are namespaces names chosen then if they are automatically calculated
+// namespaces are held by readers and writers.
+pub struct Namespace {
+ prefix: Option<String>,
+ namespace: String,
+}
+
+// names are qualified, they contain the namespace
+pub struct Name {
+ namespace: String,
+ name: String,
+}
+
+pub enum Node {
+ Element(Element),
+ Text(String),
+}
+
+// should this be a trait?
+pub struct Element {
+ name: Name,
+ // namespace: (Name, String), // can't have this, must be external method that is called within the context of a reader/writer
+ // each element once created contains the qualified namespace information for that element
+ // the name contains the qualified namespace so this is unnecessary
+ // namespace: String,
+ // hashmap of explicit namespace declarations on the element itself only
+ // possibly not needed as can be calculated at write time depending on context and qualified namespace, and for reading, element validity and namespaces are kept track of by the reader.
+ // namespaces: HashMap<Option<String>, String>,
+ // attributes can be in a different namespace than the element. how to make sure they are valid?
+ // maybe include the namespace instead of or with the prefix
+ // you can calculate the prefix from the namespaced name and the current writer context
+ // you can validate the prefix and calculate the namespace from the current reader context
+ // this results in readers and writers being able to return qualification errors as they aren't able to create elements until every part is qualified.
+ attributes: HashMap<Name, String>,
+ children: Option<Vec<Node>>,
+}
+
+// example of deriving an element:
+
+// #[derive(XMLWrite, XMLRead)]
+// #[peanuts(namespace = "jabber:client", namespace:stream = "http://etherx.jabber.org/streams", name = "stream:stream")]
+// pub struct Stream {
+// from: JID,
+// id: String,
+// to: JID,
+// version: String,
+// #[peanuts(namespace = "http://www.w3.org/XML/1998/namespace")]
+// lang: Lang,
+// }
+
+// note: if an element name has a prefix all unprefixed attributes are qualified by the namespace of the prefix, so in this example from's Name's namespace would be "http://etherx.jabber.org/streams"
diff --git a/src/error.rs b/src/error.rs
new file mode 100644
index 0000000..12fcaf2
--- /dev/null
+++ b/src/error.rs
@@ -0,0 +1 @@
+pub enum Error {}
diff --git a/src/event.rs b/src/event.rs
new file mode 100644
index 0000000..1eab55b
--- /dev/null
+++ b/src/event.rs
@@ -0,0 +1 @@
+// tags, declaration, comments, text. individual bits and what they contain, e.g. tag contains attributes and namespace declarations, lang, ONLY within the tag
diff --git a/src/lexer.rs b/src/lexer.rs
new file mode 100644
index 0000000..abb5ebd
--- /dev/null
+++ b/src/lexer.rs
@@ -0,0 +1,9 @@
+// lexer: tokenizes to bits like '<', '<?', '"', etc.
+
+pub enum Token {
+ Whitespace,
+ OpenTag,
+ CloseTag,
+ Slash,
+ Text(String),
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..5d1046f
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,15 @@
+mod element;
+mod error;
+mod reader;
+mod writer;
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn it_works() {
+ let result = 2 + 2;
+ assert_eq!(result, 4);
+ }
+}
diff --git a/src/parser.rs b/src/parser.rs
new file mode 100644
index 0000000..b2a8579
--- /dev/null
+++ b/src/parser.rs
@@ -0,0 +1 @@
+// parser: parses tokens from lexer into events
diff --git a/src/reader.rs b/src/reader.rs
new file mode 100644
index 0000000..05afc73
--- /dev/null
+++ b/src/reader.rs
@@ -0,0 +1,32 @@
+use futures::Stream;
+use tokio::io::AsyncRead;
+
+use crate::{
+ element::{Element, Name, Namespace},
+ error::Error,
+};
+
+/// streaming reader that tracks depth and available namespaces at current depth
+pub struct Reader<R> {
+ stream: R,
+ // holds which tags we are in atm over depth
+ depth: Vec<Name>,
+ namespaces: Vec<(usize, Namespace)>,
+}
+
+impl<R: AsyncRead> Reader<R> {
+ pub async fn read(&self) -> Result<impl From<Element>, Error> {}
+ pub async fn read_start(&self) -> Result<impl From<Element>, Error> {}
+ pub async fn read_end(&self) -> Result<(), Error> {}
+}
+
+impl<R: AsyncRead> Stream for Reader<R> {
+ type Item = impl From<Element>;
+
+ async fn poll_next(
+ self: std::pin::Pin<&mut Self>,
+ cx: &mut std::task::Context<'_>,
+ ) -> std::task::Poll<Option<Self::Item>> {
+ todo!()
+ }
+}
diff --git a/src/writer.rs b/src/writer.rs
new file mode 100644
index 0000000..d7fc037
--- /dev/null
+++ b/src/writer.rs
@@ -0,0 +1,47 @@
+use futures::{AsyncWrite, Sink};
+
+use crate::{
+ element::{Element, Name, Namespace},
+ error::Error,
+};
+
+pub struct Writer<W> {
+ stream: W,
+ depth: Vec<Name>,
+ namespaces: Vec<(usize, Namespace)>,
+}
+
+impl<W: AsyncWrite> Writer<W> {
+ pub async fn write(&self, element: impl Into<Element>) -> Result<(), Error> {}
+ pub async fn write_start(&self, element: impl Into<Element>) -> Result<(), Error> {}
+ pub async fn write_end(&self) -> Result<(), Error> {}
+}
+
+impl<W: AsyncWrite, E: Into<Element>> Sink<E> for Writer<W> {
+ type Error = Error;
+
+ fn poll_ready(
+ self: std::pin::Pin<&mut Self>,
+ cx: &mut std::task::Context<'_>,
+ ) -> std::task::Poll<Result<(), Self::Error>> {
+ todo!()
+ }
+
+ fn start_send(self: std::pin::Pin<&mut Self>, item: E) -> Result<(), Self::Error> {
+ todo!()
+ }
+
+ fn poll_flush(
+ self: std::pin::Pin<&mut Self>,
+ cx: &mut std::task::Context<'_>,
+ ) -> std::task::Poll<Result<(), Self::Error>> {
+ todo!()
+ }
+
+ fn poll_close(
+ self: std::pin::Pin<&mut Self>,
+ cx: &mut std::task::Context<'_>,
+ ) -> std::task::Poll<Result<(), Self::Error>> {
+ todo!()
+ }
+}