1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
use std::collections::HashMap;

use super::{Generator, Resolver};
use crate::documentation::{Method, Property};
use pulldown_cmark::{CowStr, Event, Tag};

/// Callbacks to encode markdown input in a given format.
///
/// This trait should be implemented if you want to make your own backend.
pub trait Callbacks {
    /// File extension for the files generated by this callback.
    fn extension(&self) -> &'static str;
    /// Drive the generation process.
    ///
    /// This returns a map from file names (relative to the output directory) to
    /// their contents.
    ///
    /// You can find inspiration about how to implement this in the source code, for
    /// example in `src/backend/html.rs`.
    fn generate_files(&mut self, generator: Generator) -> HashMap<String, String>;
    /// Called before encoding each method.
    ///
    /// **Default**: does nothing
    fn start_method(&mut self, _s: &mut String, _resolver: &Resolver, _method: &Method) {}
    /// Called before encoding each property.
    ///
    /// **Default**: does nothing
    fn start_property(&mut self, _s: &mut String, _resolver: &Resolver, _property: &Property) {}
    /// Encode the stream of `events` in `s`.
    fn encode(&mut self, s: &mut String, events: Vec<Event<'_>>);
}

impl dyn Callbacks {
    /// Default start_method implementation, implemented on `dyn Callbacks` to avoid
    /// code duplication.
    ///
    /// This will create a level 3 header that looks like (in markdown):
    /// ```markdown
    /// ### <a id="func-name"></a>func name(arg1: [type](link), ...) -> [type](link)
    /// ________
    /// ```
    ///
    /// With appropriate linking.
    pub fn start_method_default(&mut self, s: &mut String, property: &Resolver, method: &Method) {
        let link = &format!("<a id=\"func-{}\"></a>", method.name);
        self.encode(
            s,
            vec![
                Event::Start(Tag::Heading(3)),
                Event::Html(CowStr::Borrowed(link)),
            ],
        );
        let mut method_header = String::from("func ");
        method_header.push_str(&method.name);
        method_header.push('(');
        for (index, (name, typ, _)) in method.parameters.iter().enumerate() {
            method_header.push_str(&name);
            method_header.push_str(": ");
            self.encode(s, vec![Event::Text(CowStr::Borrowed(&method_header))]);
            method_header.clear();
            self.encode(s, property.encode_type(typ));
            if index + 1 != method.parameters.len() {
                method_header.push_str(", ");
            }
        }
        method_header.push_str(") -> ");
        let mut last_events = vec![Event::Text(CowStr::Borrowed(&method_header))];
        last_events.extend(property.encode_type(&method.return_type));
        last_events.push(Event::End(Tag::Heading(3)));
        last_events.push(Event::Rule);
        self.encode(s, last_events);
    }

    /// Default start_property implementation, implemented on `dyn Callbacks` to avoid
    /// code duplication.
    ///
    /// This will create a level 3 header that looks like (in markdown):
    /// ```markdown
    /// ### <a id="property-name"></a> name: [type](link)
    /// ________
    /// ```
    ///
    /// With appropriate linking.
    pub fn start_property_default(
        &mut self,
        s: &mut String,
        resolver: &Resolver,
        property: &Property,
    ) {
        let link = &format!(
            "<a id=\"property-{}\"></a> {}: ",
            property.name, property.name
        );
        self.encode(
            s,
            vec![
                Event::Start(Tag::Heading(3)),
                Event::Html(CowStr::Borrowed(link)),
            ],
        );
        let mut last_events = resolver.encode_type(&property.typ);
        last_events.push(Event::End(Tag::Heading(3)));
        last_events.push(Event::Rule);
        self.encode(s, last_events);
    }
}

impl std::fmt::Debug for dyn Callbacks {
    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        formatter.write_str("Callbacks")
    }
}