aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar cel 🌸 <cel@blos.sm>2024-03-04 16:14:28 +0000
committerLibravatar cel 🌸 <cel@blos.sm>2024-03-04 16:14:28 +0000
commit844f3a5d11e4360e9d6bdb79cfed49287aa8b14d (patch)
tree5525c4f134ef3d7a6082935baa61e6097670c968 /src
downloadpeanuts-844f3a5d11e4360e9d6bdb79cfed49287aa8b14d.tar.gz
peanuts-844f3a5d11e4360e9d6bdb79cfed49287aa8b14d.tar.bz2
peanuts-844f3a5d11e4360e9d6bdb79cfed49287aa8b14d.zip
initial commit
Diffstat (limited to 'src')
-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
8 files changed, 161 insertions, 0 deletions
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!()
+ }
+}