Hello,
I'm new to rust and one of the first things I'm doing is extending the mdbook-latex
program. The current approach is to use pulldown_cmark
to directly transform md to latex code. Some problems arise like when a headline contains bold text. I thought it might be good to construct a (simple)syntax tree with children
and parent
pointers of each node. (Well in most other languages this would have been simple) however I struggled with rust which is why I'd like some opinions/styleguides/tipps etc.
The code here is only the Tree part to simplify things. The enum Value
would get a lot more entries.
I think the structure is quite self explanatory the root of the tree is an Ast
with possibly one Ast
in the parent field and 0..many Ast
in the children: Vec
.
There is a rather complex impl Debug
.
A trait with a function add_child
to add one child (thereby updating the parent and children)
The main contains basically what usually is in testcases.
- Does this code leak?
- Is it written as you would write something in rust?
- Are there better ways to write this(or in general a wrong idea)?
- anything else you'd want to mention?
I thank you for any hint or even effort to guide me along to be a better rust programmer!
use std::cell::RefCell;
use std::rc::Weak;
use std::rc::Rc;
#[derive(Debug)]
pub enum Value {
Text { content: String },
Number { zahl: u32 },
}
pub struct Ast {
node: Value,
parent: Option<Weak<RefCell<Ast>>>,
children: Vec<Rc<RefCell<Ast>>>,
}
impl std::fmt::Debug for Ast {
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
match &self.node {
Value::Text { content } => write!(formatter, "[{}, ", content)?,
Value::Number { zahl } => write!(formatter, "[{}, ", zahl)?,
};
if &self.children.len() > &0 {
let children: Vec<String> = self
.children
.iter()
.map(|s| format!("{:?}", s.borrow()))
.collect();
write!(formatter, "[{}]", children.join(", "))?;
} else {
write!(formatter, ".")?;
}
write!(formatter, "]")
}
}
pub trait AstModify {
fn add_child(self: Self, node: Value) -> Self;
}
impl AstModify for Rc<RefCell<Ast>> {
fn add_child(self: Self, node: Value) -> Self {
let mut nc = Ast {
node: node,
parent: None,
children: Vec::new(),
};
nc.parent = Some(Rc::downgrade(&Rc::clone(&self)));
let rc = Rc::new(RefCell::new(nc));
Rc::clone(&self).borrow_mut().children.push(Rc::clone(&rc));
Rc::clone(&rc)
}
}
fn main() {
let mast = Rc::new(RefCell::new(Ast {
node: Value::Number { zahl: 15 },
parent: None,
children: Vec::new(),
}));
println!("################\nrunning {:?}", mast.borrow());
mast.clone().add_child(Value::Number { zahl: 16 });
let c1 = mast.clone().add_child(Value::Number { zahl: 17 });
c1.clone().add_child( Value::Text {
content: "Test".to_string(),
},
);
Rc::clone(&c1).add_child(
Value::Text {
content: "Test".to_string(),
},
);
Rc::clone(&mast).add_child( Value::Text {
content: "Test".to_string(),
},
);
println!("################\nafteradd {:?}", mast.borrow());
}
Output:
################
running [15, .]
################
afteradd [15, [[16, .], [17, [[Test, .], [Test, .]]], [Test, .]]]
Errors:
Compiling playground v0.0.1 (/playground)
Finished release [optimized] target(s) in 5.04s
Running `target/release/playground`