Skip to content

Instantly share code, notes, and snippets.

@kroltan
Created September 7, 2021 16:44
Show Gist options
  • Save kroltan/d756450e7d0aa79e947be71b86587f16 to your computer and use it in GitHub Desktop.
Save kroltan/d756450e7d0aa79e947be71b86587f16 to your computer and use it in GitHub Desktop.
World's second-worst Rust XML writing library
use std::{
borrow::BorrowMut,
io::{Error, ErrorKind, Write},
};
#[derive(Debug)]
enum State {
Open,
Attribute,
Children,
}
pub struct Xml<W: Write> {
writer: W
}
impl<W: Write> Xml<W> {
pub fn new(writer: W) -> Self {
Self { writer }
}
pub fn open(self, tag: &str) -> XmlElement<W> {
XmlElement {
tag,
writer: self.writer,
state: State::Open,
}
}
pub fn end(self) -> W {
self.writer
}
}
#[derive(Debug)]
#[must_use = "You must call `.close()` to finish writing the element"]
pub struct XmlElement<'a, W: Write> {
tag: &'a str,
writer: W,
state: State,
}
impl<'a, W: Write> XmlElement<'a, W> {
pub fn sibling<'b>(self, tag: &'b str) -> Result<XmlElement<'b, W>, Error> {
let writer = self.close()?.end();
Ok(Xml::new(writer).open(tag))
}
pub fn attribute(mut self, attribute: &str, value: &str) -> Result<Self, Error> {
match self.state {
State::Open => {
write!(self.writer.borrow_mut(), "<{}", self.tag)?;
self.state = State::Attribute
}
State::Attribute => {}
State::Children => {
return Err(Error::new(
ErrorKind::Other,
"Attempted to write attribute after children",
))
}
}
write!(self.writer.borrow_mut(), " {}=\"{}\"", attribute, value)?;
Ok(self)
}
pub fn children(mut self, builder: fn(Xml<W>) -> Result<W, Error>) -> Result<Self, Error> {
match self.state {
State::Open => {
write!(self.writer.borrow_mut(), "<{}>", self.tag)?;
self.state = State::Children
}
State::Attribute => {
write!(self.writer.borrow_mut(), ">")?;
self.state = State::Children
}
State::Children => {}
}
let writer = builder(Xml::new(self.writer))?;
Ok(Self { writer, ..self })
}
pub fn close(mut self) -> Result<Xml<W>, Error> {
let writer = self.writer.borrow_mut();
match self.state {
State::Open => write!(writer, "<{}/>", self.tag)?,
State::Attribute => write!(writer, "/>")?,
State::Children => write!(writer, "</{}>", self.tag)?,
}
Ok(Xml::new(self.writer))
}
}
#[cfg(test)]
mod tests {
use crate::*;
#[test]
fn it_works() -> Result<(), std::io::Error> {
let writer = Xml::new(Vec::new())
.open("foo")
.attribute("bar", "12")?
.children(|xml| Ok(xml.open("kek").sibling("kek")?.close()?.end()))?
.close()?
.end();
assert_eq!(&writer, "<foo bar=\"12\"><kek/><kek/></foo>".as_bytes());
Ok(())
}
}
@kroltan
Copy link
Author

kroltan commented Sep 7, 2021

The #1 worst one had the audacity to publish itself on crates.io.

License

DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004

Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.

DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  1. You just DO WHAT THE FUCK YOU WANT TO.

@kroltan
Copy link
Author

kroltan commented Sep 7, 2021

Also if you get hacked or your server catches fire because you were mad enough to use this with actual real world data it's not my problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment