// Copyright 2021 The Fuchsia Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file.

use { protocols::FidlProtocol, fidl::endpoints::DiscoverableProtocolMarker, proc_macro::TokenStream, quote::quote, std::collections::hash_map::Entry, protocols_dependencies::{DependencyGraph, Node, VerifyError}, };

#[proc_macro] pub fn generate_protocol_map(_item: TokenStream) -> TokenStream { let mut graph = DependencyGraph::default(); {% for dep in deps %} let {{ dep.lib }}_node = Node::new( // Protocol name. <<{{ dep.lib }}::ProtocolType as FidlProtocol>::Protocol as DiscoverableProtocolMarker>::PROTOCOL_NAME, // Build target. “{{ dep.target }}”.to_owned(),

  // Deps.
  {{ dep.lib }}::PROTOCOL_DEPS,
);
match graph.nodes.entry({{ dep.lib }}_node.protocol) {
    Entry::Occupied(e) => {
        panic!("Protocol endpoint for {} already registered with library at {}", {{ dep.lib }}_node.protocol, e.get().build_target);
    }
    Entry::Vacant(i) => {
      i.insert({{ dep.lib }}_node)
    }
};
{% endfor %}
if let Err(e) = graph.verify() {
  match e {
    VerifyError::CycleFound(path) => {
      let errors_string = path
        .into_iter()
        .map(|n| format!("\n\t{}, implemented in {}", n.protocol, n.build_target))
        .collect::<Vec<_>>()
        .join("");
      panic!("Dependency cycle detected between the following protocols: {}", errors_string);
    }
    VerifyError::InvalidDependencyError(m) => panic!("{}", m),
  }
}
let res = quote! {
    {
        use fidl::endpoints::DiscoverableProtocolMarker;
        use protocols::{FidlStreamHandler, FidlProtocol};
        use protocols::NameToStreamHandlerMap;
        let mut map = NameToStreamHandlerMap::new();
        {% for dep in deps %}
        map.insert(
            <<{{ dep.lib }}::ProtocolType as FidlProtocol>::Protocol as DiscoverableProtocolMarker>::PROTOCOL_NAME.to_owned(),
            Box::new(<{{dep.lib }}::ProtocolType as FidlProtocol>::StreamHandler::default()),
        );
        {% endfor %}
        map
    }
};

TokenStream::from(res)

}