mod used_directives;
pub(super) use self::used_directives::UsedDirectives;
use super::field_types_map::FieldTypesMap;
use crate::{composition_ir as ir, federated_graph as federated, subgraphs};
use std::collections::HashMap;
pub(super) struct Context<'a> {
pub(super) out: &'a mut federated::FederatedGraph,
pub(super) subgraphs: &'a subgraphs::Subgraphs,
pub(super) field_types_map: FieldTypesMap,
pub(super) selection_map: HashMap<(federated::Definition, subgraphs::StringId), federated::FieldId>,
pub(super) definitions: HashMap<federated::StringId, federated::Definition>,
pub(super) composed_directive_linked_schemas: Vec<(subgraphs::LinkedSchemaId, federated::StringId)>,
pub(super) used_directives: UsedDirectives,
used_extensions: fixedbitset::FixedBitSet,
strings_ir: ir::StringsIr,
}
impl<'a> Context<'a> {
pub(crate) fn new(
ir: &mut ir::CompositionIr,
subgraphs: &'a subgraphs::Subgraphs,
out: &'a mut federated::FederatedGraph,
) -> Self {
Context {
out,
subgraphs,
definitions: std::mem::take(&mut ir.definitions_by_name),
strings_ir: std::mem::take(&mut ir.strings),
selection_map: HashMap::with_capacity(ir.fields.len()),
field_types_map: FieldTypesMap::default(),
used_extensions: ir.used_extensions.clone(),
used_directives: UsedDirectives::empty(),
composed_directive_linked_schemas: Vec::new(),
}
}
pub(crate) fn convert_extension_id(&self, extension_id: subgraphs::ExtensionId) -> federated::ExtensionId {
assert!(
self.used_extensions[usize::from(extension_id)],
"Unused extensions used in FederatedGraph?"
);
let offset = self.used_extensions.count_zeroes(..usize::from(extension_id));
federated::ExtensionId::from(usize::from(extension_id) - offset)
}
pub(crate) fn insert_string(&mut self, string_id: subgraphs::StringId) -> federated::StringId {
self.strings_ir.insert(&self.subgraphs[string_id])
}
pub(crate) fn insert_str(&mut self, string: &str) -> federated::StringId {
self.strings_ir.insert(string)
}
pub(crate) fn lookup_str(&self, string: &str) -> Option<federated::StringId> {
self.strings_ir.lookup(string)
}
pub(crate) fn lookup_string_id(&self, string: federated::StringId) -> &str {
&self.strings_ir[string]
}
pub(crate) fn insert_value(&mut self, value: &subgraphs::Value) -> federated::Value {
self.insert_value_with_type(value, None)
}
pub(crate) fn insert_value_with_type(
&mut self,
value: &subgraphs::Value,
enum_type: Option<federated::EnumDefinitionId>,
) -> federated::Value {
match value {
subgraphs::Value::Null => federated::Value::Null,
subgraphs::Value::String(value) => federated::Value::String(self.insert_string(*value)),
subgraphs::Value::Int(value) => federated::Value::Int(*value),
subgraphs::Value::Float(value) => federated::Value::Float(*value),
subgraphs::Value::Boolean(value) => federated::Value::Boolean(*value),
subgraphs::Value::Enum(value) => {
let value_name = self.insert_string(*value);
let enum_value = enum_type.and_then(|enum_id| self.out.find_enum_value_by_name_id(enum_id, value_name));
if let Some(enum_value) = enum_value {
federated::Value::EnumValue(enum_value.id())
} else {
federated::Value::UnboundEnumValue(value_name)
}
}
subgraphs::Value::Object(value) => federated::Value::Object(
value
.iter()
.map(|(k, v)| (self.insert_string(*k), self.insert_value_with_type(v, enum_type)))
.collect(),
),
subgraphs::Value::List(value) => federated::Value::List(
value
.iter()
.map(|v| self.insert_value_with_type(v, enum_type))
.collect(),
),
}
}
}
impl std::ops::Index<federated::StringId> for Context<'_> {
type Output = str;
fn index(&self, index: federated::StringId) -> &Self::Output {
&self.strings_ir[index]
}
}
impl std::ops::Index<subgraphs::StringId> for Context<'_> {
type Output = str;
fn index(&self, index: subgraphs::StringId) -> &Self::Output {
&self.subgraphs[index]
}
}
impl Drop for Context<'_> {
fn drop(&mut self) {
self.out.strings = std::mem::take(&mut self.strings_ir).into_federated_strings();
}
}