<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use super::constant_directive::ConstantDirective;
use super::constant_value::ConstantValue;
use super::primitive::*;
use super::type_annotation::TypeAnnotation;
use common::Span;
use std::fmt;

/// A document only consisting of executable definitions (fragments and operations).
/// This excludes schema definitions and schema extensions.
#[derive(Debug)]
pub struct SchemaDocument {
    pub span: Span,
    pub definitions: Vec<TypeSystemDefinition>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub enum TypeSystemDefinition {
    SchemaDefinition(SchemaDefinition),
    SchemaExtension(SchemaExtension),
    EnumTypeDefinition(EnumTypeDefinition),
    EnumTypeExtension(EnumTypeExtension),
    InterfaceTypeDefinition(InterfaceTypeDefinition),
    InterfaceTypeExtension(InterfaceTypeExtension),
    ObjectTypeDefinition(ObjectTypeDefinition),
    ObjectTypeExtension(ObjectTypeExtension),
    UnionTypeDefinition(UnionTypeDefinition),
    UnionTypeExtension(UnionTypeExtension),
    InputObjectTypeDefinition(InputObjectTypeDefinition),
    InputObjectTypeExtension(InputObjectTypeExtension),
    ScalarTypeDefinition(ScalarTypeDefinition),
    ScalarTypeExtension(ScalarTypeExtension),
    DirectiveDefinition(DirectiveDefinition),
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct SchemaDefinition {
    pub directives: Vec<ConstantDirective>,
    pub operation_types: List<OperationTypeDefinition>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct SchemaExtension {
    pub directives: Vec<ConstantDirective>,
    pub operation_types: Option<List<OperationTypeDefinition>>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct OperationTypeDefinition {
    pub operation: OperationType,
    pub type_: Identifier,
}

#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Copy, Clone)]
pub enum OperationType {
    Query,
    Mutation,
    Subscription,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct ObjectTypeDefinition {
    pub name: Identifier,
    pub interfaces: Vec<Identifier>,
    pub directives: Vec<ConstantDirective>,
    pub fields: Option<List<FieldDefinition>>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct ObjectTypeExtension {
    pub name: Identifier,
    pub interfaces: Vec<Identifier>,
    pub directives: Vec<ConstantDirective>,
    pub fields: Option<List<FieldDefinition>>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct InterfaceTypeDefinition {
    pub name: Identifier,
    pub interfaces: Vec<Identifier>,
    pub directives: Vec<ConstantDirective>,
    pub fields: Option<List<FieldDefinition>>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct InterfaceTypeExtension {
    pub name: Identifier,
    pub interfaces: Vec<Identifier>,
    pub directives: Vec<ConstantDirective>,
    pub fields: Option<List<FieldDefinition>>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct UnionTypeDefinition {
    pub name: Identifier,
    pub directives: Vec<ConstantDirective>,
    pub members: Vec<Identifier>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct UnionTypeExtension {
    pub name: Identifier,
    pub directives: Vec<ConstantDirective>,
    pub members: Vec<Identifier>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct ScalarTypeDefinition {
    pub name: Identifier,
    pub directives: Vec<ConstantDirective>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct ScalarTypeExtension {
    pub name: Identifier,
    pub directives: Vec<ConstantDirective>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct EnumTypeDefinition {
    pub name: Identifier,
    pub directives: Vec<ConstantDirective>,
    pub values: Option<List<EnumValueDefinition>>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct EnumTypeExtension {
    pub name: Identifier,
    pub directives: Vec<ConstantDirective>,
    pub values: Option<List<EnumValueDefinition>>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct InputObjectTypeDefinition {
    pub name: Identifier,
    pub directives: Vec<ConstantDirective>,
    pub fields: Option<List<InputValueDefinition>>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct InputObjectTypeExtension {
    pub name: Identifier,
    pub directives: Vec<ConstantDirective>,
    pub fields: Option<List<InputValueDefinition>>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct EnumValueDefinition {
    pub name: Identifier,
    pub directives: Vec<ConstantDirective>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct DirectiveDefinition {
    pub name: Identifier,
    pub arguments: Option<List<InputValueDefinition>>,
    pub repeatable: bool,
    pub locations: Vec<DirectiveLocation>,
}

#[derive(PartialEq, Eq, Ord, PartialOrd, Hash, Debug, Clone, Copy)]
pub enum DirectiveLocation {
    Query,
    Mutation,
    Subscription,
    Field,
    FragmentDefinition,
    FragmentSpread,
    InlineFragment,
    Schema,
    Scalar,
    Object,
    FieldDefinition,
    ArgumentDefinition,
    Interface,
    Union,
    Enum,
    EnumValue,
    InputObject,
    InputFieldDefinition,
    VariableDefinition,
}

impl fmt::Display for DirectiveLocation {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            DirectiveLocation::Query => write!(f, "QUERY"),
            DirectiveLocation::Mutation => write!(f, "MUTATION"),
            DirectiveLocation::Subscription => write!(f, "SUBSCRIPTION"),
            DirectiveLocation::Field => write!(f, "FIELD"),
            DirectiveLocation::FragmentDefinition => write!(f, "FRAGMENT_DEFINITION"),
            DirectiveLocation::FragmentSpread => write!(f, "FRAGMENT_SPREAD"),
            DirectiveLocation::InlineFragment => write!(f, "INLINE_FRAGMENT"),
            DirectiveLocation::Schema => write!(f, "SCHEMA"),
            DirectiveLocation::Scalar => write!(f, "SCALAR"),
            DirectiveLocation::Object => write!(f, "OBJECT"),
            DirectiveLocation::FieldDefinition => write!(f, "FIELD_DEFINITION"),
            DirectiveLocation::ArgumentDefinition => write!(f, "ARGUMENT_DEFINITION"),
            DirectiveLocation::Interface => write!(f, "INTERFACE"),
            DirectiveLocation::Union => write!(f, "UNION"),
            DirectiveLocation::Enum => write!(f, "ENUM"),
            DirectiveLocation::EnumValue => write!(f, "ENUM_VALUE"),
            DirectiveLocation::InputObject => write!(f, "INPUT_OBJECT"),
            DirectiveLocation::InputFieldDefinition => write!(f, "INPUT_FIELD_DEFINITION"),
            DirectiveLocation::VariableDefinition => write!(f, "VARIABLE_DEFINITION"),
        }
    }
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct InputValueDefinition {
    pub name: Identifier,
    pub type_: TypeAnnotation,
    pub default_value: Option<ConstantValue>,
    pub directives: Vec<ConstantDirective>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct FieldDefinition {
    pub name: Identifier,
    pub type_: TypeAnnotation,
    pub arguments: Option<List<InputValueDefinition>>,
    pub directives: Vec<ConstantDirective>,
}
<commit_msg>fmt::Display implementations for `graphql-syntax` type system nodes<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use super::constant_directive::ConstantDirective;
use super::constant_value::ConstantValue;
use super::primitive::*;
use super::type_annotation::TypeAnnotation;
use common::Span;
use interner::StringKey;
use std::fmt;

/// A document only consisting of executable definitions (fragments and operations).
/// This excludes schema definitions and schema extensions.
#[derive(Debug)]
pub struct SchemaDocument {
    pub span: Span,
    pub definitions: Vec<TypeSystemDefinition>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub enum TypeSystemDefinition {
    SchemaDefinition(SchemaDefinition),
    SchemaExtension(SchemaExtension),
    EnumTypeDefinition(EnumTypeDefinition),
    EnumTypeExtension(EnumTypeExtension),
    InterfaceTypeDefinition(InterfaceTypeDefinition),
    InterfaceTypeExtension(InterfaceTypeExtension),
    ObjectTypeDefinition(ObjectTypeDefinition),
    ObjectTypeExtension(ObjectTypeExtension),
    UnionTypeDefinition(UnionTypeDefinition),
    UnionTypeExtension(UnionTypeExtension),
    InputObjectTypeDefinition(InputObjectTypeDefinition),
    InputObjectTypeExtension(InputObjectTypeExtension),
    ScalarTypeDefinition(ScalarTypeDefinition),
    ScalarTypeExtension(ScalarTypeExtension),
    DirectiveDefinition(DirectiveDefinition),
}

impl fmt::Display for TypeSystemDefinition {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            TypeSystemDefinition::SchemaDefinition(SchemaDefinition {
                directives,
                operation_types,
            }) => write_schema_definition_helper(f, directives, &operation_types.items),
            TypeSystemDefinition::ObjectTypeExtension(ObjectTypeExtension {
                name,
                interfaces,
                fields,
                directives,
            }) => write_object_helper(f, &name.value, &interfaces, &fields, directives, true),
            TypeSystemDefinition::ObjectTypeDefinition(ObjectTypeDefinition {
                name,
                interfaces,
                fields,
                directives,
            }) => write_object_helper(f, &name.value, interfaces, &fields, directives, false),
            TypeSystemDefinition::InterfaceTypeDefinition(InterfaceTypeDefinition {
                name,
                fields,
                directives,
                ..
            }) => write_interface_helper(f, &name.value, &fields, directives, false),
            TypeSystemDefinition::InterfaceTypeExtension(InterfaceTypeExtension {
                name,
                interfaces: _,
                fields,
                directives,
            }) => write_interface_helper(f, &name.value, &fields, directives, true),
            TypeSystemDefinition::UnionTypeDefinition(UnionTypeDefinition {
                name,
                directives,
                members,
            }) => write_union_type_definition_helper(f, &name.value, &directives, members),
            TypeSystemDefinition::DirectiveDefinition(DirectiveDefinition {
                name,
                arguments,
                repeatable,
                locations,
            }) => {
                write_directive_definition_helper(f, &name.value, &arguments, repeatable, locations)
            }
            TypeSystemDefinition::InputObjectTypeDefinition(InputObjectTypeDefinition {
                name,
                directives,
                fields,
            }) => write_input_object_type_definition_helper(f, &name.value, directives, &fields),
            TypeSystemDefinition::EnumTypeDefinition(EnumTypeDefinition {
                name,
                directives,
                values,
            }) => write_enum_type_definition_helper(f, &name.value, directives, &values),
            TypeSystemDefinition::ScalarTypeDefinition(ScalarTypeDefinition {
                name,
                directives,
            }) => write_scalar_type_definition_helper(f, &name.value, directives),
            _ => panic!("Type is not implemented"),
        }
    }
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct SchemaDefinition {
    pub directives: Vec<ConstantDirective>,
    pub operation_types: List<OperationTypeDefinition>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct SchemaExtension {
    pub directives: Vec<ConstantDirective>,
    pub operation_types: Option<List<OperationTypeDefinition>>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct OperationTypeDefinition {
    pub operation: OperationType,
    pub type_: Identifier,
}

impl fmt::Display for OperationTypeDefinition {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}: {}", self.operation, self.type_)
    }
}

#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Copy, Clone)]
pub enum OperationType {
    Query,
    Mutation,
    Subscription,
}

impl fmt::Display for OperationType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            OperationType::Query => write!(f, "query"),
            OperationType::Mutation => write!(f, "mutation"),
            OperationType::Subscription => write!(f, "subscription"),
        }
    }
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct ObjectTypeDefinition {
    pub name: Identifier,
    pub interfaces: Vec<Identifier>,
    pub directives: Vec<ConstantDirective>,
    pub fields: Option<List<FieldDefinition>>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct ObjectTypeExtension {
    pub name: Identifier,
    pub interfaces: Vec<Identifier>,
    pub directives: Vec<ConstantDirective>,
    pub fields: Option<List<FieldDefinition>>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct InterfaceTypeDefinition {
    pub name: Identifier,
    pub interfaces: Vec<Identifier>,
    pub directives: Vec<ConstantDirective>,
    pub fields: Option<List<FieldDefinition>>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct InterfaceTypeExtension {
    pub name: Identifier,
    pub interfaces: Vec<Identifier>,
    pub directives: Vec<ConstantDirective>,
    pub fields: Option<List<FieldDefinition>>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct UnionTypeDefinition {
    pub name: Identifier,
    pub directives: Vec<ConstantDirective>,
    pub members: Vec<Identifier>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct UnionTypeExtension {
    pub name: Identifier,
    pub directives: Vec<ConstantDirective>,
    pub members: Vec<Identifier>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct ScalarTypeDefinition {
    pub name: Identifier,
    pub directives: Vec<ConstantDirective>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct ScalarTypeExtension {
    pub name: Identifier,
    pub directives: Vec<ConstantDirective>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct EnumTypeDefinition {
    pub name: Identifier,
    pub directives: Vec<ConstantDirective>,
    pub values: Option<List<EnumValueDefinition>>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct EnumTypeExtension {
    pub name: Identifier,
    pub directives: Vec<ConstantDirective>,
    pub values: Option<List<EnumValueDefinition>>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct InputObjectTypeDefinition {
    pub name: Identifier,
    pub directives: Vec<ConstantDirective>,
    pub fields: Option<List<InputValueDefinition>>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct InputObjectTypeExtension {
    pub name: Identifier,
    pub directives: Vec<ConstantDirective>,
    pub fields: Option<List<InputValueDefinition>>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct EnumValueDefinition {
    pub name: Identifier,
    pub directives: Vec<ConstantDirective>,
}

impl fmt::Display for EnumValueDefinition {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.name)?;
        write_directives(f, &self.directives)
    }
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct DirectiveDefinition {
    pub name: Identifier,
    pub arguments: Option<List<InputValueDefinition>>,
    pub repeatable: bool,
    pub locations: Vec<DirectiveLocation>,
}

#[derive(PartialEq, Eq, Ord, PartialOrd, Hash, Debug, Clone, Copy)]
pub enum DirectiveLocation {
    Query,
    Mutation,
    Subscription,
    Field,
    FragmentDefinition,
    FragmentSpread,
    InlineFragment,
    Schema,
    Scalar,
    Object,
    FieldDefinition,
    ArgumentDefinition,
    Interface,
    Union,
    Enum,
    EnumValue,
    InputObject,
    InputFieldDefinition,
    VariableDefinition,
}

impl fmt::Display for DirectiveLocation {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            DirectiveLocation::Query => write!(f, "QUERY"),
            DirectiveLocation::Mutation => write!(f, "MUTATION"),
            DirectiveLocation::Subscription => write!(f, "SUBSCRIPTION"),
            DirectiveLocation::Field => write!(f, "FIELD"),
            DirectiveLocation::FragmentDefinition => write!(f, "FRAGMENT_DEFINITION"),
            DirectiveLocation::FragmentSpread => write!(f, "FRAGMENT_SPREAD"),
            DirectiveLocation::InlineFragment => write!(f, "INLINE_FRAGMENT"),
            DirectiveLocation::Schema => write!(f, "SCHEMA"),
            DirectiveLocation::Scalar => write!(f, "SCALAR"),
            DirectiveLocation::Object => write!(f, "OBJECT"),
            DirectiveLocation::FieldDefinition => write!(f, "FIELD_DEFINITION"),
            DirectiveLocation::ArgumentDefinition => write!(f, "ARGUMENT_DEFINITION"),
            DirectiveLocation::Interface => write!(f, "INTERFACE"),
            DirectiveLocation::Union => write!(f, "UNION"),
            DirectiveLocation::Enum => write!(f, "ENUM"),
            DirectiveLocation::EnumValue => write!(f, "ENUM_VALUE"),
            DirectiveLocation::InputObject => write!(f, "INPUT_OBJECT"),
            DirectiveLocation::InputFieldDefinition => write!(f, "INPUT_FIELD_DEFINITION"),
            DirectiveLocation::VariableDefinition => write!(f, "VARIABLE_DEFINITION"),
        }
    }
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct InputValueDefinition {
    pub name: Identifier,
    pub type_: TypeAnnotation,
    pub default_value: Option<ConstantValue>,
    pub directives: Vec<ConstantDirective>,
}

impl fmt::Display for InputValueDefinition {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}: {}", self.name, self.type_)?;
        if let Some(v) = &self.default_value {
            write!(f, " = {}", v)?;
        }

        if !self.directives.is_empty() {
            write!(f, " ")?;
            write_list(f, &self.directives, " ")?;
        }

        Ok(())
    }
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct FieldDefinition {
    pub name: Identifier,
    pub type_: TypeAnnotation,
    pub arguments: Option<List<InputValueDefinition>>,
    pub directives: Vec<ConstantDirective>,
}

impl fmt::Display for FieldDefinition {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.name)?;
        if let Some(arguments) = self.arguments.as_ref() {
            write_arguments(f, &arguments.items)?;
        }
        write!(f, ": {}", self.type_)?;
        write_directives(f, &self.directives)
    }
}

fn write_list(
    f: &mut fmt::Formatter<'_>,
    list: &[impl fmt::Display],
    separator: &str,
) -> fmt::Result {
    let v = list
        .iter()
        .map(|elem| elem.to_string())
        .collect::<Vec<String>>()
        .join(separator);
    write!(f, "{}", v)
}

fn write_arguments(f: &mut fmt::Formatter<'_>, arguments: &[impl fmt::Display]) -> fmt::Result {
    if arguments.is_empty() {
        return Ok(());
    }

    write!(f, "(")?;
    write_list(f, arguments, ", ")?;
    write!(f, ")")
}

fn write_directives(f: &mut fmt::Formatter<'_>, directives: &[ConstantDirective]) -> fmt::Result {
    if directives.is_empty() {
        return Ok(());
    }

    write!(f, " ")?;
    write_list(f, directives, " ")
}

fn write_fields(f: &mut fmt::Formatter<'_>, fields: &[impl fmt::Display]) -> fmt::Result {
    if fields.is_empty() {
        return Ok(());
    }

    write!(f, " {{\n  ")?;
    write_list(f, fields, "\n  ")?;
    write!(f, "\n}}")
}

fn write_schema_definition_helper(
    f: &mut fmt::Formatter<'_>,
    directives: &[ConstantDirective],
    operation_types: &[OperationTypeDefinition],
) -> fmt::Result {
    write!(f, "schema")?;
    write_directives(f, directives)?;
    write_fields(f, operation_types)?;
    write!(f, "\n")
}

fn write_object_helper(
    f: &mut fmt::Formatter<'_>,
    name: &StringKey,
    interfaces: &[Identifier],
    fields: &Option<List<FieldDefinition>>,
    directives: &[ConstantDirective],
    is_extension: bool,
) -> fmt::Result {
    if is_extension {
        write!(f, "extend ")?;
    }

    write!(f, "type {}", name)?;
    if !interfaces.is_empty() {
        write!(f, " implements ")?;
        write_list(f, &interfaces, " & ")?;
    }
    write_directives(f, directives)?;
    if let Some(fields) = fields.as_ref() {
        write_fields(f, &fields.items)?;
    }
    write!(f, "\n")
}

fn write_interface_helper(
    f: &mut fmt::Formatter<'_>,
    name: &StringKey,
    fields: &Option<List<FieldDefinition>>,
    directives: &[ConstantDirective],
    is_extension: bool,
) -> fmt::Result {
    if is_extension {
        write!(f, "extend ")?;
    }

    write!(f, "interface {}", name)?;
    write_directives(f, directives)?;
    if let Some(fields) = fields.as_ref() {
        write_fields(f, &fields.items)?;
    }
    write!(f, "\n")
}

fn write_union_type_definition_helper(
    f: &mut fmt::Formatter<'_>,
    name: &StringKey,
    directives: &[ConstantDirective],
    members: &[Identifier],
) -> fmt::Result {
    write!(f, "union {}", name)?;
    write_directives(f, directives)?;
    write!(f, " = ")?;
    write_list(f, members, " | ")?;
    write!(f, "\n")
}

fn write_directive_definition_helper(
    f: &mut fmt::Formatter<'_>,
    name: &StringKey,
    arguments: &Option<List<InputValueDefinition>>,
    _repeatable: &bool,
    locations: &[DirectiveLocation],
) -> fmt::Result {
    write!(f, "directive @{}", name)?;
    if let Some(arguments) = arguments.as_ref() {
        write_arguments(f, &arguments.items)?;
    }
    write!(f, " on ")?;
    write_list(f, locations, " | ")?;
    write!(f, "\n")
}

fn write_input_object_type_definition_helper(
    f: &mut fmt::Formatter<'_>,
    name: &StringKey,
    directives: &[ConstantDirective],
    fields: &Option<List<InputValueDefinition>>,
) -> fmt::Result {
    write!(f, "input {}", name)?;
    write_directives(f, directives)?;
    if let Some(fields) = fields.as_ref() {
        write_fields(f, &fields.items)?;
    }
    write!(f, "\n")
}

fn write_enum_type_definition_helper(
    f: &mut fmt::Formatter<'_>,
    name: &StringKey,
    directives: &[ConstantDirective],
    values: &Option<List<EnumValueDefinition>>,
) -> fmt::Result {
    write!(f, "enum {}", name)?;
    write_directives(f, directives)?;
    if let Some(values) = values.as_ref() {
        write_fields(f, &values.items)?;
    }

    write!(f, "\n")
}

fn write_scalar_type_definition_helper(
    f: &mut fmt::Formatter<'_>,
    name: &StringKey,
    directives: &[ConstantDirective],
) -> fmt::Result {
    write!(f, "scalar {}", name)?;
    write_directives(f, directives)?;
    write!(f, "\n")
}

impl fmt::Display for ConstantDirective {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "@{}", self.name)?;
        if let Some(arguments) = self.arguments.as_ref() {
            write_arguments(f, &arguments.items)?;
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>use crate::cmp::Ordering;
use crate::time::Duration;

use core::hash::{Hash, Hasher};

pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
use crate::convert::TryInto;

const NSEC_PER_SEC: u64 = 1_000_000_000;

#[derive(Copy, Clone)]
struct Timespec {
    t: libc::timespec,
}

impl Timespec {
    const fn zero() -> Timespec {
        Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } }
    }

    fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
        if self >= other {
            Ok(if self.t.tv_nsec >= other.t.tv_nsec {
                Duration::new(
                    (self.t.tv_sec - other.t.tv_sec) as u64,
                    (self.t.tv_nsec - other.t.tv_nsec) as u32,
                )
            } else {
                Duration::new(
                    (self.t.tv_sec - 1 - other.t.tv_sec) as u64,
                    self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) - other.t.tv_nsec as u32,
                )
            })
        } else {
            match other.sub_timespec(self) {
                Ok(d) => Err(d),
                Err(d) => Ok(d),
            }
        }
    }

    fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
        let mut secs = other
            .as_secs()
            .try_into() // <- target type would be `libc::time_t`
            .ok()
            .and_then(|secs| self.t.tv_sec.checked_add(secs))?;

        // Nano calculations can't overflow because nanos are <1B which fit
        // in a u32.
        let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
        if nsec >= NSEC_PER_SEC as u32 {
            nsec -= NSEC_PER_SEC as u32;
            secs = secs.checked_add(1)?;
        }
        Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _ } })
    }

    fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
        let mut secs = other
            .as_secs()
            .try_into() // <- target type would be `libc::time_t`
            .ok()
            .and_then(|secs| self.t.tv_sec.checked_sub(secs))?;

        // Similar to above, nanos can't overflow.
        let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
        if nsec < 0 {
            nsec += NSEC_PER_SEC as i32;
            secs = secs.checked_sub(1)?;
        }
        Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _ } })
    }
}

impl PartialEq for Timespec {
    fn eq(&self, other: &Timespec) -> bool {
        self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec
    }
}

impl Eq for Timespec {}

impl PartialOrd for Timespec {
    fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Timespec {
    fn cmp(&self, other: &Timespec) -> Ordering {
        let me = (self.t.tv_sec, self.t.tv_nsec);
        let other = (other.t.tv_sec, other.t.tv_nsec);
        me.cmp(&other)
    }
}

impl Hash for Timespec {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.t.tv_sec.hash(state);
        self.t.tv_nsec.hash(state);
    }
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
mod inner {
    use crate::fmt;
    use crate::mem;
    use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
    use crate::sys::cvt;
    use crate::sys_common::mul_div_u64;
    use crate::time::Duration;

    use super::Timespec;
    use super::NSEC_PER_SEC;

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
    pub struct Instant {
        t: u64,
    }

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct SystemTime {
        t: Timespec,
    }

    pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };

    #[repr(C)]
    #[derive(Copy, Clone)]
    struct mach_timebase_info {
        numer: u32,
        denom: u32,
    }
    type mach_timebase_info_t = *mut mach_timebase_info;
    type kern_return_t = libc::c_int;

    impl Instant {
        pub fn now() -> Instant {
            extern "C" {
                fn mach_absolute_time() -> u64;
            }
            Instant { t: unsafe { mach_absolute_time() } }
        }

        pub const fn zero() -> Instant {
            Instant { t: 0 }
        }

        pub fn actually_monotonic() -> bool {
            true
        }

        pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
            let diff = self.t.checked_sub(other.t)?;
            let info = info();
            let nanos = mul_div_u64(diff, info.numer as u64, info.denom as u64);
            Some(Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32))
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant { t: self.t.checked_add(checked_dur2intervals(other)?)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant { t: self.t.checked_sub(checked_dur2intervals(other)?)? })
        }
    }

    impl SystemTime {
        pub fn now() -> SystemTime {
            use crate::ptr;

            let mut s = libc::timeval { tv_sec: 0, tv_usec: 0 };
            cvt(unsafe { libc::gettimeofday(&mut s, ptr::null_mut()) }).unwrap();
            return SystemTime::from(s);
        }

        pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
            self.t.sub_timespec(&other.t)
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_add_duration(other)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_sub_duration(other)? })
        }
    }

    impl From<libc::timeval> for SystemTime {
        fn from(t: libc::timeval) -> SystemTime {
            SystemTime::from(libc::timespec {
                tv_sec: t.tv_sec,
                tv_nsec: (t.tv_usec * 1000) as libc::c_long,
            })
        }
    }

    impl From<libc::timespec> for SystemTime {
        fn from(t: libc::timespec) -> SystemTime {
            SystemTime { t: Timespec { t } }
        }
    }

    impl fmt::Debug for SystemTime {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.debug_struct("SystemTime")
                .field("tv_sec", &self.t.t.tv_sec)
                .field("tv_nsec", &self.t.t.tv_nsec)
                .finish()
        }
    }

    fn checked_dur2intervals(dur: &Duration) -> Option<u64> {
        let nanos =
            dur.as_secs().checked_mul(NSEC_PER_SEC)?.checked_add(dur.subsec_nanos() as u64)?;
        let info = info();
        Some(mul_div_u64(nanos, info.denom as u64, info.numer as u64))
    }

    fn info() -> mach_timebase_info {
        static mut INFO: mach_timebase_info = mach_timebase_info { numer: 0, denom: 0 };
        static STATE: AtomicUsize = AtomicUsize::new(0);

        unsafe {
            // If a previous thread has filled in this global state, use that.
            if STATE.load(SeqCst) == 2 {
                return INFO;
            }

            // ... otherwise learn for ourselves ...
            let mut info = mem::zeroed();
            extern "C" {
                fn mach_timebase_info(info: mach_timebase_info_t) -> kern_return_t;
            }

            mach_timebase_info(&mut info);

            // ... and attempt to be the one thread that stores it globally for
            // all other threads
            if STATE.compare_exchange(0, 1, SeqCst, SeqCst).is_ok() {
                INFO = info;
                STATE.store(2, SeqCst);
            }
            return info;
        }
    }
}

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
mod inner {
    use crate::fmt;
    use crate::sys::cvt;
    use crate::time::Duration;

    use super::Timespec;

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct Instant {
        t: Timespec,
    }

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct SystemTime {
        t: Timespec,
    }

    pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };

    impl Instant {
        pub fn now() -> Instant {
            Instant { t: now(libc::CLOCK_MONOTONIC) }
        }

        pub const fn zero() -> Instant {
            Instant { t: Timespec::zero() }
        }

        pub fn actually_monotonic() -> bool {
            (cfg!(target_os = "linux") && cfg!(target_arch = "x86_64"))
                || (cfg!(target_os = "linux") && cfg!(target_arch = "x86"))
                || cfg!(target_os = "fuchsia")
                || false // last clause, used so `||` is always trailing above
        }

        pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
            self.t.sub_timespec(&other.t).ok()
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant { t: self.t.checked_add_duration(other)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant { t: self.t.checked_sub_duration(other)? })
        }
    }

    impl fmt::Debug for Instant {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.debug_struct("Instant")
                .field("tv_sec", &self.t.t.tv_sec)
                .field("tv_nsec", &self.t.t.tv_nsec)
                .finish()
        }
    }

    impl SystemTime {
        pub fn now() -> SystemTime {
            SystemTime { t: now(libc::CLOCK_REALTIME) }
        }

        pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
            self.t.sub_timespec(&other.t)
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_add_duration(other)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_sub_duration(other)? })
        }
    }

    impl From<libc::timespec> for SystemTime {
        fn from(t: libc::timespec) -> SystemTime {
            SystemTime { t: Timespec { t } }
        }
    }

    impl fmt::Debug for SystemTime {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.debug_struct("SystemTime")
                .field("tv_sec", &self.t.t.tv_sec)
                .field("tv_nsec", &self.t.t.tv_nsec)
                .finish()
        }
    }

    #[cfg(not(target_os = "dragonfly"))]
    pub type clock_t = libc::c_int;
    #[cfg(target_os = "dragonfly")]
    pub type clock_t = libc::c_ulong;

    fn now(clock: clock_t) -> Timespec {
        let mut t = Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } };
        cvt(unsafe { libc::clock_gettime(clock, &mut t.t) }).unwrap();
        t
    }
}
<commit_msg>Strip unnecessary subexpression<commit_after>use crate::cmp::Ordering;
use crate::time::Duration;

use core::hash::{Hash, Hasher};

pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
use crate::convert::TryInto;

const NSEC_PER_SEC: u64 = 1_000_000_000;

#[derive(Copy, Clone)]
struct Timespec {
    t: libc::timespec,
}

impl Timespec {
    const fn zero() -> Timespec {
        Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } }
    }

    fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
        if self >= other {
            Ok(if self.t.tv_nsec >= other.t.tv_nsec {
                Duration::new(
                    (self.t.tv_sec - other.t.tv_sec) as u64,
                    (self.t.tv_nsec - other.t.tv_nsec) as u32,
                )
            } else {
                Duration::new(
                    (self.t.tv_sec - 1 - other.t.tv_sec) as u64,
                    self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) - other.t.tv_nsec as u32,
                )
            })
        } else {
            match other.sub_timespec(self) {
                Ok(d) => Err(d),
                Err(d) => Ok(d),
            }
        }
    }

    fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
        let mut secs = other
            .as_secs()
            .try_into() // <- target type would be `libc::time_t`
            .ok()
            .and_then(|secs| self.t.tv_sec.checked_add(secs))?;

        // Nano calculations can't overflow because nanos are <1B which fit
        // in a u32.
        let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
        if nsec >= NSEC_PER_SEC as u32 {
            nsec -= NSEC_PER_SEC as u32;
            secs = secs.checked_add(1)?;
        }
        Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _ } })
    }

    fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
        let mut secs = other
            .as_secs()
            .try_into() // <- target type would be `libc::time_t`
            .ok()
            .and_then(|secs| self.t.tv_sec.checked_sub(secs))?;

        // Similar to above, nanos can't overflow.
        let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
        if nsec < 0 {
            nsec += NSEC_PER_SEC as i32;
            secs = secs.checked_sub(1)?;
        }
        Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _ } })
    }
}

impl PartialEq for Timespec {
    fn eq(&self, other: &Timespec) -> bool {
        self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec
    }
}

impl Eq for Timespec {}

impl PartialOrd for Timespec {
    fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Timespec {
    fn cmp(&self, other: &Timespec) -> Ordering {
        let me = (self.t.tv_sec, self.t.tv_nsec);
        let other = (other.t.tv_sec, other.t.tv_nsec);
        me.cmp(&other)
    }
}

impl Hash for Timespec {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.t.tv_sec.hash(state);
        self.t.tv_nsec.hash(state);
    }
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
mod inner {
    use crate::fmt;
    use crate::mem;
    use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
    use crate::sys::cvt;
    use crate::sys_common::mul_div_u64;
    use crate::time::Duration;

    use super::Timespec;
    use super::NSEC_PER_SEC;

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
    pub struct Instant {
        t: u64,
    }

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct SystemTime {
        t: Timespec,
    }

    pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };

    #[repr(C)]
    #[derive(Copy, Clone)]
    struct mach_timebase_info {
        numer: u32,
        denom: u32,
    }
    type mach_timebase_info_t = *mut mach_timebase_info;
    type kern_return_t = libc::c_int;

    impl Instant {
        pub fn now() -> Instant {
            extern "C" {
                fn mach_absolute_time() -> u64;
            }
            Instant { t: unsafe { mach_absolute_time() } }
        }

        pub const fn zero() -> Instant {
            Instant { t: 0 }
        }

        pub fn actually_monotonic() -> bool {
            true
        }

        pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
            let diff = self.t.checked_sub(other.t)?;
            let info = info();
            let nanos = mul_div_u64(diff, info.numer as u64, info.denom as u64);
            Some(Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32))
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant { t: self.t.checked_add(checked_dur2intervals(other)?)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant { t: self.t.checked_sub(checked_dur2intervals(other)?)? })
        }
    }

    impl SystemTime {
        pub fn now() -> SystemTime {
            use crate::ptr;

            let mut s = libc::timeval { tv_sec: 0, tv_usec: 0 };
            cvt(unsafe { libc::gettimeofday(&mut s, ptr::null_mut()) }).unwrap();
            return SystemTime::from(s);
        }

        pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
            self.t.sub_timespec(&other.t)
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_add_duration(other)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_sub_duration(other)? })
        }
    }

    impl From<libc::timeval> for SystemTime {
        fn from(t: libc::timeval) -> SystemTime {
            SystemTime::from(libc::timespec {
                tv_sec: t.tv_sec,
                tv_nsec: (t.tv_usec * 1000) as libc::c_long,
            })
        }
    }

    impl From<libc::timespec> for SystemTime {
        fn from(t: libc::timespec) -> SystemTime {
            SystemTime { t: Timespec { t } }
        }
    }

    impl fmt::Debug for SystemTime {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.debug_struct("SystemTime")
                .field("tv_sec", &self.t.t.tv_sec)
                .field("tv_nsec", &self.t.t.tv_nsec)
                .finish()
        }
    }

    fn checked_dur2intervals(dur: &Duration) -> Option<u64> {
        let nanos =
            dur.as_secs().checked_mul(NSEC_PER_SEC)?.checked_add(dur.subsec_nanos() as u64)?;
        let info = info();
        Some(mul_div_u64(nanos, info.denom as u64, info.numer as u64))
    }

    fn info() -> mach_timebase_info {
        static mut INFO: mach_timebase_info = mach_timebase_info { numer: 0, denom: 0 };
        static STATE: AtomicUsize = AtomicUsize::new(0);

        unsafe {
            // If a previous thread has filled in this global state, use that.
            if STATE.load(SeqCst) == 2 {
                return INFO;
            }

            // ... otherwise learn for ourselves ...
            let mut info = mem::zeroed();
            extern "C" {
                fn mach_timebase_info(info: mach_timebase_info_t) -> kern_return_t;
            }

            mach_timebase_info(&mut info);

            // ... and attempt to be the one thread that stores it globally for
            // all other threads
            if STATE.compare_exchange(0, 1, SeqCst, SeqCst).is_ok() {
                INFO = info;
                STATE.store(2, SeqCst);
            }
            return info;
        }
    }
}

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
mod inner {
    use crate::fmt;
    use crate::sys::cvt;
    use crate::time::Duration;

    use super::Timespec;

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct Instant {
        t: Timespec,
    }

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct SystemTime {
        t: Timespec,
    }

    pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };

    impl Instant {
        pub fn now() -> Instant {
            Instant { t: now(libc::CLOCK_MONOTONIC) }
        }

        pub const fn zero() -> Instant {
            Instant { t: Timespec::zero() }
        }

        pub fn actually_monotonic() -> bool {
            (cfg!(target_os = "linux") && cfg!(target_arch = "x86_64"))
                || (cfg!(target_os = "linux") && cfg!(target_arch = "x86"))
                || cfg!(target_os = "fuchsia")
        }

        pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
            self.t.sub_timespec(&other.t).ok()
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant { t: self.t.checked_add_duration(other)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant { t: self.t.checked_sub_duration(other)? })
        }
    }

    impl fmt::Debug for Instant {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.debug_struct("Instant")
                .field("tv_sec", &self.t.t.tv_sec)
                .field("tv_nsec", &self.t.t.tv_nsec)
                .finish()
        }
    }

    impl SystemTime {
        pub fn now() -> SystemTime {
            SystemTime { t: now(libc::CLOCK_REALTIME) }
        }

        pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
            self.t.sub_timespec(&other.t)
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_add_duration(other)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_sub_duration(other)? })
        }
    }

    impl From<libc::timespec> for SystemTime {
        fn from(t: libc::timespec) -> SystemTime {
            SystemTime { t: Timespec { t } }
        }
    }

    impl fmt::Debug for SystemTime {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.debug_struct("SystemTime")
                .field("tv_sec", &self.t.t.tv_sec)
                .field("tv_nsec", &self.t.t.tv_nsec)
                .finish()
        }
    }

    #[cfg(not(target_os = "dragonfly"))]
    pub type clock_t = libc::c_int;
    #[cfg(target_os = "dragonfly")]
    pub type clock_t = libc::c_ulong;

    fn now(clock: clock_t) -> Timespec {
        let mut t = Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } };
        cvt(unsafe { libc::clock_gettime(clock, &mut t.t) }).unwrap();
        t
    }
}
<|endoftext|>


<commit_before>use std::{any::Any, collections::HashMap};

use dces::prelude::Component;

/// The struct `Registry` represents a global service registry. It is used to register and call
/// global Registry like settings service oder a database service.
#[derive(Default)]
pub struct Registry {
    registry: HashMap<String, Box<dyn Any>>,
}

impl Registry {
    /// Creates a service registry with an empty Registry map.
    pub fn new() -> Self {
        Registry::default()
    }

    /// Register a new Registry with the given key.
    pub fn register<C: Component>(&mut self, key: impl Into<String>, service: C) {
        self.registry.insert(key.into(), Box::new(service));
    }

    /// Gets a service.
    ///
    /// # Panics
    ///
    /// Panics if the there is no service for the given key or the given service type is wrong.
    pub fn get<C: Component>(&self, key: impl Into<String>) -> &C {
        let key = key.into();
        self.registry
            .get(&key)
            .expect(format!("Registry.get(): could not found key: {}", key).as_str())
            .downcast_ref()
            .expect(format!("Registry.get(): wrong type for key: {}", key).as_str())
    }

    /// Gets a service.
    ///
    /// # Panics
    ///
    /// Panics if the there is no service for the given key or the given service type is wrong.
    // pub fn try_get<C: Component>(&self, key: impl Into<String>) -> Option<&C> {
    //     self.Registry
    //         .get(&key.into())
    //         .ok_or_else(|| None)
    //         .map(|c| c.downcast_ref())
    // }

    /// Gets a mutable reference of the requested service.
    ///
    /// # Panics
    ///
    /// Panics if the there is no service for the given key or the given service type is wrong.
    pub fn get_mut<C: Component>(&mut self, key: impl Into<String>) -> &C {
        let key = key.into();
        self.registry
            .get_mut(&key)
            .expect(format!("Registry.get(): could not found key: {}", key).as_str())
            .downcast_ref()
            .expect(format!("Registry.get(): wrong type for key: {}", key).as_str())
    }
}
<commit_msg>Finish registry.<commit_after>use std::{any::Any, collections::HashMap};

use dces::prelude::Component;

/// The struct `Registry` represents a global registry. It is used to register and call
/// global elements like services.
#[derive(Default)]
pub struct Registry {
    registry: HashMap<String, Box<dyn Any>>,
}

impl Registry {
    /// Creates a service registry with an empty Registry map.
    pub fn new() -> Self {
        Registry::default()
    }

    /// Register a new Registry with the given key.
    pub fn register<C: Component>(&mut self, key: impl Into<String>, service: C) {
        self.registry.insert(key.into(), Box::new(service));
    }

    /// Gets an element from the registry.
    ///
    /// # Panics
    ///
    /// Panics if the there is no element for the given key or the given service type is wrong.
    pub fn get<C: Component>(&self, key: &str) -> &C {
        self.registry
            .get(&key.to_string())
            .unwrap_or_else(|| panic!("Registry.get(): key: {} could not be found.", key))
            .downcast_ref()
            .unwrap_or_else(|| panic!("Registry.get(): wrong type for key: {}", key))
    }

    /// Gets a mutable reference of the requested element.
    ///
    /// # Panics
    ///
    /// Panics if the there is no service for the given key or the given service type is wrong.
    pub fn get_mut<C: Component>(&mut self, key: impl Into<String>) -> &mut C {
        let key = key.into();
        self.registry
            .get_mut(&key)
            .unwrap_or_else(|| panic!("Registry.get(): key: {} could not be found.", key))
            .downcast_mut()
            .unwrap_or_else(|| panic!("Registry.get(): wrong type for key: {}", key))
    }

    /// Try to get an element from the registry.
    ///
    /// # Panics
    ///
    /// Panics if the there is no service for the given key or the given service type is wrong.
    pub fn try_get<C: Component>(&self, key: &str) -> Option<&C> {
        if let Some(e) = self.registry.get(&key.to_string()) {
            if let Some(r) = e.downcast_ref() {
                return Some(r);
            }
        }

        None
    }

    /// Try to get an element from the registry.
    ///
    /// # Panics
    ///
    /// Panics if the there is no service for the given key or the given service type is wrong.
    pub fn try_get_mut<C: Component>(&mut self, key: &str) -> Option<&mut C> {
        if let Some(e) = self.registry.get_mut(&key.to_string()) {
            if let Some(r) = e.downcast_mut() {
                return Some(r);
            }
        }

        None
    }

    /// Returns the number of elements in the registry.
    pub fn len(&self) -> usize {
        self.registry.len()
    }

    /// Returns true if the registry contains no elements.
    pub fn is_empty(&self) -> bool {
        self.registry.is_empty()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    struct ServiceOne;
    struct ServiceTwo;

    #[test]
    fn register() {
        let mut registry = Registry::new();
        registry.register("one", ServiceOne);
        registry.register("two", ServiceTwo);

        assert!(registry.try_get::<ServiceOne>("one").is_some());
        assert!(registry.try_get::<ServiceTwo>("two").is_some());
    }

    #[test]
    fn try_get_mut() {
        let mut registry = Registry::new();
        registry.register("one", ServiceOne);
        registry.register("two", ServiceTwo);

        assert!(registry.try_get_mut::<ServiceOne>("one").is_some());
        assert!(registry.try_get_mut::<ServiceTwo>("two").is_some());
    }

    #[test]
    fn len() {
        let mut registry = Registry::new();
        assert_eq!(registry.len(), 0);

        registry.register("one", ServiceOne);
        assert_eq!(registry.len(), 1);

        registry.register("two", ServiceTwo);
        assert_eq!(registry.len(), 2);
    }

    #[test]
    fn is_empty() {
        let mut registry = Registry::new();
        assert!(registry.is_empty());

        registry.register("one", ServiceOne);
        assert!(!registry.is_empty());
    }
}<|endoftext|>


<commit_before>//! FIXME: write short doc here

use std::{
    path::{Path, PathBuf},
    sync::Arc,
};

use crossbeam_channel::{unbounded, Receiver};
use lsp_server::ErrorCode;
use lsp_types::Url;
use parking_lot::RwLock;
use ra_ide::{
    Analysis, AnalysisChange, AnalysisHost, CrateGraph, FeatureFlags, FileId, LibraryData,
    SourceRootId,
};
use ra_project_model::{get_rustc_cfg_options, ProjectWorkspace};
use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch};
use ra_vfs_glob::{Glob, RustPackageFilterBuilder};
use relative_path::RelativePathBuf;

use crate::{
    main_loop::pending_requests::{CompletedRequest, LatestRequests},
    LspError, Result,
};

#[derive(Debug, Clone)]
pub struct Options {
    pub publish_decorations: bool,
    pub supports_location_link: bool,
    pub line_folding_only: bool,
    pub max_inlay_hint_length: Option<usize>,
}

/// `WorldState` is the primary mutable state of the language server
///
/// The most interesting components are `vfs`, which stores a consistent
/// snapshot of the file systems, and `analysis_host`, which stores our
/// incremental salsa database.
#[derive(Debug)]
pub struct WorldState {
    pub options: Options,
    //FIXME: this belongs to `LoopState` rather than to `WorldState`
    pub roots_to_scan: usize,
    pub roots: Vec<PathBuf>,
    pub workspaces: Arc<Vec<ProjectWorkspace>>,
    pub analysis_host: AnalysisHost,
    pub vfs: Arc<RwLock<Vfs>>,
    pub task_receiver: Receiver<VfsTask>,
    pub latest_requests: Arc<RwLock<LatestRequests>>,
}

/// An immutable snapshot of the world's state at a point in time.
pub struct WorldSnapshot {
    pub options: Options,
    pub workspaces: Arc<Vec<ProjectWorkspace>>,
    pub analysis: Analysis,
    pub vfs: Arc<RwLock<Vfs>>,
    pub latest_requests: Arc<RwLock<LatestRequests>>,
}

impl WorldState {
    pub fn new(
        folder_roots: Vec<PathBuf>,
        workspaces: Vec<ProjectWorkspace>,
        lru_capacity: Option<usize>,
        exclude_globs: &[Glob],
        watch: Watch,
        options: Options,
        feature_flags: FeatureFlags,
    ) -> WorldState {
        let mut change = AnalysisChange::new();

        let mut roots = Vec::new();
        roots.extend(folder_roots.iter().map(|path| {
            let mut filter = RustPackageFilterBuilder::default().set_member(true);
            for glob in exclude_globs.iter() {
                filter = filter.exclude(glob.clone());
            }
            RootEntry::new(path.clone(), filter.into_vfs_filter())
        }));
        for ws in workspaces.iter() {
            roots.extend(ws.to_roots().into_iter().map(|pkg_root| {
                let mut filter =
                    RustPackageFilterBuilder::default().set_member(pkg_root.is_member());
                for glob in exclude_globs.iter() {
                    filter = filter.exclude(glob.clone());
                }
                RootEntry::new(pkg_root.path().clone(), filter.into_vfs_filter())
            }));
        }
        let (task_sender, task_receiver) = unbounded();
        let task_sender = Box::new(move |t| task_sender.send(t).unwrap());
        let (mut vfs, vfs_roots) = Vfs::new(roots, task_sender, watch);
        let roots_to_scan = vfs_roots.len();
        for r in vfs_roots {
            let vfs_root_path = vfs.root2path(r);
            let is_local = folder_roots.iter().any(|it| vfs_root_path.starts_with(it));
            change.add_root(SourceRootId(r.0), is_local);
            change.set_debug_root_path(SourceRootId(r.0), vfs_root_path.display().to_string());
        }

        // FIXME: Read default cfgs from config
        let default_cfg_options = {
            let mut opts = get_rustc_cfg_options();
            opts.insert_atom("test".into());
            opts.insert_atom("debug_assertion".into());
            opts
        };

        // Create crate graph from all the workspaces
        let mut crate_graph = CrateGraph::default();
        let mut load = |path: &std::path::Path| {
            let vfs_file = vfs.load(path);
            vfs_file.map(|f| FileId(f.0))
        };
        for ws in workspaces.iter() {
            let (graph, crate_names) = ws.to_crate_graph(&default_cfg_options, &mut load);
            let shift = crate_graph.extend(graph);
            for (crate_id, name) in crate_names {
                change.set_debug_crate_name(crate_id.shift(shift), name)
            }
        }
        change.set_crate_graph(crate_graph);

        let mut analysis_host = AnalysisHost::new(lru_capacity, feature_flags);
        analysis_host.apply_change(change);
        WorldState {
            options,
            roots_to_scan,
            roots: folder_roots,
            workspaces: Arc::new(workspaces),
            analysis_host,
            vfs: Arc::new(RwLock::new(vfs)),
            task_receiver,
            latest_requests: Default::default(),
        }
    }

    /// Returns a vec of libraries
    /// FIXME: better API here
    pub fn process_changes(
        &mut self,
    ) -> Vec<(SourceRootId, Vec<(FileId, RelativePathBuf, Arc<String>)>)> {
        let changes = self.vfs.write().commit_changes();
        if changes.is_empty() {
            return Vec::new();
        }
        let mut libs = Vec::new();
        let mut change = AnalysisChange::new();
        for c in changes {
            match c {
                VfsChange::AddRoot { root, files } => {
                    let root_path = self.vfs.read().root2path(root);
                    let is_local = self.roots.iter().any(|r| root_path.starts_with(r));
                    if is_local {
                        self.roots_to_scan -= 1;
                        for (file, path, text) in files {
                            change.add_file(SourceRootId(root.0), FileId(file.0), path, text);
                        }
                    } else {
                        let files = files
                            .into_iter()
                            .map(|(vfsfile, path, text)| (FileId(vfsfile.0), path, text))
                            .collect();
                        libs.push((SourceRootId(root.0), files));
                    }
                }
                VfsChange::AddFile { root, file, path, text } => {
                    change.add_file(SourceRootId(root.0), FileId(file.0), path, text);
                }
                VfsChange::RemoveFile { root, file, path } => {
                    change.remove_file(SourceRootId(root.0), FileId(file.0), path)
                }
                VfsChange::ChangeFile { file, text } => {
                    change.change_file(FileId(file.0), text);
                }
            }
        }
        self.analysis_host.apply_change(change);
        libs
    }

    pub fn add_lib(&mut self, data: LibraryData) {
        self.roots_to_scan -= 1;
        let mut change = AnalysisChange::new();
        change.add_library(data);
        self.analysis_host.apply_change(change);
    }

    pub fn snapshot(&self) -> WorldSnapshot {
        WorldSnapshot {
            options: self.options.clone(),
            workspaces: Arc::clone(&self.workspaces),
            analysis: self.analysis_host.analysis(),
            vfs: Arc::clone(&self.vfs),
            latest_requests: Arc::clone(&self.latest_requests),
        }
    }

    pub fn maybe_collect_garbage(&mut self) {
        self.analysis_host.maybe_collect_garbage()
    }

    pub fn collect_garbage(&mut self) {
        self.analysis_host.collect_garbage()
    }

    pub fn complete_request(&mut self, request: CompletedRequest) {
        self.latest_requests.write().record(request)
    }

    pub fn feature_flags(&self) -> &FeatureFlags {
        self.analysis_host.feature_flags()
    }
}

impl WorldSnapshot {
    pub fn analysis(&self) -> &Analysis {
        &self.analysis
    }

    pub fn uri_to_file_id(&self, uri: &Url) -> Result<FileId> {
        let path = uri.to_file_path().map_err(|()| format!("invalid uri: {}", uri))?;
        let file = self.vfs.read().path2file(&path).ok_or_else(|| {
            // Show warning as this file is outside current workspace
            LspError {
                code: ErrorCode::InvalidRequest as i32,
                message: "Rust file outside current workspace is not supported yet.".to_string(),
            }
        })?;
        Ok(FileId(file.0))
    }

    pub fn file_id_to_uri(&self, id: FileId) -> Result<Url> {
        let path = self.vfs.read().file2path(VfsFile(id.0));
        let url = Url::from_file_path(&path)
            .map_err(|_| format!("can't convert path to url: {}", path.display()))?;

        #[cfg(target_os = "windows")]
        let url = lowercase_drive_letter(&url);
        Ok(url)
    }

    pub fn file_line_endings(&self, id: FileId) -> LineEndings {
        self.vfs.read().file_line_endings(VfsFile(id.0))
    }

    pub fn path_to_uri(&self, root: SourceRootId, path: &RelativePathBuf) -> Result<Url> {
        let base = self.vfs.read().root2path(VfsRoot(root.0));
        let path = path.to_path(base);
        let url = Url::from_file_path(&path)
            .map_err(|_| format!("can't convert path to url: {}", path.display()))?;
        Ok(url)
    }

    pub fn status(&self) -> String {
        let mut res = String::new();
        if self.workspaces.is_empty() {
            res.push_str("no workspaces\n")
        } else {
            res.push_str("workspaces:\n");
            for w in self.workspaces.iter() {
                res += &format!("{} packages loaded\n", w.n_packages());
            }
        }
        res.push_str("\nanalysis:\n");
        res.push_str(
            &self
                .analysis
                .status()
                .unwrap_or_else(|_| "Analysis retrieval was cancelled".to_owned()),
        );
        res
    }

    pub fn workspace_root_for(&self, file_id: FileId) -> Option<&Path> {
        let path = self.vfs.read().file2path(VfsFile(file_id.0));
        self.workspaces.iter().find_map(|ws| ws.workspace_root_for(&path))
    }

    pub fn feature_flags(&self) -> &FeatureFlags {
        self.analysis.feature_flags()
    }
}

#[cfg(target_os = "windows")]
fn lowercase_drive_letter(url: &Url) -> Url {
    use std::str::FromStr;

    let s = url.to_string();
    let drive_partition: Vec<&str> = s.rsplitn(2, ':').collect::<Vec<&str>>();

    if drive_partition.len() == 1 {
        return url.clone();
    }

    let joined = drive_partition[1].to_ascii_lowercase() + ":" + drive_partition[0];
    let url = Url::from_str(&joined).expect("This came from a valid `Url`");
    url
}

#[test]
fn test_lowercase_drive_letter_with_drive() {
    let url = Url::from_file_path("C:\\Test").unwrap();
    let url = lowercase_drive_letter(&url);

    assert_eq!(url.to_string(), "file:///c:/Test");
}

#[test]
fn test_drive_without_colon_passthrough() {
    let url = Url::from_file_path(r#"\\localhost\C$\my_dir"#).expect("Should work");
    let url = lowercase_drive_letter(&url);

    assert_eq!(url.to_string(), "file:///C$/my_dir");
}
<commit_msg>improved path checking to consider only paths that may contain a windows drive.<commit_after>//! FIXME: write short doc here

use std::{
    path::{Path, PathBuf},
    sync::Arc,
};

use crossbeam_channel::{unbounded, Receiver};
use lsp_server::ErrorCode;
use lsp_types::Url;
use parking_lot::RwLock;
use ra_ide::{
    Analysis, AnalysisChange, AnalysisHost, CrateGraph, FeatureFlags, FileId, LibraryData,
    SourceRootId,
};
use ra_project_model::{get_rustc_cfg_options, ProjectWorkspace};
use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch};
use ra_vfs_glob::{Glob, RustPackageFilterBuilder};
use relative_path::RelativePathBuf;
use std::path::{Component, Prefix};

use crate::{
    main_loop::pending_requests::{CompletedRequest, LatestRequests},
    LspError, Result,
};
use std::str::FromStr;

#[derive(Debug, Clone)]
pub struct Options {
    pub publish_decorations: bool,
    pub supports_location_link: bool,
    pub line_folding_only: bool,
    pub max_inlay_hint_length: Option<usize>,
}

/// `WorldState` is the primary mutable state of the language server
///
/// The most interesting components are `vfs`, which stores a consistent
/// snapshot of the file systems, and `analysis_host`, which stores our
/// incremental salsa database.
#[derive(Debug)]
pub struct WorldState {
    pub options: Options,
    //FIXME: this belongs to `LoopState` rather than to `WorldState`
    pub roots_to_scan: usize,
    pub roots: Vec<PathBuf>,
    pub workspaces: Arc<Vec<ProjectWorkspace>>,
    pub analysis_host: AnalysisHost,
    pub vfs: Arc<RwLock<Vfs>>,
    pub task_receiver: Receiver<VfsTask>,
    pub latest_requests: Arc<RwLock<LatestRequests>>,
}

/// An immutable snapshot of the world's state at a point in time.
pub struct WorldSnapshot {
    pub options: Options,
    pub workspaces: Arc<Vec<ProjectWorkspace>>,
    pub analysis: Analysis,
    pub vfs: Arc<RwLock<Vfs>>,
    pub latest_requests: Arc<RwLock<LatestRequests>>,
}

impl WorldState {
    pub fn new(
        folder_roots: Vec<PathBuf>,
        workspaces: Vec<ProjectWorkspace>,
        lru_capacity: Option<usize>,
        exclude_globs: &[Glob],
        watch: Watch,
        options: Options,
        feature_flags: FeatureFlags,
    ) -> WorldState {
        let mut change = AnalysisChange::new();

        let mut roots = Vec::new();
        roots.extend(folder_roots.iter().map(|path| {
            let mut filter = RustPackageFilterBuilder::default().set_member(true);
            for glob in exclude_globs.iter() {
                filter = filter.exclude(glob.clone());
            }
            RootEntry::new(path.clone(), filter.into_vfs_filter())
        }));
        for ws in workspaces.iter() {
            roots.extend(ws.to_roots().into_iter().map(|pkg_root| {
                let mut filter =
                    RustPackageFilterBuilder::default().set_member(pkg_root.is_member());
                for glob in exclude_globs.iter() {
                    filter = filter.exclude(glob.clone());
                }
                RootEntry::new(pkg_root.path().clone(), filter.into_vfs_filter())
            }));
        }
        let (task_sender, task_receiver) = unbounded();
        let task_sender = Box::new(move |t| task_sender.send(t).unwrap());
        let (mut vfs, vfs_roots) = Vfs::new(roots, task_sender, watch);
        let roots_to_scan = vfs_roots.len();
        for r in vfs_roots {
            let vfs_root_path = vfs.root2path(r);
            let is_local = folder_roots.iter().any(|it| vfs_root_path.starts_with(it));
            change.add_root(SourceRootId(r.0), is_local);
            change.set_debug_root_path(SourceRootId(r.0), vfs_root_path.display().to_string());
        }

        // FIXME: Read default cfgs from config
        let default_cfg_options = {
            let mut opts = get_rustc_cfg_options();
            opts.insert_atom("test".into());
            opts.insert_atom("debug_assertion".into());
            opts
        };

        // Create crate graph from all the workspaces
        let mut crate_graph = CrateGraph::default();
        let mut load = |path: &std::path::Path| {
            let vfs_file = vfs.load(path);
            vfs_file.map(|f| FileId(f.0))
        };
        for ws in workspaces.iter() {
            let (graph, crate_names) = ws.to_crate_graph(&default_cfg_options, &mut load);
            let shift = crate_graph.extend(graph);
            for (crate_id, name) in crate_names {
                change.set_debug_crate_name(crate_id.shift(shift), name)
            }
        }
        change.set_crate_graph(crate_graph);

        let mut analysis_host = AnalysisHost::new(lru_capacity, feature_flags);
        analysis_host.apply_change(change);
        WorldState {
            options,
            roots_to_scan,
            roots: folder_roots,
            workspaces: Arc::new(workspaces),
            analysis_host,
            vfs: Arc::new(RwLock::new(vfs)),
            task_receiver,
            latest_requests: Default::default(),
        }
    }

    /// Returns a vec of libraries
    /// FIXME: better API here
    pub fn process_changes(
        &mut self,
    ) -> Vec<(SourceRootId, Vec<(FileId, RelativePathBuf, Arc<String>)>)> {
        let changes = self.vfs.write().commit_changes();
        if changes.is_empty() {
            return Vec::new();
        }
        let mut libs = Vec::new();
        let mut change = AnalysisChange::new();
        for c in changes {
            match c {
                VfsChange::AddRoot { root, files } => {
                    let root_path = self.vfs.read().root2path(root);
                    let is_local = self.roots.iter().any(|r| root_path.starts_with(r));
                    if is_local {
                        self.roots_to_scan -= 1;
                        for (file, path, text) in files {
                            change.add_file(SourceRootId(root.0), FileId(file.0), path, text);
                        }
                    } else {
                        let files = files
                            .into_iter()
                            .map(|(vfsfile, path, text)| (FileId(vfsfile.0), path, text))
                            .collect();
                        libs.push((SourceRootId(root.0), files));
                    }
                }
                VfsChange::AddFile { root, file, path, text } => {
                    change.add_file(SourceRootId(root.0), FileId(file.0), path, text);
                }
                VfsChange::RemoveFile { root, file, path } => {
                    change.remove_file(SourceRootId(root.0), FileId(file.0), path)
                }
                VfsChange::ChangeFile { file, text } => {
                    change.change_file(FileId(file.0), text);
                }
            }
        }
        self.analysis_host.apply_change(change);
        libs
    }

    pub fn add_lib(&mut self, data: LibraryData) {
        self.roots_to_scan -= 1;
        let mut change = AnalysisChange::new();
        change.add_library(data);
        self.analysis_host.apply_change(change);
    }

    pub fn snapshot(&self) -> WorldSnapshot {
        WorldSnapshot {
            options: self.options.clone(),
            workspaces: Arc::clone(&self.workspaces),
            analysis: self.analysis_host.analysis(),
            vfs: Arc::clone(&self.vfs),
            latest_requests: Arc::clone(&self.latest_requests),
        }
    }

    pub fn maybe_collect_garbage(&mut self) {
        self.analysis_host.maybe_collect_garbage()
    }

    pub fn collect_garbage(&mut self) {
        self.analysis_host.collect_garbage()
    }

    pub fn complete_request(&mut self, request: CompletedRequest) {
        self.latest_requests.write().record(request)
    }

    pub fn feature_flags(&self) -> &FeatureFlags {
        self.analysis_host.feature_flags()
    }
}

impl WorldSnapshot {
    pub fn analysis(&self) -> &Analysis {
        &self.analysis
    }

    pub fn uri_to_file_id(&self, uri: &Url) -> Result<FileId> {
        let path = uri.to_file_path().map_err(|()| format!("invalid uri: {}", uri))?;
        let file = self.vfs.read().path2file(&path).ok_or_else(|| {
            // Show warning as this file is outside current workspace
            LspError {
                code: ErrorCode::InvalidRequest as i32,
                message: "Rust file outside current workspace is not supported yet.".to_string(),
            }
        })?;
        Ok(FileId(file.0))
    }

    pub fn file_id_to_uri(&self, id: FileId) -> Result<Url> {
        let path = self.vfs.read().file2path(VfsFile(id.0));
        let url = url_from_path_with_drive_lowercasing(path)?;

        Ok(url)
    }

    pub fn file_line_endings(&self, id: FileId) -> LineEndings {
        self.vfs.read().file_line_endings(VfsFile(id.0))
    }

    pub fn path_to_uri(&self, root: SourceRootId, path: &RelativePathBuf) -> Result<Url> {
        let base = self.vfs.read().root2path(VfsRoot(root.0));
        let path = path.to_path(base);
        let url = Url::from_file_path(&path)
            .map_err(|_| format!("can't convert path to url: {}", path.display()))?;
        Ok(url)
    }

    pub fn status(&self) -> String {
        let mut res = String::new();
        if self.workspaces.is_empty() {
            res.push_str("no workspaces\n")
        } else {
            res.push_str("workspaces:\n");
            for w in self.workspaces.iter() {
                res += &format!("{} packages loaded\n", w.n_packages());
            }
        }
        res.push_str("\nanalysis:\n");
        res.push_str(
            &self
                .analysis
                .status()
                .unwrap_or_else(|_| "Analysis retrieval was cancelled".to_owned()),
        );
        res
    }

    pub fn workspace_root_for(&self, file_id: FileId) -> Option<&Path> {
        let path = self.vfs.read().file2path(VfsFile(file_id.0));
        self.workspaces.iter().find_map(|ws| ws.workspace_root_for(&path))
    }

    pub fn feature_flags(&self) -> &FeatureFlags {
        self.analysis.feature_flags()
    }
}

/// Returns a `Url` object from a given path, will lowercase drive letters if present.
/// This will only happen when processing windows paths.
///
/// When processing non-windows path, this is essentially the same as `Url::from_file_path`.
fn url_from_path_with_drive_lowercasing(path: impl AsRef<Path>) -> Result<Url> {
    let component_has_windows_drive = path
        .as_ref()
        .components()
        .find(|comp| {
            if let Component::Prefix(c) = comp {
                match c.kind() {
                    Prefix::Disk(_) | Prefix::VerbatimDisk(_) => return true,
                    _ => return false,
                }
            }
            false
        })
        .is_some();

    // VSCode expects drive letters to be lowercased, where rust will uppercase the drive letters.
    if component_has_windows_drive {
        let url_original = Url::from_file_path(&path)
            .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?;

        let drive_partition: Vec<&str> =
            url_original.as_str().rsplitn(2, ':').collect::<Vec<&str>>();

        // There is a drive partition, but we never found a colon.
        // This should not happen, but in this case we just pass it through.
        if drive_partition.len() == 1 {
            return Ok(url_original);
        }

        let joined = drive_partition[1].to_ascii_lowercase() + ":" + drive_partition[0];
        let url = Url::from_str(&joined).expect("This came from a valid `Url`");

        Ok(url)
    } else {
        Ok(Url::from_file_path(&path)
            .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?)
    }
}

#[test]
fn test_lowercase_drive_letter_with_drive() {
    let url = url_from_path_with_drive_lowercasing("C:\\Test").unwrap();

    assert_eq!(url.to_string(), "file:///c:/Test");
}

#[test]
fn test_drive_without_colon_passthrough() {
    let url = url_from_path_with_drive_lowercasing(r#"\\localhost\C$\my_dir"#).unwrap();

    assert_eq!(url.to_string(), "file://localhost/C$/my_dir");
}
<|endoftext|>


<commit_before>use crate::{
    prelude::{verify::TxErr, Properties, SignedBlock, TxVariant},
    serializer::*,
};
use std::io::{self, Cursor, Error};

#[derive(Clone, Debug, PartialEq)]
pub enum RequestType {
    Batch(Vec<MsgRequest>),
    Single(MsgRequest),
}

impl RequestType {
    pub fn serialize(&self, buf: &mut Vec<u8>) {
        match self {
            RequestType::Batch(batch) => {
                buf.push(0);
                buf.push_u32(batch.len() as u32);
                for req in batch {
                    req.serialize(buf);
                }
            }
            RequestType::Single(req) => {
                buf.push(1);
                req.serialize(buf);
            }
        }
    }

    pub fn deserialize(cursor: &mut Cursor<&[u8]>) -> io::Result<Self> {
        let tag = cursor.take_u8()?;
        match tag {
            0 => {
                let len = cursor.take_u32()?;
                let mut batch = Vec::with_capacity(len as usize);
                for _ in 0..len {
                    batch.push(MsgRequest::deserialize(cursor)?);
                }
                Ok(RequestType::Batch(batch))
            }
            1 => Ok(RequestType::Single(MsgRequest::deserialize(cursor)?)),
            _ => {
                return Err(io::Error::new(
                    io::ErrorKind::InvalidData,
                    "failed to deserialize type",
                ))
            }
        }
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum ResponseType {
    Batch(Vec<MsgResponse>),
    Single(MsgResponse),
}

impl ResponseType {
    pub fn unwrap_batch(self) -> Vec<MsgResponse> {
        match self {
            ResponseType::Batch(batch) => batch,
            _ => panic!("expected batch response type"),
        }
    }

    pub fn unwrap_single(self) -> MsgResponse {
        match self {
            ResponseType::Single(res) => res,
            _ => panic!("expected single response type"),
        }
    }

    pub fn serialize(&self, buf: &mut Vec<u8>) {
        match self {
            ResponseType::Batch(batch) => {
                buf.push(0);
                buf.push_u32(batch.len() as u32);
                for res in batch {
                    res.serialize(buf);
                }
            }
            ResponseType::Single(res) => {
                buf.push(1);
                res.serialize(buf);
            }
        }
    }

    pub fn deserialize(cursor: &mut Cursor<&[u8]>) -> io::Result<Self> {
        let tag = cursor.take_u8()?;
        match tag {
            0 => {
                let len = cursor.take_u32()?;
                let mut batch = Vec::with_capacity(len as usize);
                for _ in 0..len {
                    batch.push(MsgResponse::deserialize(cursor)?);
                }
                Ok(ResponseType::Batch(batch))
            }
            1 => Ok(ResponseType::Single(MsgResponse::deserialize(cursor)?)),
            _ => {
                return Err(io::Error::new(
                    io::ErrorKind::InvalidData,
                    "failed to deserialize type",
                ))
            }
        }
    }
}

#[repr(u8)]
pub enum MsgType {
    Error = 0,
    GetProperties = 1,
    GetBlock = 2,
    Broadcast = 3,
}

#[derive(Clone, Debug, PartialEq)]
pub enum MsgRequest {
    GetProperties,
    GetBlock(u64), // height
    Broadcast(TxVariant),
}

impl MsgRequest {
    pub fn serialize(&self, buf: &mut Vec<u8>) {
        match self {
            MsgRequest::GetProperties => buf.push(MsgType::GetProperties as u8),
            MsgRequest::GetBlock(height) => {
                buf.reserve_exact(9);
                buf.push(MsgType::GetBlock as u8);
                buf.push_u64(*height);
            }
            MsgRequest::Broadcast(tx) => {
                buf.reserve_exact(4096);
                buf.push(MsgType::Broadcast as u8);
                tx.serialize(buf);
            }
        }
    }

    pub fn deserialize(cursor: &mut Cursor<&[u8]>) -> io::Result<Self> {
        let tag = cursor.take_u8()?;
        match tag {
            t if t == MsgType::GetProperties as u8 => Ok(MsgRequest::GetProperties),
            t if t == MsgType::GetBlock as u8 => {
                let height = cursor.take_u64()?;
                Ok(MsgRequest::GetBlock(height))
            }
            t if t == MsgType::Broadcast as u8 => {
                let tx = TxVariant::deserialize(cursor)
                    .ok_or_else(|| Error::new(io::ErrorKind::InvalidData, "failed to decode tx"))?;
                Ok(MsgRequest::Broadcast(tx))
            }
            _ => Err(Error::new(
                io::ErrorKind::InvalidData,
                "invalid msg request",
            )),
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ErrorKind {
    Io,
    InvalidHeight,
    TxValidation(TxErr),
}

impl ErrorKind {
    fn serialize(self, buf: &mut Vec<u8>) {
        match self {
            ErrorKind::Io => buf.push(0),
            ErrorKind::InvalidHeight => buf.push(1),
            ErrorKind::TxValidation(err) => {
                buf.push(2);
                err.serialize(buf);
            }
        }
    }

    fn deserialize(cursor: &mut Cursor<&[u8]>) -> io::Result<Self> {
        let tag = cursor.take_u8()?;
        Ok(match tag {
            0 => ErrorKind::Io,
            1 => ErrorKind::InvalidHeight,
            2 => ErrorKind::TxValidation(TxErr::deserialize(cursor)?),
            _ => {
                return Err(io::Error::new(
                    io::ErrorKind::InvalidData,
                    "failed to deserialize ErrorKind",
                ))
            }
        })
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum MsgResponse {
    Error(ErrorKind),
    GetProperties(Properties),
    GetBlock(SignedBlock),
    Broadcast(),
}

impl MsgResponse {
    pub fn is_err(&self) -> bool {
        match self {
            MsgResponse::Error(..) => true,
            _ => false,
        }
    }

    pub fn serialize(&self, buf: &mut Vec<u8>) {
        use std::mem;

        match self {
            MsgResponse::Error(err) => {
                buf.reserve_exact(2048);
                buf.push(MsgType::Error as u8);
                err.serialize(buf);
            }
            MsgResponse::GetProperties(props) => {
                buf.reserve_exact(4096 + mem::size_of::<Properties>());
                buf.push(MsgType::GetProperties as u8);
                buf.push_u64(props.height);
                {
                    let mut tx_buf = Vec::with_capacity(4096);
                    TxVariant::OwnerTx(props.owner.as_ref().clone()).serialize(&mut tx_buf);
                    buf.extend_from_slice(&tx_buf);
                }
                buf.push_asset(props.network_fee);
                buf.push_asset(props.token_supply);
            }
            MsgResponse::GetBlock(block) => {
                buf.reserve_exact(1_048_576);
                buf.push(MsgType::GetBlock as u8);
                block.serialize_with_tx(buf);
            }
            MsgResponse::Broadcast() => buf.push(MsgType::Broadcast as u8),
        }
    }

    pub fn deserialize(cursor: &mut Cursor<&[u8]>) -> io::Result<Self> {
        let tag = cursor.take_u8()?;
        match tag {
            t if t == MsgType::Error as u8 => {
                let err = ErrorKind::deserialize(cursor)?;
                Ok(MsgResponse::Error(err))
            }
            t if t == MsgType::GetProperties as u8 => {
                let height = cursor.take_u64()?;
                let owner = {
                    let var = TxVariant::deserialize(cursor).ok_or_else(|| {
                        Error::new(io::ErrorKind::InvalidData, "failed to deserialize owner tx")
                    })?;
                    match var {
                        TxVariant::OwnerTx(tx) => Box::new(tx),
                        _ => {
                            return Err(Error::new(io::ErrorKind::InvalidData, "expected owner tx"))
                        }
                    }
                };
                let network_fee = cursor.take_asset()?;
                let token_supply = cursor.take_asset()?;
                Ok(MsgResponse::GetProperties(Properties {
                    height,
                    owner,
                    network_fee,
                    token_supply,
                }))
            }
            t if t == MsgType::GetBlock as u8 => {
                let block = SignedBlock::deserialize_with_tx(cursor)
                    .ok_or_else(|| Error::from(io::ErrorKind::UnexpectedEof))?;
                Ok(MsgResponse::GetBlock(block))
            }
            _ => Err(Error::new(
                io::ErrorKind::InvalidData,
                "invalid msg response",
            )),
        }
    }
}
<commit_msg>Deserialize broadcast message responses<commit_after>use crate::{
    prelude::{verify::TxErr, Properties, SignedBlock, TxVariant},
    serializer::*,
};
use std::io::{self, Cursor, Error};

#[derive(Clone, Debug, PartialEq)]
pub enum RequestType {
    Batch(Vec<MsgRequest>),
    Single(MsgRequest),
}

impl RequestType {
    pub fn serialize(&self, buf: &mut Vec<u8>) {
        match self {
            RequestType::Batch(batch) => {
                buf.push(0);
                buf.push_u32(batch.len() as u32);
                for req in batch {
                    req.serialize(buf);
                }
            }
            RequestType::Single(req) => {
                buf.push(1);
                req.serialize(buf);
            }
        }
    }

    pub fn deserialize(cursor: &mut Cursor<&[u8]>) -> io::Result<Self> {
        let tag = cursor.take_u8()?;
        match tag {
            0 => {
                let len = cursor.take_u32()?;
                let mut batch = Vec::with_capacity(len as usize);
                for _ in 0..len {
                    batch.push(MsgRequest::deserialize(cursor)?);
                }
                Ok(RequestType::Batch(batch))
            }
            1 => Ok(RequestType::Single(MsgRequest::deserialize(cursor)?)),
            _ => {
                return Err(io::Error::new(
                    io::ErrorKind::InvalidData,
                    "failed to deserialize type",
                ))
            }
        }
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum ResponseType {
    Batch(Vec<MsgResponse>),
    Single(MsgResponse),
}

impl ResponseType {
    pub fn unwrap_batch(self) -> Vec<MsgResponse> {
        match self {
            ResponseType::Batch(batch) => batch,
            _ => panic!("expected batch response type"),
        }
    }

    pub fn unwrap_single(self) -> MsgResponse {
        match self {
            ResponseType::Single(res) => res,
            _ => panic!("expected single response type"),
        }
    }

    pub fn serialize(&self, buf: &mut Vec<u8>) {
        match self {
            ResponseType::Batch(batch) => {
                buf.push(0);
                buf.push_u32(batch.len() as u32);
                for res in batch {
                    res.serialize(buf);
                }
            }
            ResponseType::Single(res) => {
                buf.push(1);
                res.serialize(buf);
            }
        }
    }

    pub fn deserialize(cursor: &mut Cursor<&[u8]>) -> io::Result<Self> {
        let tag = cursor.take_u8()?;
        match tag {
            0 => {
                let len = cursor.take_u32()?;
                let mut batch = Vec::with_capacity(len as usize);
                for _ in 0..len {
                    batch.push(MsgResponse::deserialize(cursor)?);
                }
                Ok(ResponseType::Batch(batch))
            }
            1 => Ok(ResponseType::Single(MsgResponse::deserialize(cursor)?)),
            _ => {
                return Err(io::Error::new(
                    io::ErrorKind::InvalidData,
                    "failed to deserialize type",
                ))
            }
        }
    }
}

#[repr(u8)]
pub enum MsgType {
    Error = 0,
    GetProperties = 1,
    GetBlock = 2,
    Broadcast = 3,
}

#[derive(Clone, Debug, PartialEq)]
pub enum MsgRequest {
    GetProperties,
    GetBlock(u64), // height
    Broadcast(TxVariant),
}

impl MsgRequest {
    pub fn serialize(&self, buf: &mut Vec<u8>) {
        match self {
            MsgRequest::GetProperties => buf.push(MsgType::GetProperties as u8),
            MsgRequest::GetBlock(height) => {
                buf.reserve_exact(9);
                buf.push(MsgType::GetBlock as u8);
                buf.push_u64(*height);
            }
            MsgRequest::Broadcast(tx) => {
                buf.reserve_exact(4096);
                buf.push(MsgType::Broadcast as u8);
                tx.serialize(buf);
            }
        }
    }

    pub fn deserialize(cursor: &mut Cursor<&[u8]>) -> io::Result<Self> {
        let tag = cursor.take_u8()?;
        match tag {
            t if t == MsgType::GetProperties as u8 => Ok(MsgRequest::GetProperties),
            t if t == MsgType::GetBlock as u8 => {
                let height = cursor.take_u64()?;
                Ok(MsgRequest::GetBlock(height))
            }
            t if t == MsgType::Broadcast as u8 => {
                let tx = TxVariant::deserialize(cursor)
                    .ok_or_else(|| Error::new(io::ErrorKind::InvalidData, "failed to decode tx"))?;
                Ok(MsgRequest::Broadcast(tx))
            }
            _ => Err(Error::new(
                io::ErrorKind::InvalidData,
                "invalid msg request",
            )),
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ErrorKind {
    Io,
    InvalidHeight,
    TxValidation(TxErr),
}

impl ErrorKind {
    fn serialize(self, buf: &mut Vec<u8>) {
        match self {
            ErrorKind::Io => buf.push(0),
            ErrorKind::InvalidHeight => buf.push(1),
            ErrorKind::TxValidation(err) => {
                buf.push(2);
                err.serialize(buf);
            }
        }
    }

    fn deserialize(cursor: &mut Cursor<&[u8]>) -> io::Result<Self> {
        let tag = cursor.take_u8()?;
        Ok(match tag {
            0 => ErrorKind::Io,
            1 => ErrorKind::InvalidHeight,
            2 => ErrorKind::TxValidation(TxErr::deserialize(cursor)?),
            _ => {
                return Err(io::Error::new(
                    io::ErrorKind::InvalidData,
                    "failed to deserialize ErrorKind",
                ))
            }
        })
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum MsgResponse {
    Error(ErrorKind),
    GetProperties(Properties),
    GetBlock(SignedBlock),
    Broadcast(),
}

impl MsgResponse {
    pub fn is_err(&self) -> bool {
        match self {
            MsgResponse::Error(..) => true,
            _ => false,
        }
    }

    pub fn serialize(&self, buf: &mut Vec<u8>) {
        use std::mem;

        match self {
            MsgResponse::Error(err) => {
                buf.reserve_exact(2048);
                buf.push(MsgType::Error as u8);
                err.serialize(buf);
            }
            MsgResponse::GetProperties(props) => {
                buf.reserve_exact(4096 + mem::size_of::<Properties>());
                buf.push(MsgType::GetProperties as u8);
                buf.push_u64(props.height);
                {
                    let mut tx_buf = Vec::with_capacity(4096);
                    TxVariant::OwnerTx(props.owner.as_ref().clone()).serialize(&mut tx_buf);
                    buf.extend_from_slice(&tx_buf);
                }
                buf.push_asset(props.network_fee);
                buf.push_asset(props.token_supply);
            }
            MsgResponse::GetBlock(block) => {
                buf.reserve_exact(1_048_576);
                buf.push(MsgType::GetBlock as u8);
                block.serialize_with_tx(buf);
            }
            MsgResponse::Broadcast() => buf.push(MsgType::Broadcast as u8),
        }
    }

    pub fn deserialize(cursor: &mut Cursor<&[u8]>) -> io::Result<Self> {
        let tag = cursor.take_u8()?;
        match tag {
            t if t == MsgType::Error as u8 => {
                let err = ErrorKind::deserialize(cursor)?;
                Ok(MsgResponse::Error(err))
            }
            t if t == MsgType::GetProperties as u8 => {
                let height = cursor.take_u64()?;
                let owner = {
                    let var = TxVariant::deserialize(cursor).ok_or_else(|| {
                        Error::new(io::ErrorKind::InvalidData, "failed to deserialize owner tx")
                    })?;
                    match var {
                        TxVariant::OwnerTx(tx) => Box::new(tx),
                        _ => {
                            return Err(Error::new(io::ErrorKind::InvalidData, "expected owner tx"))
                        }
                    }
                };
                let network_fee = cursor.take_asset()?;
                let token_supply = cursor.take_asset()?;
                Ok(MsgResponse::GetProperties(Properties {
                    height,
                    owner,
                    network_fee,
                    token_supply,
                }))
            }
            t if t == MsgType::GetBlock as u8 => {
                let block = SignedBlock::deserialize_with_tx(cursor)
                    .ok_or_else(|| Error::from(io::ErrorKind::UnexpectedEof))?;
                Ok(MsgResponse::GetBlock(block))
            }
            t if t == MsgType::Broadcast as u8 => Ok(MsgResponse::Broadcast()),
            _ => Err(Error::new(
                io::ErrorKind::InvalidData,
                "invalid msg response",
            )),
        }
    }
}
<|endoftext|>


<commit_before>use godcoin::{constants::MAX_TX_SIGNATURES, prelude::*};

pub mod minter;
pub use minter::*;

pub fn get_asset(grael: &str) -> Asset {
    grael.parse().unwrap()
}

pub fn create_tx_header(fee: &str) -> Tx {
    let expiry = godcoin::get_epoch_time() + 1;
    create_tx_header_with_expiry(fee, expiry)
}

pub fn create_tx_header_with_expiry(fee: &str, expiry: u64) -> Tx {
    let nonce: u32 = {
        let mut nonce = [0; 4];
        sodiumoxide::randombytes::randombytes_into(&mut nonce);
        u32::from_ne_bytes(nonce)
    };
    Tx {
        nonce,
        expiry,
        fee: fee.parse().unwrap(),
        signature_pairs: Vec::with_capacity(MAX_TX_SIGNATURES),
    }
}

pub fn check_sigs(tx: &TxVariant) -> bool {
    let mut buf = Vec::with_capacity(4096);
    tx.serialize_without_sigs(&mut buf);
    for sig_pair in tx.sigs() {
        if !sig_pair.verify(&buf) {
            return false;
        }
    }

    true
}
<commit_msg>Increase default expiry time for integration tests<commit_after>use godcoin::{constants::MAX_TX_SIGNATURES, prelude::*};

pub mod minter;
pub use minter::*;

pub fn get_asset(grael: &str) -> Asset {
    grael.parse().unwrap()
}

pub fn create_tx_header(fee: &str) -> Tx {
    let expiry = godcoin::get_epoch_time() + 30;
    create_tx_header_with_expiry(fee, expiry)
}

pub fn create_tx_header_with_expiry(fee: &str, expiry: u64) -> Tx {
    let nonce: u32 = {
        let mut nonce = [0; 4];
        sodiumoxide::randombytes::randombytes_into(&mut nonce);
        u32::from_ne_bytes(nonce)
    };
    Tx {
        nonce,
        expiry,
        fee: fee.parse().unwrap(),
        signature_pairs: Vec::with_capacity(MAX_TX_SIGNATURES),
    }
}

pub fn check_sigs(tx: &TxVariant) -> bool {
    let mut buf = Vec::with_capacity(4096);
    tx.serialize_without_sigs(&mut buf);
    for sig_pair in tx.sigs() {
        if !sig_pair.verify(&buf) {
            return false;
        }
    }

    true
}
<|endoftext|>