1#![allow(clippy::new_without_default)]
4#![allow(clippy::should_implement_trait)]
5
6use std::collections::hash_map::DefaultHasher;
7use std::fmt;
8use std::hash::Hash;
9
10use crate::node::{Attributes, Children, Node, Value};
11
12pub mod path;
13pub mod tag;
14
15#[derive(Clone, Debug)]
17pub struct Element {
18 name: String,
19 attributes: Attributes,
20 children: Children,
21}
22
23impl Element {
24 pub fn new<T>(name: T) -> Self
26 where
27 T: Into<String>,
28 {
29 Element {
30 name: name.into(),
31 attributes: Attributes::new(),
32 children: Children::new(),
33 }
34 }
35
36 #[inline]
38 pub fn get_name(&self) -> &str {
39 &self.name
40 }
41
42 #[inline]
44 pub fn get_attributes(&self) -> &Attributes {
45 &self.attributes
46 }
47
48 #[inline]
50 pub fn get_attributes_mut(&mut self) -> &mut Attributes {
51 &mut self.attributes
52 }
53
54 #[inline]
56 pub fn get_children(&self) -> &Children {
57 &self.children
58 }
59
60 #[inline]
62 pub fn get_children_mut(&mut self) -> &mut Children {
63 &mut self.children
64 }
65}
66
67impl fmt::Display for Element {
68 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
69 write!(formatter, "<{}", self.name)?;
70 let mut attributes = self.attributes.iter().collect::<Vec<_>>();
71 attributes.sort_by_key(|pair| pair.0.as_str());
72 for (name, value) in attributes {
73 write!(formatter, r#" {}="{}""#, name, escape(value))?;
74 }
75 if self.children.is_empty() {
76 return write!(formatter, "/>");
77 }
78 write!(formatter, ">")?;
79 let mut bare = false;
80 for child in self.children.iter() {
81 bare = child.is_bare() && !formatter.alternate();
82 if !bare {
83 writeln!(formatter)?;
84 }
85 write!(formatter, "{}", child)?;
86 }
87 if !bare {
88 writeln!(formatter)?;
89 }
90 write!(formatter, "</{}>", self.name)
91 }
92}
93
94impl Node for Element {
95 #[inline]
96 fn append<T>(&mut self, node: T)
97 where
98 T: Into<Box<dyn Node>>,
99 {
100 self.children.push(node.into());
101 }
102
103 #[inline]
104 fn assign<T, U>(&mut self, name: T, value: U)
105 where
106 T: Into<String>,
107 U: Into<Value>,
108 {
109 self.attributes.insert(name.into(), value.into());
110 }
111
112 #[inline]
113 fn get_name(&self) -> &str {
114 Self::get_name(self)
115 }
116
117 #[inline]
118 fn get_attributes(&self) -> Option<&Attributes> {
119 Self::get_attributes(self).into()
120 }
121
122 #[inline]
123 fn get_attributes_mut(&mut self) -> Option<&mut Attributes> {
124 Self::get_attributes_mut(self).into()
125 }
126
127 #[inline]
128 fn get_children(&self) -> Option<&Children> {
129 Self::get_children(self).into()
130 }
131
132 #[inline]
133 fn get_children_mut(&mut self) -> Option<&mut Children> {
134 Self::get_children_mut(self).into()
135 }
136}
137
138macro_rules! implement_nested(
139 ($struct_name:ident::$field_name:ident) => (
140 implement_nested!($struct_name::$field_name []);
141 );
142 ($struct_name:ident::$field_name:ident [$($indicator_name:ident),*]) => (
143 impl $struct_name {
144 pub fn add<T>(mut self, node: T) -> Self
146 where
147 T: Into<Box<dyn Node>>,
148 {
149 Node::append(&mut self, node);
150 self
151 }
152
153 #[inline]
155 pub fn set<T, U>(mut self, name: T, value: U) -> Self
156 where
157 T: Into<String>,
158 U: Into<Value>,
159 {
160 Node::assign(&mut self, name, value);
161 self
162 }
163 }
164
165 impl Node for $struct_name {
166 #[inline]
167 fn append<T>(&mut self, node: T)
168 where
169 T: Into<Box<dyn Node>>,
170 {
171 self.$field_name.append(node);
172 }
173
174 #[inline]
175 fn assign<T, U>(&mut self, name: T, value: U)
176 where
177 T: Into<String>,
178 U: Into<Value>,
179 {
180 self.$field_name.assign(name, value);
181 }
182
183 #[inline]
184 fn get_name(&self) -> &str {
185 self.$field_name.get_name()
186 }
187
188 #[inline]
189 fn get_attributes(&self) -> Option<&Attributes> {
190 self.$field_name.get_attributes().into()
191 }
192
193 #[inline]
194 fn get_attributes_mut(&mut self) -> Option<&mut Attributes> {
195 self.$field_name.get_attributes_mut().into()
196 }
197
198 #[inline]
199 fn get_children(&self) -> Option<&Children> {
200 self.$field_name.get_children().into()
201 }
202
203 #[inline]
204 fn get_children_mut(&mut self) -> Option<&mut Children> {
205 self.$field_name.get_children_mut().into()
206 }
207
208 $(
209 #[inline]
210 fn $indicator_name(&self) -> bool {
211 true
212 }
213 )*
214 }
215
216 impl std::ops::Deref for $struct_name {
217 type Target = Element;
218
219 #[inline]
220 fn deref(&self) -> &Self::Target {
221 &self.$field_name
222 }
223 }
224
225 impl std::ops::DerefMut for $struct_name {
226 #[inline]
227 fn deref_mut(&mut self) -> &mut Self::Target {
228 &mut self.$field_name
229 }
230 }
231
232 impl std::fmt::Display for $struct_name {
233 #[inline]
234 fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
235 if self.is_bareable() {
236 write!(formatter, "{:#}", self.$field_name)
237 } else {
238 self.$field_name.fmt(formatter)
239 }
240 }
241 }
242
243 impl From<$struct_name> for Element {
244 #[inline]
245 fn from(value: $struct_name) -> Self {
246 value.$field_name
247 }
248 }
249 );
250);
251
252macro_rules! implement {
253 ($(#[$doc:meta] struct $struct_name:ident)*) => ($(
254 #[$doc]
255 #[derive(Clone, Debug)]
256 pub struct $struct_name {
257 inner: Element,
258 }
259
260 impl $struct_name {
261 #[inline]
263 pub fn new() -> Self {
264 $struct_name {
265 inner: Element::new(tag::$struct_name),
266 }
267 }
268 }
269
270 impl Default for $struct_name {
271 fn default() -> Self {
272 Self::new()
273 }
274 }
275
276 impl super::NodeDefaultHash for $struct_name {
277 #[inline]
278 fn default_hash(&self, state: &mut DefaultHasher) {
279 self.inner.default_hash(state);
280 }
281 }
282
283 implement_nested! { $struct_name::inner }
284 )*);
285}
286
287impl super::NodeDefaultHash for Element {
288 fn default_hash(&self, state: &mut DefaultHasher) {
289 self.name.hash(state);
290 self.attributes.iter().for_each(|(key, value)| {
291 key.hash(state);
292 value.hash(state)
293 });
294 self.children
295 .iter()
296 .for_each(|child| child.default_hash(state));
297 }
298}
299
300implement! {
301 #[doc = "An [`a`](https://www.w3.org/TR/SVG/linking.html#AElement) element."]
302 struct Anchor
303
304 #[doc = "An [`animate`](https://www.w3.org/TR/SVG/animate.html#AnimateElement) element."]
305 struct Animate
306
307 #[doc = "An [`animateColor`](https://www.w3.org/TR/SVG/animate.html#AnimateColorElement) element."]
308 struct AnimateColor
309
310 #[doc = "An [`animateMotion`](https://www.w3.org/TR/SVG/animate.html#AnimateMotionElement) element."]
311 struct AnimateMotion
312
313 #[doc = "An [`animateTransform`](https://www.w3.org/TR/SVG/animate.html#AnimateTransformElement) element."]
314 struct AnimateTransform
315
316 #[doc = "A [`circle`](https://www.w3.org/TR/SVG/shapes.html#CircleElement) element."]
317 struct Circle
318
319 #[doc = "A [`clipPath`](https://www.w3.org/TR/SVG/masking.html#ClipPathElement) element."]
320 struct ClipPath
321
322 #[doc = "A [`defs`](https://www.w3.org/TR/SVG/struct.html#DefsElement) element."]
323 struct Definitions
324
325 #[doc = "A [`desc`](https://www.w3.org/TR/SVG/struct.html#DescElement) element."]
326 struct Description
327
328 #[doc = "An [`ellipse`](https://www.w3.org/TR/SVG/shapes.html#EllipseElement) element."]
329 struct Ellipse
330
331 #[doc = "A [`filter`](https://www.w3.org/TR/SVG/filters.html#FilterElement) element."]
332 struct Filter
333
334 #[doc = "A [`feBlend`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feBlend) element."]
335 struct FilterEffectBlend
336
337 #[doc = "A [`feColorMatrix`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feColorMatrix) element."]
338 struct FilterEffectColorMatrix
339
340 #[doc = "A [`feComponentTransfer`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feComponentTransfer) element."]
341 struct FilterEffectComponentTransfer
342
343 #[doc = "A [`feComposite`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feComposite) element."]
344 struct FilterEffectComposite
345
346 #[doc = "A [`feConvolveMatrix`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feConvolveMatrix) element."]
347 struct FilterEffectConvolveMatrix
348
349 #[doc = "A [`feDiffuseLighting`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feDiffuseLighting) element."]
350 struct FilterEffectDiffuseLighting
351
352 #[doc = "A [`feDisplacementMap`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feDisplacementMap) element."]
353 struct FilterEffectDisplacementMap
354
355 #[doc = "A [`feDistantLight`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feDistantLight) element."]
356 struct FilterEffectDistantLight
357
358 #[doc = "A [`feDropShadow`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feDropShadow) element."]
359 struct FilterEffectDropShadow
360
361 #[doc = "A [`feFlood`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feFlood) element."]
362 struct FilterEffectFlood
363
364 #[doc = "A [`feFuncA`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feFuncA) element."]
365 struct FilterEffectFunctionA
366
367 #[doc = "A [`feFuncB`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feFuncB) element."]
368 struct FilterEffectFunctionB
369
370 #[doc = "A [`feFuncG`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feFuncG) element."]
371 struct FilterEffectFunctionG
372
373 #[doc = "A [`feFuncR`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feFuncR) element."]
374 struct FilterEffectFunctionR
375
376 #[doc = "A [`feGaussianBlur`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feGaussianBlur) element."]
377 struct FilterEffectGaussianBlur
378
379 #[doc = "A [`feImage`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feImage) element."]
380 struct FilterEffectImage
381
382 #[doc = "A [`feMerge`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feMerge) element."]
383 struct FilterEffectMerge
384
385 #[doc = "A [`feMergeNode`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feMergeNode) element."]
386 struct FilterEffectMergeNode
387
388 #[doc = "A [`feMorphology`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feMorphology) element."]
389 struct FilterEffectMorphology
390
391 #[doc = "A [`feOffset`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feOffset) element."]
392 struct FilterEffectOffset
393
394 #[doc = "A [`fePointLight`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/fePointLight) element."]
395 struct FilterEffectPointLight
396
397 #[doc = "A [`feSpecularLighting`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feSpecularLighting) element."]
398 struct FilterEffectSpecularLighting
399
400 #[doc = "A [`feSpotLight`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feSpotLight) element."]
401 struct FilterEffectSpotLight
402
403 #[doc = "A [`feTile`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feTile) element."]
404 struct FilterEffectTile
405
406 #[doc = "A [`feTurbulence`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feTurbulence) element."]
407 struct FilterEffectTurbulence
408
409 #[doc = "A [`foreignObject`](https://www.w3.org/TR/SVG/embedded.html#ForeignObjectElement) element."]
410 struct ForeignObject
411
412 #[doc = "A [`g`](https://www.w3.org/TR/SVG/struct.html#GElement) element."]
413 struct Group
414
415 #[doc = "An [`image`](https://www.w3.org/TR/SVG/struct.html#ImageElement) element."]
416 struct Image
417
418 #[doc = "A [`line`](https://www.w3.org/TR/SVG/shapes.html#LineElement) element."]
419 struct Line
420
421 #[doc = "A [`linearGradient`](https://www.w3.org/TR/SVG/pservers.html#LinearGradientElement) element."]
422 struct LinearGradient
423
424 #[doc = "A [`link`](https://www.w3.org/TR/SVG/styling.html#LinkElement) element."]
425 struct Link
426
427 #[doc = "A [`marker`](https://www.w3.org/TR/SVG/painting.html#MarkerElement) element."]
428 struct Marker
429
430 #[doc = "A [`mask`](https://www.w3.org/TR/SVG/masking.html#MaskElement) element."]
431 struct Mask
432
433 #[doc = "An [`mpath`](https://www.w3.org/TR/SVG/animate.html#MPathElement) element."]
434 struct MotionPath
435
436 #[doc = "A [`path`](https://www.w3.org/TR/SVG/paths.html#PathElement) element."]
437 struct Path
438
439 #[doc = "A [`pattern`](https://www.w3.org/TR/SVG/pservers.html#PatternElement) element."]
440 struct Pattern
441
442 #[doc = "A [`polygon`](https://www.w3.org/TR/SVG/shapes.html#PolygonElement) element."]
443 struct Polygon
444
445 #[doc = "A [`polyline`](https://www.w3.org/TR/SVG/shapes.html#PolylineElement) element."]
446 struct Polyline
447
448 #[doc = "A [`radialGradient`](https://www.w3.org/TR/SVG/pservers.html#RadialGradientElement) element."]
449 struct RadialGradient
450
451 #[doc = "A [`rect`](https://www.w3.org/TR/SVG/shapes.html#RectElement) element."]
452 struct Rectangle
453
454 #[doc = "A [`stop`](https://www.w3.org/TR/SVG/pservers.html#StopElement) element."]
455 struct Stop
456
457 #[doc = "A [`symbol`](https://www.w3.org/TR/SVG/struct.html#SymbolElement) element."]
458 struct Symbol
459
460 #[doc = "A [`use`](https://www.w3.org/TR/SVG/struct.html#UseElement) element."]
461 struct Use
462}
463
464macro_rules! implement {
465 (@itemize $i:item) => ($i);
466 ($(
467 #[$doc:meta]
468 struct $struct_name:ident
469 [$($indicator_name:ident),*]
470 [$($trait_name:ident: $($trait_type:tt)*),*]
471 [$inner:ident $(,$argument_name:ident: $argument_type:ty)*] $body:block
472 )*) => ($(
473 #[$doc]
474 #[derive(Clone, Debug)]
475 pub struct $struct_name {
476 inner: Element,
477 }
478
479 implement! { @itemize
480 impl $struct_name {
481 #[inline]
483 pub fn new<$($trait_name: $($trait_type)*),*>($($argument_name: $argument_type),*) -> Self {
484 #[inline(always)]
485 fn initialize<$($trait_name: $($trait_type)*),*>(
486 $inner: &mut Element $(, $argument_name: $argument_type)*
487 ) $body
488 let mut inner = Element::new(tag::$struct_name);
489 initialize(&mut inner $(, $argument_name)*);
490 $struct_name {
491 inner,
492 }
493 }
494 }
495 }
496
497 impl super::NodeDefaultHash for $struct_name {
498 fn default_hash(&self, state: &mut DefaultHasher) {
499 self.inner.default_hash(state);
500 }
501 }
502
503 implement_nested! { $struct_name::inner [$($indicator_name),*] }
504 )*);
505}
506
507implement! {
508 #[doc = "An [`svg`](https://www.w3.org/TR/SVG/struct.html#SVGElement) element."]
509 struct SVG [is_bareable] [] [inner] {
510 inner.assign("xmlns", "http://www.w3.org/2000/svg");
511 }
512
513 #[doc = "A [`script`](https://www.w3.org/TR/SVG/script.html#ScriptElement) element."]
514 struct Script [is_bareable] [T: Into<String>] [inner, content: T] {
515 inner.append(crate::node::Text::new(content));
516 }
517
518 #[doc = "A [`style`](https://www.w3.org/TR/SVG/styling.html#StyleElement) element."]
519 struct Style [is_bareable] [T: Into<String>] [inner, content: T] {
520 inner.append(crate::node::Text::new(content));
521 }
522
523 #[doc = "A [`text`](https://www.w3.org/TR/SVG/text.html#TextElement) element."]
524 struct Text [is_bareable] [T: Into<String>] [inner, content: T] {
525 inner.append(crate::node::Text::new(content));
526 }
527
528 #[doc = "A [`textPath`](https://www.w3.org/TR/SVG/text.html#TextPathElement) element."]
529 struct TextPath [] [T: Into<String>] [inner, content: T] {
530 inner.append(crate::node::Text::new(content));
531 }
532
533 #[doc = "A [`title`](https://www.w3.org/TR/SVG/struct.html#TitleElement) element."]
534 struct Title [] [T: Into<String>] [inner, content: T] {
535 inner.append(crate::node::Text::new(content));
536 }
537
538 #[doc = "A [`tspan`](https://www.w3.org/TR/SVG/text.html#TextElement) element."]
539 struct TSpan [] [T: Into<String>] [inner, content: T] {
540 inner.append(crate::node::Text::new(content));
541 }
542}
543
544fn escape(value: &str) -> String {
545 crate::node::text::escape(value)
546 .replace('"', """)
547 .replace('\'', "'")
548}
549
550#[cfg(test)]
551mod tests {
552 use super::{Element, Rectangle, Style, Title};
553 use crate::node::element;
554
555 #[test]
556 fn element_children() {
557 let mut one = element::Group::new()
558 .add(element::Text::new("foo"))
559 .add(element::Text::new("bar"))
560 .add(element::Text::new("buz"));
561 let two = element::Group::new()
562 .add(one.get_children()[0].clone())
563 .add(one.get_children_mut().pop().unwrap());
564
565 assert_eq!(
566 one.to_string(),
567 "<g>\n<text>\nfoo\n</text>\n<text>\nbar\n</text>\n</g>",
568 );
569 assert_eq!(
570 two.to_string(),
571 "<g>\n<text>\nfoo\n</text>\n<text>\nbuz\n</text>\n</g>",
572 );
573 }
574
575 #[test]
576 fn element_display() {
577 use crate::node::Node;
578
579 let mut element = Element::new("foo");
580 element.assign("x", -10);
581 element.assign("y", "10px");
582 element.assign("s", (12.5, 13.0));
583 element.assign("c", "green");
584 element.append(Element::new("bar"));
585
586 assert_eq!(
587 element.to_string().lines().collect::<Vec<_>>(),
588 &[
589 r#"<foo c="green" s="12.5 13" x="-10" y="10px">"#,
590 "<bar/>",
591 "</foo>",
592 ],
593 );
594 }
595
596 #[test]
597 fn element_display_angles() {
598 let element = Rectangle::new()
599 .set("fill", "#FF780088")
600 .set("height", 10)
601 .set("width", 0.3088995)
602 .set("x", 328.0725)
603 .set("y", 120)
604 .add(Title::new("widgets >=3.0.9, <3.1.dev0"));
605
606 assert_eq!(
607 element.to_string().lines().collect::<Vec<_>>(),
608 &[
609 r###"<rect fill="#FF780088" height="10" width="0.3088995" x="328.0725" y="120">"###,
610 "<title>widgets >=3.0.9, <3.1.dev0</title>",
611 "</rect>",
612 ],
613 );
614 }
615
616 #[test]
617 fn element_display_quotes() {
618 use crate::node::Node;
619
620 let mut element = Element::new("foo");
621 element.assign("s", "'single'");
622 element.assign("d", r#""double""#);
623 element.assign("m", r#""mixed'"#);
624
625 assert_eq!(
626 element.to_string(),
627 r#"<foo d=""double"" m=""mixed'" s="'single'"/>"#,
628 );
629 }
630
631 #[test]
632 fn style_display() {
633 let element = Style::new("* { font-family: foo; }");
634
635 assert_eq!(
636 element.to_string().lines().collect::<Vec<_>>(),
637 &["<style>", "* { font-family: foo; }", "</style>"],
638 );
639 }
640}