<commit_before>use crate::common::*;
use crate::data::packet::Packet;
use crate::data::value::*;
use std::any::Any;
use std::io::{ErrorKind, Seek, SeekFrom, Write};
use std::sync::Arc;

use crate::error::*;

pub trait WriteOwned: Write + ToOwned {}
pub trait WriteSeek: Write + Seek + ToOwned {}

impl<T: Write + ToOwned> WriteOwned for T {}
impl<T: Write + Seek + ToOwned> WriteSeek for T {}

/// Runtime wrapper around either a [`Write`] or a [`WriteSeek`] trait object which supports querying
/// for seek support.
pub enum Writer<WO: WriteOwned, WS: WriteSeek> {
    NonSeekable(WO, u64),
    Seekable(WS),
}

impl<WO: WriteOwned, WS: WriteSeek> Writer<WO, WS> {
    /// Creates a [`Writer`] from an object that implements both [`Write`] and [`Seek`] traits.
    pub fn from_seekable(inner: WS) -> Self {
        Self::Seekable(inner)
    }

    /// Creates a [`Writer`] from an object that implements the [`Write`] trait.
    pub fn from_nonseekable(inner: WO) -> Self {
        Self::NonSeekable(inner, 0)
    }

    /// Returns whether the [`Writer`] can seek within the source.
    pub fn can_seek(&self) -> bool {
        matches!(self, Self::Seekable(_))
    }

    /// Returns the non-seekable object whether is present.
    pub fn non_seekable_object(&self) -> Option<(<WO as ToOwned>::Owned, u64)> {
        if let Self::NonSeekable(inner, index) = self {
            Some((inner.to_owned(), *index))
        } else {
            None
        }
    }

    /// Returns the seekable object whether is present.
    pub fn seekable_object(&self) -> Option<<WS as ToOwned>::Owned> {
        if let Self::Seekable(inner) = self {
            Some(inner.to_owned())
        } else {
            None
        }
    }
}

impl<WO: WriteOwned, WS: WriteSeek> Write for Writer<WO, WS> {
    fn write(&mut self, bytes: &[u8]) -> std::io::Result<usize> {
        match self {
            Self::NonSeekable(inner, ref mut index) => {
                let result = inner.write(bytes);

                if let Ok(written) = result {
                    *index += written as u64;
                }

                result
            }
            Self::Seekable(inner) => inner.write(bytes),
        }
    }

    fn flush(&mut self) -> std::io::Result<()> {
        match self {
            Self::NonSeekable(inner, ..) => inner.flush(),
            Self::Seekable(inner) => inner.flush(),
        }
    }
}

impl<WO: WriteOwned, WS: WriteSeek> Seek for Writer<WO, WS> {
    fn seek(&mut self, seek: SeekFrom) -> std::io::Result<u64> {
        match self {
            Self::NonSeekable(_, index) => {
                if let SeekFrom::Current(0) = seek {
                    Ok(*index)
                } else {
                    Err(std::io::Error::new(
                        ErrorKind::Other,
                        "Seeking not supported",
                    ))
                }
            }
            Self::Seekable(inner) => inner.seek(seek),
        }
    }
}

/// Used to implement muxing operations.
pub trait Muxer: Send {
    /// Configures a muxer.
    fn configure(&mut self) -> Result<()>;
    /// Writes a stream header into a data structure implementing
    /// the `Write` trait.
    fn write_header<WO: WriteOwned, WS: WriteSeek>(
        &mut self,
        out: &mut Writer<WO, WS>,
    ) -> Result<()>;
    /// Writes a stream packet into a data structure implementing
    /// the `Write` trait.
    fn write_packet<WO: WriteOwned, WS: WriteSeek>(
        &mut self,
        out: &mut Writer<WO, WS>,
        pkt: Arc<Packet>,
    ) -> Result<()>;
    /// Writes a stream trailer into a data structure implementing
    /// the `Write` trait.
    fn write_trailer<WO: WriteOwned, WS: WriteSeek>(
        &mut self,
        out: &mut Writer<WO, WS>,
    ) -> Result<()>;

    /// Sets global media file information for a muxer.
    fn set_global_info(&mut self, info: GlobalInfo) -> Result<()>;
    /// Sets a muxer option.
    ///
    /// This method should be called as many times as the number of options
    /// present in a muxer.
    fn set_option<'a>(&mut self, key: &str, val: Value<'a>) -> Result<()>;
}

/// Auxiliary structure to encapsulate a muxer object and
/// its additional data.
pub struct Context<M: Muxer + Send, WO: WriteOwned, WS: WriteSeek> {
    muxer: M,
    writer: Writer<WO, WS>,
    /// User private data.
    ///
    /// This data cannot be cloned.
    pub user_private: Option<Box<dyn Any + Send + Sync>>,
}

impl<M: Muxer + Send, WO: WriteOwned, WS: WriteSeek> Context<M, WO, WS> {
    /// Creates a new `Context` instance.
    pub fn new(muxer: M, writer: Writer<WO, WS>) -> Self {
        Context {
            muxer,
            writer,
            user_private: None,
        }
    }

    /// Configures a muxer.
    pub fn configure(&mut self) -> Result<()> {
        self.muxer.configure()
    }

    /// Writes a stream header to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_header(&mut self) -> Result<()> {
        self.muxer.write_header(&mut self.writer)
    }

    /// Writes a stream packet to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_packet(&mut self, pkt: Arc<Packet>) -> Result<()> {
        self.muxer.write_packet(&mut self.writer, pkt)
    }

    /// Writes a stream trailer to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_trailer(&mut self) -> Result<()> {
        self.muxer.write_trailer(&mut self.writer)?;
        self.writer.flush()?;

        Ok(())
    }

    /// Sets global media file information for a muxer.
    pub fn set_global_info(&mut self, info: GlobalInfo) -> Result<()> {
        self.muxer.set_global_info(info)
    }

    /// Sets a muxer option.
    ///
    /// This method should be called as many times as the number of options
    /// present in a muxer.
    pub fn set_option<'a, V>(&mut self, key: &str, val: V) -> Result<()>
    where
        V: Into<Value<'a>>,
    {
        self.muxer.set_option(key, val.into())
    }

    /// Returns the underlying writer.
    pub fn writer(&self) -> &Writer<WO, WS> {
        &self.writer
    }
}

/// Format descriptor.
///
/// Contains information on a format and its own muxer.
#[derive(Clone, Debug, PartialEq)]
pub struct Descr {
    /// Format name.
    pub name: &'static str,
    /// Muxer name.
    pub demuxer: &'static str,
    /// Format description.
    pub description: &'static str,
    /// Format media file extensions.
    pub extensions: &'static [&'static str],
    /// Format MIME.
    pub mime: &'static [&'static str],
}

/// Used to get a format descriptor and create a new muxer.
pub trait Descriptor {
    type OutputMuxer: Muxer + Send;

    /// Creates a new muxer for the requested format.
    fn create(&self) -> Self::OutputMuxer;
    /// Returns the descriptor of a format.
    fn describe(&self) -> &Descr;
}

/// Used to look for a specific format.
pub trait Lookup<T: Descriptor + ?Sized> {
    /// Retrieves a specific format by name.
    fn by_name(&self, name: &str) -> Option<&'static T>;
}

impl<T: Descriptor + ?Sized> Lookup<T> for [&'static T] {
    fn by_name(&self, name: &str) -> Option<&'static T> {
        self.iter().find(|&&d| d.describe().name == name).copied()
    }
}
<commit_msg>format: Add muxer tests<commit_after>use crate::common::*;
use crate::data::packet::Packet;
use crate::data::value::*;
use std::any::Any;
use std::io::{ErrorKind, Seek, SeekFrom, Write};
use std::sync::Arc;

use crate::error::*;

pub trait WriteOwned: Write + ToOwned {}
pub trait WriteSeek: Write + Seek + ToOwned {}

impl<T: Write + ToOwned> WriteOwned for T {}
impl<T: Write + Seek + ToOwned> WriteSeek for T {}

/// Runtime wrapper around either a [`Write`] or a [`WriteSeek`] trait object which supports querying
/// for seek support.
pub enum Writer<WO: WriteOwned, WS: WriteSeek> {
    NonSeekable(WO, u64),
    Seekable(WS),
}

impl<WO: WriteOwned, WS: WriteSeek> Writer<WO, WS> {
    /// Creates a [`Writer`] from an object that implements both [`Write`] and [`Seek`] traits.
    pub fn from_seekable(inner: WS) -> Self {
        Self::Seekable(inner)
    }

    /// Creates a [`Writer`] from an object that implements the [`Write`] trait.
    pub fn from_nonseekable(inner: WO) -> Self {
        Self::NonSeekable(inner, 0)
    }

    /// Returns whether the [`Writer`] can seek within the source.
    pub fn can_seek(&self) -> bool {
        matches!(self, Self::Seekable(_))
    }

    /// Returns the non-seekable object whether is present.
    pub fn non_seekable_object(&self) -> Option<(<WO as ToOwned>::Owned, u64)> {
        if let Self::NonSeekable(inner, index) = self {
            Some((inner.to_owned(), *index))
        } else {
            None
        }
    }

    /// Returns the seekable object whether is present.
    pub fn seekable_object(&self) -> Option<<WS as ToOwned>::Owned> {
        if let Self::Seekable(inner) = self {
            Some(inner.to_owned())
        } else {
            None
        }
    }
}

impl<WO: WriteOwned, WS: WriteSeek> Write for Writer<WO, WS> {
    fn write(&mut self, bytes: &[u8]) -> std::io::Result<usize> {
        match self {
            Self::NonSeekable(inner, ref mut index) => {
                let result = inner.write(bytes);

                if let Ok(written) = result {
                    *index += written as u64;
                }

                result
            }
            Self::Seekable(inner) => inner.write(bytes),
        }
    }

    fn flush(&mut self) -> std::io::Result<()> {
        match self {
            Self::NonSeekable(inner, ..) => inner.flush(),
            Self::Seekable(inner) => inner.flush(),
        }
    }
}

impl<WO: WriteOwned, WS: WriteSeek> Seek for Writer<WO, WS> {
    fn seek(&mut self, seek: SeekFrom) -> std::io::Result<u64> {
        match self {
            Self::NonSeekable(_, index) => {
                if let SeekFrom::Current(0) = seek {
                    Ok(*index)
                } else {
                    Err(std::io::Error::new(
                        ErrorKind::Other,
                        "Seeking not supported",
                    ))
                }
            }
            Self::Seekable(inner) => inner.seek(seek),
        }
    }
}

/// Used to implement muxing operations.
pub trait Muxer: Send {
    /// Configures a muxer.
    fn configure(&mut self) -> Result<()>;
    /// Writes a stream header into a data structure implementing
    /// the `Write` trait.
    fn write_header<WO: WriteOwned, WS: WriteSeek>(
        &mut self,
        out: &mut Writer<WO, WS>,
    ) -> Result<()>;
    /// Writes a stream packet into a data structure implementing
    /// the `Write` trait.
    fn write_packet<WO: WriteOwned, WS: WriteSeek>(
        &mut self,
        out: &mut Writer<WO, WS>,
        pkt: Arc<Packet>,
    ) -> Result<()>;
    /// Writes a stream trailer into a data structure implementing
    /// the `Write` trait.
    fn write_trailer<WO: WriteOwned, WS: WriteSeek>(
        &mut self,
        out: &mut Writer<WO, WS>,
    ) -> Result<()>;

    /// Sets global media file information for a muxer.
    fn set_global_info(&mut self, info: GlobalInfo) -> Result<()>;
    /// Sets a muxer option.
    ///
    /// This method should be called as many times as the number of options
    /// present in a muxer.
    fn set_option<'a>(&mut self, key: &str, val: Value<'a>) -> Result<()>;
}

/// Auxiliary structure to encapsulate a muxer object and
/// its additional data.
pub struct Context<M: Muxer + Send, WO: WriteOwned, WS: WriteSeek> {
    muxer: M,
    writer: Writer<WO, WS>,
    /// User private data.
    ///
    /// This data cannot be cloned.
    pub user_private: Option<Box<dyn Any + Send + Sync>>,
}

impl<M: Muxer + Send, WO: WriteOwned, WS: WriteSeek> Context<M, WO, WS> {
    /// Creates a new `Context` instance.
    pub fn new(muxer: M, writer: Writer<WO, WS>) -> Self {
        Context {
            muxer,
            writer,
            user_private: None,
        }
    }

    /// Configures a muxer.
    pub fn configure(&mut self) -> Result<()> {
        self.muxer.configure()
    }

    /// Writes a stream header to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_header(&mut self) -> Result<()> {
        self.muxer.write_header(&mut self.writer)
    }

    /// Writes a stream packet to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_packet(&mut self, pkt: Arc<Packet>) -> Result<()> {
        self.muxer.write_packet(&mut self.writer, pkt)
    }

    /// Writes a stream trailer to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_trailer(&mut self) -> Result<()> {
        self.muxer.write_trailer(&mut self.writer)?;
        self.writer.flush()?;

        Ok(())
    }

    /// Sets global media file information for a muxer.
    pub fn set_global_info(&mut self, info: GlobalInfo) -> Result<()> {
        self.muxer.set_global_info(info)
    }

    /// Sets a muxer option.
    ///
    /// This method should be called as many times as the number of options
    /// present in a muxer.
    pub fn set_option<'a, V>(&mut self, key: &str, val: V) -> Result<()>
    where
        V: Into<Value<'a>>,
    {
        self.muxer.set_option(key, val.into())
    }

    /// Returns the underlying writer.
    pub fn writer(&self) -> &Writer<WO, WS> {
        &self.writer
    }
}

/// Format descriptor.
///
/// Contains information on a format and its own muxer.
#[derive(Clone, Debug, PartialEq)]
pub struct Descr {
    /// Format name.
    pub name: &'static str,
    /// Muxer name.
    pub demuxer: &'static str,
    /// Format description.
    pub description: &'static str,
    /// Format media file extensions.
    pub extensions: &'static [&'static str],
    /// Format MIME.
    pub mime: &'static [&'static str],
}

/// Used to get a format descriptor and create a new muxer.
pub trait Descriptor {
    type OutputMuxer: Muxer + Send;

    /// Creates a new muxer for the requested format.
    fn create(&self) -> Self::OutputMuxer;
    /// Returns the descriptor of a format.
    fn describe(&self) -> &Descr;
}

/// Used to look for a specific format.
pub trait Lookup<T: Descriptor + ?Sized> {
    /// Retrieves a specific format by name.
    fn by_name(&self, name: &str) -> Option<&'static T>;
}

impl<T: Descriptor + ?Sized> Lookup<T> for [&'static T] {
    fn by_name(&self, name: &str) -> Option<&'static T> {
        self.iter().find(|&&d| d.describe().name == name).copied()
    }
}

#[cfg(test)]
mod test {
    use std::io::Cursor;

    use super::*;

    struct DummyDes {
        d: Descr,
    }

    struct DummyMuxer {}

    impl DummyMuxer {
        pub fn new() -> Self {
            Self {}
        }
    }

    impl Muxer for DummyMuxer {
        fn configure(&mut self) -> Result<()> {
            Ok(())
        }

        fn write_header<WO: WriteOwned, WS: WriteSeek>(
            &mut self,
            out: &mut Writer<WO, WS>,
        ) -> Result<()> {
            let buf = b"Dummy header";
            out.write_all(buf.as_slice()).unwrap();
            Ok(())
        }

        fn write_packet<WO: WriteOwned, WS: WriteSeek>(
            &mut self,
            out: &mut Writer<WO, WS>,
            pkt: Arc<Packet>,
        ) -> Result<()> {
            out.write_all(&pkt.data).unwrap();
            Ok(())
        }

        fn write_trailer<WO: WriteOwned, WS: WriteSeek>(
            &mut self,
            out: &mut Writer<WO, WS>,
        ) -> Result<()> {
            let buf = b"Dummy trailer";
            out.write_all(buf.as_slice()).unwrap();
            Ok(())
        }

        fn set_global_info(&mut self, _info: GlobalInfo) -> Result<()> {
            Ok(())
        }

        fn set_option<'a>(&mut self, _key: &str, _val: Value<'a>) -> Result<()> {
            Ok(())
        }
    }

    impl Descriptor for DummyDes {
        type OutputMuxer = DummyMuxer;

        fn create(&self) -> Self::OutputMuxer {
            DummyMuxer {}
        }
        fn describe(&self) -> &Descr {
            &self.d
        }
    }

    const DUMMY_DES: &dyn Descriptor<OutputMuxer = DummyMuxer> = &DummyDes {
        d: Descr {
            name: "dummy",
            demuxer: "dummy",
            description: "Dummy mux",
            extensions: &["mx", "mux"],
            mime: &["application/dummy"],
        },
    };

    #[test]
    fn lookup() {
        let muxers: &[&dyn Descriptor<OutputMuxer = DummyMuxer>] = &[DUMMY_DES];

        muxers.by_name("dummy").unwrap();
    }

    #[test]
    fn write_header() {
        let mux = DummyMuxer::new();
        let writer: Writer<Cursor<Vec<u8>>, Cursor<Vec<u8>>> =
            Writer::from_seekable(Cursor::new(Vec::new()));

        let mut muxer = Context::new(mux, writer);
        muxer.configure().unwrap();
        muxer.write_header().unwrap();
    }
}
<|endoftext|>


<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 fnv::{FnvHashMap, FnvHashSet};
use graphql_syntax::*;
use interner::StringKey;

pub struct ReachableAst {
    /// The definitions that need to be compiled, includes the project
    /// definitions plus the fragment definitions in the base definitions
    /// reachable from the project definitions.
    pub definitions: Vec<ExecutableDefinition>,
    /// The fragment names added from the base definitions.
    pub base_fragment_names: FnvHashSet<StringKey>,
}

/// Get all definitions that reachable from project defintions
pub fn get_reachable_ast(
    project_definitions: Vec<ExecutableDefinition>,
    base_definitions: Vec<ExecutableDefinition>,
) -> ReachableAst {
    if base_definitions.is_empty() {
        return ReachableAst {
            definitions: project_definitions,
            base_fragment_names: FnvHashSet::default(),
        };
    }

    let mut reachable_base_asts = FnvHashSet::default();
    let mut base_definitions_map = FnvHashMap::default();

    // Preprocess all base fragment definitions
    // Skipping operations because project definitions can't reference base operations
    for base_definition in base_definitions {
        match &base_definition {
            ExecutableDefinition::Fragment(fragment) => {
                let name = fragment.name.value;
                assert!(
                    base_definitions_map.insert(name, base_definition).is_none(),
                    "get_reachable_ast called on graph with duplicate definition of `{}`",
                    name
                )
            }
            ExecutableDefinition::Operation(_) => {}
        }
    }

    let mut result = project_definitions.clone();

    // Find references from project definitions -> base definitions
    for definition in project_definitions {
        let selections = match definition {
            ExecutableDefinition::Operation(definition) => definition.selections,
            ExecutableDefinition::Fragment(definition) => definition.selections,
        };
        visit_selections(
            &base_definitions_map,
            &mut reachable_base_asts,
            &selections,
            false,
        )
    }

    for key in &reachable_base_asts {
        let value = base_definitions_map.remove(key).unwrap();
        result.push(value);
    }

    ReachableAst {
        definitions: result,
        base_fragment_names: reachable_base_asts,
    }
}

/// Get fragment references of each definition
pub fn get_definition_references<'a>(
    definitions: impl IntoIterator<Item = &'a ExecutableDefinition>,
) -> FnvHashMap<StringKey, FnvHashSet<StringKey>> {
    let mut result = FnvHashMap::default();
    for definition in definitions {
        let name = definition.name().expect("Expect a name on an operation");
        let mut selections: Vec<_> = match definition {
            ExecutableDefinition::Operation(definition) => &definition.selections.items,
            ExecutableDefinition::Fragment(definition) => &definition.selections.items,
        }
        .iter()
        .collect();
        let mut references = FnvHashSet::default();
        loop {
            let selection = selections.pop();
            if let Some(selection) = selection {
                match selection {
                    Selection::FragmentSpread(selection) => {
                        references.insert(selection.name.value);
                    }
                    Selection::LinkedField(selection) => {
                        selections.extend(selection.selections.items.iter());
                    }
                    Selection::InlineFragment(selection) => {
                        selections.extend(selection.selections.items.iter());
                    }
                    Selection::ScalarField(_) => {}
                }
            } else {
                break;
            }
        }
        result.insert(name, references);
    }
    result
}

fn visit_selections(
    base_definitions_map: &FnvHashMap<StringKey, ExecutableDefinition>,
    reachable_base_asts: &mut FnvHashSet<StringKey>,
    selections: &List<Selection>,
    is_base: bool,
) {
    for selection in &selections.items {
        match selection {
            Selection::FragmentSpread(selection) => {
                if is_base || base_definitions_map.contains_key(&selection.name.value) {
                    traverse_base_ast_definition(
                        base_definitions_map,
                        reachable_base_asts,
                        selection.name.value,
                    )
                }
            }
            Selection::LinkedField(selection) => visit_selections(
                base_definitions_map,
                reachable_base_asts,
                &selection.selections,
                is_base,
            ),
            Selection::InlineFragment(selection) => visit_selections(
                base_definitions_map,
                reachable_base_asts,
                &selection.selections,
                is_base,
            ),
            Selection::ScalarField(_) => {}
        }
    }
}

fn traverse_base_ast_definition(
    base_definitions_map: &FnvHashMap<StringKey, ExecutableDefinition>,
    reachable_base_asts: &mut FnvHashSet<StringKey>,
    key: StringKey,
) {
    if reachable_base_asts.contains(&key) {
        return;
    }
    if let Some(base_definition) = base_definitions_map.get(&key) {
        reachable_base_asts.insert(key);
        let selections = match base_definition {
            ExecutableDefinition::Operation(definition) => &definition.selections,
            ExecutableDefinition::Fragment(definition) => &definition.selections,
        };
        visit_selections(base_definitions_map, reachable_base_asts, selections, true)
    }
}
<commit_msg>minor refactor on dependency-analyzer<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 fnv::{FnvHashMap, FnvHashSet};
use graphql_syntax::*;
use interner::StringKey;

pub struct ReachableAst {
    /// The definitions that need to be compiled, includes the project
    /// definitions plus the fragment definitions in the base definitions
    /// reachable from the project definitions.
    pub definitions: Vec<ExecutableDefinition>,
    /// The fragment names added from the base definitions.
    pub base_fragment_names: FnvHashSet<StringKey>,
}

/// Get all definitions that reachable from project defintions
pub fn get_reachable_ast(
    project_definitions: Vec<ExecutableDefinition>,
    base_definitions: Vec<ExecutableDefinition>,
) -> ReachableAst {
    if base_definitions.is_empty() {
        return ReachableAst {
            definitions: project_definitions,
            base_fragment_names: FnvHashSet::default(),
        };
    }

    let mut reachable_base_asts = FnvHashSet::default();
    let mut base_definitions_map = FnvHashMap::default();

    // Preprocess all base fragment definitions
    // Skipping operations because project definitions can't reference base operations
    for base_definition in base_definitions {
        match &base_definition {
            ExecutableDefinition::Fragment(fragment) => {
                let name = fragment.name.value;
                assert!(
                    base_definitions_map.insert(name, base_definition).is_none(),
                    "get_reachable_ast called on graph with duplicate definition of `{}`",
                    name
                )
            }
            ExecutableDefinition::Operation(_) => {}
        }
    }

    let mut result = project_definitions.clone();

    // Find references from project definitions -> base definitions
    for definition in project_definitions {
        let selections = match definition {
            ExecutableDefinition::Operation(definition) => definition.selections,
            ExecutableDefinition::Fragment(definition) => definition.selections,
        };
        visit_selections(
            &base_definitions_map,
            &mut reachable_base_asts,
            &selections,
            false,
        )
    }

    for key in &reachable_base_asts {
        let value = base_definitions_map.remove(key).unwrap();
        result.push(value);
    }

    ReachableAst {
        definitions: result,
        base_fragment_names: reachable_base_asts,
    }
}

/// Get fragment references of each definition
pub fn get_definition_references<'a>(
    definitions: impl IntoIterator<Item = &'a ExecutableDefinition>,
) -> FnvHashMap<StringKey, FnvHashSet<StringKey>> {
    let mut result = FnvHashMap::default();
    for definition in definitions {
        let name = definition.name().expect("Expect a name on an operation");
        let mut selections: Vec<_> = match definition {
            ExecutableDefinition::Operation(definition) => &definition.selections.items,
            ExecutableDefinition::Fragment(definition) => &definition.selections.items,
        }
        .iter()
        .collect();
        let mut references = FnvHashSet::default();
        while let Some(selection) = selections.pop() {
            match selection {
                Selection::FragmentSpread(selection) => {
                    references.insert(selection.name.value);
                }
                Selection::LinkedField(selection) => {
                    selections.extend(&selection.selections.items);
                }
                Selection::InlineFragment(selection) => {
                    selections.extend(&selection.selections.items);
                }
                Selection::ScalarField(_) => {}
            }
        }
        result.insert(name, references);
    }
    result
}

fn visit_selections(
    base_definitions_map: &FnvHashMap<StringKey, ExecutableDefinition>,
    reachable_base_asts: &mut FnvHashSet<StringKey>,
    selections: &List<Selection>,
    is_base: bool,
) {
    for selection in &selections.items {
        match selection {
            Selection::FragmentSpread(selection) => {
                if is_base || base_definitions_map.contains_key(&selection.name.value) {
                    traverse_base_ast_definition(
                        base_definitions_map,
                        reachable_base_asts,
                        selection.name.value,
                    )
                }
            }
            Selection::LinkedField(selection) => visit_selections(
                base_definitions_map,
                reachable_base_asts,
                &selection.selections,
                is_base,
            ),
            Selection::InlineFragment(selection) => visit_selections(
                base_definitions_map,
                reachable_base_asts,
                &selection.selections,
                is_base,
            ),
            Selection::ScalarField(_) => {}
        }
    }
}

fn traverse_base_ast_definition(
    base_definitions_map: &FnvHashMap<StringKey, ExecutableDefinition>,
    reachable_base_asts: &mut FnvHashSet<StringKey>,
    key: StringKey,
) {
    if reachable_base_asts.contains(&key) {
        return;
    }
    if let Some(base_definition) = base_definitions_map.get(&key) {
        reachable_base_asts.insert(key);
        let selections = match base_definition {
            ExecutableDefinition::Operation(definition) => &definition.selections,
            ExecutableDefinition::Fragment(definition) => &definition.selections,
        };
        visit_selections(base_definitions_map, reachable_base_asts, selections, true)
    }
}
<|endoftext|>


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

use intern::string_key::Intern;
use intern::string_key::StringKey;
use lazy_static::lazy_static;

pub struct CodegenConstants {
    pub abstract_key: StringKey,
    pub action: StringKey,
    pub actor_change: StringKey,
    pub alias: StringKey,
    pub aliased_fragment_spread: StringKey,
    pub aliased_inline_fragment_spread: StringKey,
    pub args: StringKey,
    pub argument_definitions: StringKey,
    pub backward: StringKey,
    pub cache_id: StringKey,
    pub client_abstract_types: StringKey,
    pub client_component: StringKey,
    pub client_edge_backing_field_key: StringKey,
    pub client_edge_to_client_object: StringKey,
    pub client_edge_to_server_object: StringKey,
    pub client_edge_selections_key: StringKey,
    pub client_extension: StringKey,
    pub component_module_provider: StringKey,
    pub concrete_type: StringKey,
    pub condition_value: StringKey,
    pub condition: StringKey,
    pub connection: StringKey,
    pub count: StringKey,
    pub cursor: StringKey,
    pub default_handle_key: StringKey,
    pub default_value: StringKey,
    pub defer: StringKey,
    pub derived_from: StringKey,
    pub direction: StringKey,
    pub document_name: StringKey,
    pub dynamic_key_argument: StringKey,
    pub dynamic_key: StringKey,
    pub field: StringKey,
    pub fields: StringKey,
    pub filters: StringKey,
    pub flight_field: StringKey,
    pub forward: StringKey,
    pub fragment_name: StringKey,
    pub fragment_path_in_result: StringKey,
    pub fragment_prop_name: StringKey,
    pub fragment_spread_property: StringKey,
    pub fragment_spread: StringKey,
    pub fragment_value: StringKey,
    pub fragment: StringKey,
    pub handle_args: StringKey,
    pub handle: StringKey,
    pub has_client_edges: StringKey,
    pub id: StringKey,
    pub identifier_field: StringKey,
    pub if_: StringKey,
    pub inline_data_fragment_spread: StringKey,
    pub inline_data_fragment: StringKey,
    pub inline_fragment: StringKey,
    pub items: StringKey,
    pub key: StringKey,
    pub kind: StringKey,
    pub label: StringKey,
    pub linked_field_property: StringKey,
    pub linked_field: StringKey,
    pub linked_handle: StringKey,
    pub list_value: StringKey,
    pub literal: StringKey,
    pub local_argument: StringKey,
    pub mask: StringKey,
    pub metadata: StringKey,
    pub module_import: StringKey,
    pub mutation: StringKey,
    pub name: StringKey,
    pub object_value: StringKey,
    pub operation_module_provider: StringKey,
    pub operation_kind: StringKey,
    pub operation_value: StringKey,
    pub operation: StringKey,
    pub params: StringKey,
    pub passing_value: StringKey,
    pub path: StringKey,
    pub plural: StringKey,
    pub provided_variables: StringKey,
    pub provided_variables_definition: StringKey,
    pub provider: StringKey,
    pub query: StringKey,
    pub refetch: StringKey,
    pub relay_live_resolver: StringKey,
    pub relay_resolver: StringKey,
    pub request: StringKey,
    pub required_field: StringKey,
    pub resolver_module: StringKey,
    pub root_argument: StringKey,
    pub scalar_field: StringKey,
    pub scalar_handle: StringKey,
    pub selections: StringKey,
    pub split_operation: StringKey,
    pub storage_key: StringKey,
    pub stream: StringKey,
    pub subscription: StringKey,
    pub text: StringKey,
    pub type_: StringKey,
    pub type_discriminator: StringKey,
    pub updatable_query: StringKey,
    pub value: StringKey,
    pub variable_name: StringKey,
    pub variable: StringKey,
}

lazy_static! {
    pub static ref CODEGEN_CONSTANTS: CodegenConstants = CodegenConstants {
        abstract_key: "abstractKey".intern(),
        action: "action".intern(),
        actor_change: "ActorChange".intern(),
        alias: "alias".intern(),
        aliased_fragment_spread: "AliasedFragmentSpread".intern(),
        aliased_inline_fragment_spread: "AliasedInlineFragmentSpread".intern(),
        args: "args".intern(),
        argument_definitions: "argumentDefinitions".intern(),
        backward: "backward".intern(),
        cache_id: "cacheID".intern(),
        client_abstract_types: "clientAbstractTypes".intern(),
        client_component: "ClientComponent".intern(),
        client_edge_to_server_object: "ClientEdgeToServerObject".intern(),
        client_edge_to_client_object: "ClientEdgeToClientObject".intern(),
        client_edge_backing_field_key: "backingField".intern(),
        client_edge_selections_key: "linkedField".intern(),
        client_extension: "ClientExtension".intern(),
        component_module_provider: "componentModuleProvider".intern(),
        concrete_type: "concreteType".intern(),
        condition_value: "Condition".intern(),
        condition: "condition".intern(),
        connection: "connection".intern(),
        count: "count".intern(),
        cursor: "cursor".intern(),
        default_handle_key: "".intern(),
        default_value: "defaultValue".intern(),
        defer: "Defer".intern(),
        derived_from: "derivedFrom".intern(),
        direction: "direction".intern(),
        document_name: "documentName".intern(),
        dynamic_key_argument: "__dynamicKey".intern(),
        dynamic_key: "dynamicKey".intern(),
        field: "field".intern(),
        fields: "fields".intern(),
        filters: "filters".intern(),
        flight_field: "FlightField".intern(),
        forward: "forward".intern(),
        fragment_name: "fragmentName".intern(),
        fragment_path_in_result: "fragmentPathInResult".intern(),
        fragment_prop_name: "fragmentPropName".intern(),
        fragment_spread_property: "fragmentSpread".intern(),
        fragment_spread: "FragmentSpread".intern(),
        fragment_value: "Fragment".intern(),
        fragment: "fragment".intern(),
        handle_args: "handleArgs".intern(),
        handle: "handle".intern(),
        has_client_edges: "hasClientEdges".intern(),
        id: "id".intern(),
        identifier_field: "identifierField".intern(),
        if_: "if".intern(),
        inline_data_fragment_spread: "InlineDataFragmentSpread".intern(),
        inline_data_fragment: "InlineDataFragment".intern(),
        inline_fragment: "InlineFragment".intern(),
        items: "items".intern(),
        key: "key".intern(),
        kind: "kind".intern(),
        label: "label".intern(),
        linked_field_property: "linkedField".intern(),
        linked_field: "LinkedField".intern(),
        linked_handle: "LinkedHandle".intern(),
        list_value: "ListValue".intern(),
        literal: "Literal".intern(),
        local_argument: "LocalArgument".intern(),
        mask: "mask".intern(),
        metadata: "metadata".intern(),
        module_import: "ModuleImport".intern(),
        mutation: "mutation".intern(),
        name: "name".intern(),
        object_value: "ObjectValue".intern(),
        operation_module_provider: "operationModuleProvider".intern(),
        operation_kind: "operationKind".intern(),
        operation_value: "Operation".intern(),
        operation: "operation".intern(),
        params: "params".intern(),
        passing_value: "passingValue".intern(),
        path: "path".intern(),
        plural: "plural".intern(),
        provider: "provider".intern(),
        provided_variables: "providedVariables".intern(),
        provided_variables_definition: "providedVariablesDefinition".intern(),
        query: "query".intern(),
        refetch: "refetch".intern(),
        relay_live_resolver: "RelayLiveResolver".intern(),
        relay_resolver: "RelayResolver".intern(),
        request: "Request".intern(),
        required_field: "RequiredField".intern(),
        resolver_module: "resolverModule".intern(),
        root_argument: "RootArgument".intern(),
        scalar_field: "ScalarField".intern(),
        scalar_handle: "ScalarHandle".intern(),
        selections: "selections".intern(),
        split_operation: "SplitOperation".intern(),
        storage_key: "storageKey".intern(),
        stream: "Stream".intern(),
        subscription: "subscription".intern(),
        text: "text".intern(),
        type_: "type".intern(),
        type_discriminator: "TypeDiscriminator".intern(),
        updatable_query: "UpdatableQuery".intern(),
        value: "value".intern(),
        variable_name: "variableName".intern(),
        variable: "Variable".intern(),
    };
}
<commit_msg>sort codegen constants<commit_after>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use intern::string_key::Intern;
use intern::string_key::StringKey;
use lazy_static::lazy_static;

pub struct CodegenConstants {
    pub abstract_key: StringKey,
    pub action: StringKey,
    pub actor_change: StringKey,
    pub alias: StringKey,
    pub aliased_fragment_spread: StringKey,
    pub aliased_inline_fragment_spread: StringKey,
    pub args: StringKey,
    pub argument_definitions: StringKey,
    pub backward: StringKey,
    pub cache_id: StringKey,
    pub client_abstract_types: StringKey,
    pub client_component: StringKey,
    pub client_edge_backing_field_key: StringKey,
    pub client_edge_selections_key: StringKey,
    pub client_edge_to_client_object: StringKey,
    pub client_edge_to_server_object: StringKey,
    pub client_extension: StringKey,
    pub component_module_provider: StringKey,
    pub concrete_type: StringKey,
    pub condition_value: StringKey,
    pub condition: StringKey,
    pub connection: StringKey,
    pub count: StringKey,
    pub cursor: StringKey,
    pub default_handle_key: StringKey,
    pub default_value: StringKey,
    pub defer: StringKey,
    pub derived_from: StringKey,
    pub direction: StringKey,
    pub document_name: StringKey,
    pub dynamic_key_argument: StringKey,
    pub dynamic_key: StringKey,
    pub field: StringKey,
    pub fields: StringKey,
    pub filters: StringKey,
    pub flight_field: StringKey,
    pub forward: StringKey,
    pub fragment_name: StringKey,
    pub fragment_path_in_result: StringKey,
    pub fragment_prop_name: StringKey,
    pub fragment_spread_property: StringKey,
    pub fragment_spread: StringKey,
    pub fragment_value: StringKey,
    pub fragment: StringKey,
    pub handle_args: StringKey,
    pub handle: StringKey,
    pub has_client_edges: StringKey,
    pub id: StringKey,
    pub identifier_field: StringKey,
    pub if_: StringKey,
    pub inline_data_fragment_spread: StringKey,
    pub inline_data_fragment: StringKey,
    pub inline_fragment: StringKey,
    pub items: StringKey,
    pub key: StringKey,
    pub kind: StringKey,
    pub label: StringKey,
    pub linked_field_property: StringKey,
    pub linked_field: StringKey,
    pub linked_handle: StringKey,
    pub list_value: StringKey,
    pub literal: StringKey,
    pub local_argument: StringKey,
    pub mask: StringKey,
    pub metadata: StringKey,
    pub module_import: StringKey,
    pub mutation: StringKey,
    pub name: StringKey,
    pub object_value: StringKey,
    pub operation_kind: StringKey,
    pub operation_module_provider: StringKey,
    pub operation_value: StringKey,
    pub operation: StringKey,
    pub params: StringKey,
    pub passing_value: StringKey,
    pub path: StringKey,
    pub plural: StringKey,
    pub provided_variables_definition: StringKey,
    pub provided_variables: StringKey,
    pub provider: StringKey,
    pub query: StringKey,
    pub refetch: StringKey,
    pub relay_live_resolver: StringKey,
    pub relay_resolver: StringKey,
    pub request: StringKey,
    pub required_field: StringKey,
    pub resolver_module: StringKey,
    pub root_argument: StringKey,
    pub scalar_field: StringKey,
    pub scalar_handle: StringKey,
    pub selections: StringKey,
    pub split_operation: StringKey,
    pub storage_key: StringKey,
    pub stream: StringKey,
    pub subscription: StringKey,
    pub text: StringKey,
    pub type_: StringKey,
    pub type_discriminator: StringKey,
    pub updatable_query: StringKey,
    pub value: StringKey,
    pub variable_name: StringKey,
    pub variable: StringKey,
}

lazy_static! {
    pub static ref CODEGEN_CONSTANTS: CodegenConstants = CodegenConstants {
        abstract_key: "abstractKey".intern(),
        action: "action".intern(),
        actor_change: "ActorChange".intern(),
        alias: "alias".intern(),
        aliased_fragment_spread: "AliasedFragmentSpread".intern(),
        aliased_inline_fragment_spread: "AliasedInlineFragmentSpread".intern(),
        args: "args".intern(),
        argument_definitions: "argumentDefinitions".intern(),
        backward: "backward".intern(),
        cache_id: "cacheID".intern(),
        client_abstract_types: "clientAbstractTypes".intern(),
        client_component: "ClientComponent".intern(),
        client_edge_backing_field_key: "backingField".intern(),
        client_edge_selections_key: "linkedField".intern(),
        client_edge_to_client_object: "ClientEdgeToClientObject".intern(),
        client_edge_to_server_object: "ClientEdgeToServerObject".intern(),
        client_extension: "ClientExtension".intern(),
        component_module_provider: "componentModuleProvider".intern(),
        concrete_type: "concreteType".intern(),
        condition_value: "Condition".intern(),
        condition: "condition".intern(),
        connection: "connection".intern(),
        count: "count".intern(),
        cursor: "cursor".intern(),
        default_handle_key: "".intern(),
        default_value: "defaultValue".intern(),
        defer: "Defer".intern(),
        derived_from: "derivedFrom".intern(),
        direction: "direction".intern(),
        document_name: "documentName".intern(),
        dynamic_key_argument: "__dynamicKey".intern(),
        dynamic_key: "dynamicKey".intern(),
        field: "field".intern(),
        fields: "fields".intern(),
        filters: "filters".intern(),
        flight_field: "FlightField".intern(),
        forward: "forward".intern(),
        fragment_name: "fragmentName".intern(),
        fragment_path_in_result: "fragmentPathInResult".intern(),
        fragment_prop_name: "fragmentPropName".intern(),
        fragment_spread_property: "fragmentSpread".intern(),
        fragment_spread: "FragmentSpread".intern(),
        fragment_value: "Fragment".intern(),
        fragment: "fragment".intern(),
        handle_args: "handleArgs".intern(),
        handle: "handle".intern(),
        has_client_edges: "hasClientEdges".intern(),
        id: "id".intern(),
        identifier_field: "identifierField".intern(),
        if_: "if".intern(),
        inline_data_fragment_spread: "InlineDataFragmentSpread".intern(),
        inline_data_fragment: "InlineDataFragment".intern(),
        inline_fragment: "InlineFragment".intern(),
        items: "items".intern(),
        key: "key".intern(),
        kind: "kind".intern(),
        label: "label".intern(),
        linked_field_property: "linkedField".intern(),
        linked_field: "LinkedField".intern(),
        linked_handle: "LinkedHandle".intern(),
        list_value: "ListValue".intern(),
        literal: "Literal".intern(),
        local_argument: "LocalArgument".intern(),
        mask: "mask".intern(),
        metadata: "metadata".intern(),
        module_import: "ModuleImport".intern(),
        mutation: "mutation".intern(),
        name: "name".intern(),
        object_value: "ObjectValue".intern(),
        operation_kind: "operationKind".intern(),
        operation_module_provider: "operationModuleProvider".intern(),
        operation_value: "Operation".intern(),
        operation: "operation".intern(),
        params: "params".intern(),
        passing_value: "passingValue".intern(),
        path: "path".intern(),
        plural: "plural".intern(),
        provided_variables_definition: "providedVariablesDefinition".intern(),
        provided_variables: "providedVariables".intern(),
        provider: "provider".intern(),
        query: "query".intern(),
        refetch: "refetch".intern(),
        relay_live_resolver: "RelayLiveResolver".intern(),
        relay_resolver: "RelayResolver".intern(),
        request: "Request".intern(),
        required_field: "RequiredField".intern(),
        resolver_module: "resolverModule".intern(),
        root_argument: "RootArgument".intern(),
        scalar_field: "ScalarField".intern(),
        scalar_handle: "ScalarHandle".intern(),
        selections: "selections".intern(),
        split_operation: "SplitOperation".intern(),
        storage_key: "storageKey".intern(),
        stream: "Stream".intern(),
        subscription: "subscription".intern(),
        text: "text".intern(),
        type_: "type".intern(),
        type_discriminator: "TypeDiscriminator".intern(),
        updatable_query: "UpdatableQuery".intern(),
        value: "value".intern(),
        variable_name: "variableName".intern(),
        variable: "Variable".intern(),
    };
}
<|endoftext|>


<commit_before>use std::result::*;
use std::rc::*;

use rustc_serialize::*;

use super::treenode::*;
use super::basictree::*;
use super::values::*;

///
/// Encoder that will write to the specified tree node
///
struct TreeNodeEncoder {
    tag:    String,
    value:  TreeValue,
    child:  Option<Rc<TreeNode>>
}

impl TreeNodeEncoder {
    fn new() -> TreeNodeEncoder {
        TreeNodeEncoder {
            tag:    "".to_string(),
            value:  TreeValue::Nothing,
            child:  None }
    }

    fn to_basic_tree_node(&self) -> BasicTree {
        let new_node = BasicTree::new(&*self.tag, self.value.to_owned());

        self.child.to_owned().and_then(|child| {
            new_node.set_child_ref(child);
            Some(())
        });

        new_node
    }
}

#[derive(Debug)]
pub enum TreeNodeCodingError {
    UnsupportedType
}

impl Encoder for TreeNodeEncoder {
    type Error = TreeNodeCodingError;

    fn emit_nil(&mut self) -> Result<(), Self::Error> {
        self.value = TreeValue::Nothing;
        Ok(())
    }

    fn emit_i32(&mut self, v: i32) -> Result<(), Self::Error> {
        self.value = TreeValue::Int(v);
        Ok(())
    }

    fn emit_i16(&mut self, v: i16) -> Result<(), Self::Error> {
        self.value = TreeValue::Int(v as i32);
        Ok(())
    }

    fn emit_i8(&mut self, v: i8) -> Result<(), Self::Error> {
        self.value = TreeValue::Int(v as i32);
        Ok(())
    }

    fn emit_bool(&mut self, v: bool) -> Result<(), Self::Error> {
        self.value = TreeValue::Bool(v);
        Ok(())
    }

    fn emit_f64(&mut self, v: f64) -> Result<(), Self::Error> {
        self.value = TreeValue::Real(v);
        Ok(())
    }

    fn emit_f32(&mut self, v: f32) -> Result<(), Self::Error> {
        self.value = TreeValue::Real(v as f64);
        Ok(())
    }

    fn emit_str(&mut self, v: &str) -> Result<(), Self::Error> {
        self.value = TreeValue::String(v.to_string());
        Ok(())
    }

    fn emit_struct<F>(&mut self, name: &str, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        self.value = TreeValue::String(name.to_string());

        f(self)
    }

    fn emit_struct_field<F>(&mut self, f_name: &str, f_idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        // Encode the function into a new encoder
        let mut node_encoder = TreeNodeEncoder::new();
        let encoding_result = f(&mut node_encoder);

        node_encoder.tag = f_name.to_string();

        // Short-circuit on error
        if encoding_result.is_err() {
            return encoding_result;
        }

        // Replace the child node with the node generated for the new encoder
        let new_node = node_encoder.to_basic_tree_node();

        self.child.to_owned().and_then(|sibling| {
            new_node.set_sibling_ref(sibling);
            Some(())
        });

        // Save the node we just created and update the tree
        self.child = Some(Rc::new(new_node));

        Ok(())
    }

    fn emit_usize(&mut self, v: usize) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_u64(&mut self, v: u64) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_u32(&mut self, v: u32) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_u16(&mut self, v: u16) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_u8(&mut self, v: u8) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_isize(&mut self, v: isize) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_i64(&mut self, v: i64) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_char(&mut self, v: char) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_enum<F>(&mut self, name: &str, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_enum_variant<F>(&mut self, v_name: &str, v_id: usize, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_enum_variant_arg<F>(&mut self, a_idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_enum_struct_variant<F>(&mut self, v_name: &str, v_id: usize, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_enum_struct_variant_field<F>(&mut self, f_name: &str, f_idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_tuple<F>(&mut self, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_tuple_arg<F>(&mut self, idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_tuple_struct<F>(&mut self, name: &str, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_tuple_struct_arg<F>(&mut self, f_idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_option<F>(&mut self, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_option_none(&mut self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_option_some<F>(&mut self, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_seq<F>(&mut self, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_seq_elt<F>(&mut self, idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_map<F>(&mut self, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_map_elt_key<F>(&mut self, idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_map_elt_val<F>(&mut self, idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }
}

///
/// Converts an encodable object into a treenode
///
pub fn encode<T: Encodable>(source: &T) -> Result<Rc<TreeNode>, TreeNodeCodingError> {
    // The encoder doesn't directly create a TreeNode because of the way rust lifetimes work
    // (We'd need a <'a> lifetime on the encoder, and that lifetime would prevent recursion by generating
    // new encoders. This is really a limitation of Rust; we work around it by generating the description of
    // a tree node in the encoder and then the tree node itself outside of it)
    //
    // We don't expose the actual encoder publically for this reason, the API is too dumb by necessity.
    let mut encoder = TreeNodeEncoder::new();
    let result = source.encode(&mut encoder);

    result.map(|_| {
        let result: Rc<TreeNode> = Rc::new(encoder.to_basic_tree_node());
        result
    })
}

///
/// Marker trait that can be added to types to make them support encoding to a tree node via .to_tree_node()
///
pub trait EncodeToTreeNode {
    // Empty, this is a marker type
}

impl<T: Encodable + EncodeToTreeNode> ToTreeNode for T {
    ///
    /// Converts this value into a tree node
    ///
    fn to_tree_node(&self) -> Rc<TreeNode> {
        encode(self).unwrap()
    }
}

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

    #[derive(RustcEncodable, RustcDecodable)]
    struct Test {
        field1: i32,
        field2: String,
        field3: bool
    }

    // One day this ought to be possible via #[derive]
    impl EncodeToTreeNode for Test { }

    #[test]
    fn encode_struct() {
        let test = Test { field1: 32, field2: "Hi".to_string(), field3: true };
        let encoded = test.to_tree_node();

        assert!(match encoded.get_child_at("field1").get_value().to_owned() { TreeValue::Int(x) => x == 32, _ => false });
        assert!(match encoded.get_child_at("field2").get_value().to_owned() { TreeValue::String(x) => x == "Hi", _ => false });
        assert!(match encoded.get_child_at("field3").get_value().to_owned() { TreeValue::Bool(x) => x == true, _ => false });
    }
}
<commit_msg>Can avoid to_owned() here<commit_after>use std::result::*;
use std::rc::*;

use rustc_serialize::*;

use super::treenode::*;
use super::basictree::*;
use super::values::*;

///
/// Encoder that will write to the specified tree node
///
struct TreeNodeEncoder {
    tag:    String,
    value:  TreeValue,
    child:  Option<Rc<TreeNode>>
}

impl TreeNodeEncoder {
    fn new() -> TreeNodeEncoder {
        TreeNodeEncoder {
            tag:    "".to_string(),
            value:  TreeValue::Nothing,
            child:  None }
    }

    fn to_basic_tree_node(&self) -> BasicTree {
        let new_node = BasicTree::new(&*self.tag, self.value.to_owned());

        self.child.to_owned().and_then(|child| {
            new_node.set_child_ref(child);
            Some(())
        });

        new_node
    }
}

#[derive(Debug)]
pub enum TreeNodeCodingError {
    UnsupportedType
}

impl Encoder for TreeNodeEncoder {
    type Error = TreeNodeCodingError;

    fn emit_nil(&mut self) -> Result<(), Self::Error> {
        self.value = TreeValue::Nothing;
        Ok(())
    }

    fn emit_i32(&mut self, v: i32) -> Result<(), Self::Error> {
        self.value = TreeValue::Int(v);
        Ok(())
    }

    fn emit_i16(&mut self, v: i16) -> Result<(), Self::Error> {
        self.value = TreeValue::Int(v as i32);
        Ok(())
    }

    fn emit_i8(&mut self, v: i8) -> Result<(), Self::Error> {
        self.value = TreeValue::Int(v as i32);
        Ok(())
    }

    fn emit_bool(&mut self, v: bool) -> Result<(), Self::Error> {
        self.value = TreeValue::Bool(v);
        Ok(())
    }

    fn emit_f64(&mut self, v: f64) -> Result<(), Self::Error> {
        self.value = TreeValue::Real(v);
        Ok(())
    }

    fn emit_f32(&mut self, v: f32) -> Result<(), Self::Error> {
        self.value = TreeValue::Real(v as f64);
        Ok(())
    }

    fn emit_str(&mut self, v: &str) -> Result<(), Self::Error> {
        self.value = TreeValue::String(v.to_string());
        Ok(())
    }

    fn emit_struct<F>(&mut self, name: &str, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        self.value = TreeValue::String(name.to_string());

        f(self)
    }

    fn emit_struct_field<F>(&mut self, f_name: &str, f_idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        // Encode the function into a new encoder
        let mut node_encoder = TreeNodeEncoder::new();
        let encoding_result = f(&mut node_encoder);

        node_encoder.tag = f_name.to_string();

        // Short-circuit on error
        if encoding_result.is_err() {
            return encoding_result;
        }

        // Replace the child node with the node generated for the new encoder
        let new_node = node_encoder.to_basic_tree_node();

        self.child.to_owned().and_then(|sibling| {
            new_node.set_sibling_ref(sibling);
            Some(())
        });

        // Save the node we just created and update the tree
        self.child = Some(Rc::new(new_node));

        Ok(())
    }

    fn emit_usize(&mut self, v: usize) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_u64(&mut self, v: u64) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_u32(&mut self, v: u32) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_u16(&mut self, v: u16) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_u8(&mut self, v: u8) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_isize(&mut self, v: isize) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_i64(&mut self, v: i64) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_char(&mut self, v: char) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_enum<F>(&mut self, name: &str, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_enum_variant<F>(&mut self, v_name: &str, v_id: usize, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_enum_variant_arg<F>(&mut self, a_idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_enum_struct_variant<F>(&mut self, v_name: &str, v_id: usize, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_enum_struct_variant_field<F>(&mut self, f_name: &str, f_idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_tuple<F>(&mut self, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_tuple_arg<F>(&mut self, idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_tuple_struct<F>(&mut self, name: &str, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_tuple_struct_arg<F>(&mut self, f_idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_option<F>(&mut self, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_option_none(&mut self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_option_some<F>(&mut self, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_seq<F>(&mut self, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_seq_elt<F>(&mut self, idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_map<F>(&mut self, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_map_elt_key<F>(&mut self, idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_map_elt_val<F>(&mut self, idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }
}

///
/// Converts an encodable object into a treenode
///
pub fn encode<T: Encodable>(source: &T) -> Result<Rc<TreeNode>, TreeNodeCodingError> {
    // The encoder doesn't directly create a TreeNode because of the way rust lifetimes work
    // (We'd need a <'a> lifetime on the encoder, and that lifetime would prevent recursion by generating
    // new encoders. This is really a limitation of Rust; we work around it by generating the description of
    // a tree node in the encoder and then the tree node itself outside of it)
    //
    // We don't expose the actual encoder publically for this reason, the API is too dumb by necessity.
    let mut encoder = TreeNodeEncoder::new();
    let result = source.encode(&mut encoder);

    result.map(|_| {
        let result: Rc<TreeNode> = Rc::new(encoder.to_basic_tree_node());
        result
    })
}

///
/// Marker trait that can be added to types to make them support encoding to a tree node via .to_tree_node()
///
pub trait EncodeToTreeNode {
    // Empty, this is a marker type
}

impl<T: Encodable + EncodeToTreeNode> ToTreeNode for T {
    ///
    /// Converts this value into a tree node
    ///
    fn to_tree_node(&self) -> Rc<TreeNode> {
        encode(self).unwrap()
    }
}

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

    #[derive(RustcEncodable, RustcDecodable)]
    struct Test {
        field1: i32,
        field2: String,
        field3: bool
    }

    // One day this ought to be possible via #[derive]
    impl EncodeToTreeNode for Test { }

    #[test]
    fn encode_struct() {
        let test = Test { field1: 32, field2: "Hi".to_string(), field3: true };
        let encoded = test.to_tree_node();

        assert!(match *encoded.get_child_at("field1").get_value() { TreeValue::Int(ref x) => *x == 32, _ => false });
        assert!(match *encoded.get_child_at("field2").get_value() { TreeValue::String(ref x) => *x == "Hi", _ => false });
        assert!(match *encoded.get_child_at("field3").get_value() { TreeValue::Bool(ref x) => *x == true, _ => false });
    }
}
<|endoftext|>


<commit_before>//! `Kay` is a high-performance actor system, suitable for simulating millions of entities.
//!
//! In `Kay`, actors concurrently send and receive asynchronous messages, but are
//! otherwise completely isloated from each other. Actors can only mutate their own state.
//!
//! Have a look at [`Actor`](trait.Actor.html), [`Recipient`](trait.Recipient.html)
//! and [`Swarm`](struct.Swarm.html) to understand the main abstractions.

#![warn(missing_docs)]
#![feature(plugin)]
#![plugin(clippy)]
#![feature(core_intrinsics)]
#![feature(optin_builtin_traits)]
#![feature(specialization)]
#![feature(conservative_impl_trait)]
#![feature(box_syntax)]
#![feature(nonzero)]
#![allow(no_effect)]
extern crate chunked;
extern crate compact;
#[macro_use]
extern crate compact_macros;
extern crate random;
extern crate core;

mod inbox;
mod slot_map;
pub mod swarm;
#[macro_use]
mod messaging;
mod type_registry;
mod id;
mod actor_system;

pub use self::messaging::{Message, Packet, Recipient, Fate};
pub use self::id::ID;
pub use self::actor_system::{THE_SYSTEM, ActorSystem, Actor};
<commit_msg>Fix link in lib/kay/src/lib.rs<commit_after>//! `Kay` is a high-performance actor system, suitable for simulating millions of entities.
//!
//! In `Kay`, actors concurrently send and receive asynchronous messages, but are
//! otherwise completely isloated from each other. Actors can only mutate their own state.
//!
//! Have a look at [`Actor`](trait.Actor.html), [`Recipient`](trait.Recipient.html)
//! and [`Swarm`](swarm/struct.Swarm.html) to understand the main abstractions.

#![warn(missing_docs)]
#![feature(plugin)]
#![plugin(clippy)]
#![feature(core_intrinsics)]
#![feature(optin_builtin_traits)]
#![feature(specialization)]
#![feature(conservative_impl_trait)]
#![feature(box_syntax)]
#![feature(nonzero)]
#![allow(no_effect)]
extern crate chunked;
extern crate compact;
#[macro_use]
extern crate compact_macros;
extern crate random;
extern crate core;

mod inbox;
mod slot_map;
pub mod swarm;
#[macro_use]
mod messaging;
mod type_registry;
mod id;
mod actor_system;

pub use self::messaging::{Message, Packet, Recipient, Fate};
pub use self::id::ID;
pub use self::actor_system::{THE_SYSTEM, ActorSystem, Actor};
<|endoftext|>


<commit_before>pub struct Repeatedly<F> {
    pub f: F,
}

impl<T, F: FnMut() -> T> Iterator for Repeatedly<F> {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        let mut f = &mut self.f;
        Some(f())
    }
}

/// takes a function `f` of no args, presumably with side effects, and
/// returns an iterator that endlessly calls `f` and yields the return value
pub fn repeatedly<T, F: FnMut() -> T>(f: F) -> Repeatedly<F> {
    Repeatedly { f: f }
}

#[test]
fn test_repeatedly() {
    assert_eq!(vec![3, 3, 3, 3],
               repeatedly(|| 3).take(4).collect::<Vec<usize>>());

    let mut i = 0;
    assert_eq!(vec![1, 2, 3, 4],
               repeatedly(move || {
                   i += 1;
                   i
               })
                   .take(4)
                   .collect::<Vec<usize>>());
}
<commit_msg>test repeatedly with random number generation<commit_after>extern crate rand;

pub struct Repeatedly<F> {
    pub f: F,
}

impl<T, F: FnMut() -> T> Iterator for Repeatedly<F> {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        let mut f = &mut self.f;
        Some(f())
    }
}

/// takes a function `f` of no args, presumably with side effects, and
/// returns an iterator that endlessly calls `f` and yields the return value
pub fn repeatedly<T, F: FnMut() -> T>(f: F) -> Repeatedly<F> {
    Repeatedly { f: f }
}

#[test]
fn test_repeatedly() {
    use self::rand::{StdRng, SeedableRng};
    use helpers::random01;

    assert_eq!(vec![3, 3, 3, 3],
               repeatedly(|| 3).take(4).collect::<Vec<usize>>());

    let mut i = 0;
    assert_eq!(vec![1, 2, 3, 4],
               repeatedly(move || {
                   i += 1;
                   i
               })
                   .take(4)
                   .collect::<Vec<usize>>());

    let seed: &[_] = &[1, 2, 3, 4];
    let mut rng: StdRng = SeedableRng::from_seed(seed);
    assert_eq!(vec![0.5162139860908154, 0.13628294371987984, 0.21635575241586105, 0.10006169673911681],
               repeatedly(move || random01(&mut rng))
                   .take(4)
                   .collect::<Vec<f64>>());
}
<|endoftext|>


<commit_before>use input::Input;
use ncurses;
use ncurses::ll::{attr_t, chtype, mmask_t};
use ncurses::NCURSES_ATTR_SHIFT;

pub use ncurses::{ACS_LRCORNER, ACS_URCORNER, ACS_ULCORNER, ACS_LLCORNER};
pub use ncurses::{ACS_PLUS, ACS_LTEE, ACS_RTEE, ACS_BTEE, ACS_TTEE, ACS_HLINE, ACS_VLINE};
pub use ncurses::{ACS_S1, ACS_S9, ACS_DIAMOND, ACS_CKBOARD, ACS_DEGREE, ACS_PLMINUS, ACS_BULLET};
pub use ncurses::{ACS_LARROW, ACS_RARROW, ACS_DARROW, ACS_UARROW, ACS_BOARD, ACS_LANTERN, ACS_BLOCK};
pub use ncurses::{ACS_S3, ACS_S7, ACS_LEQUAL, ACS_GEQUAL, ACS_PI, ACS_NEQUAL, ACS_STERLING};
pub use ncurses::{ACS_BSSB, ACS_SSBB, ACS_BBSS, ACS_SBBS, ACS_SBSS, ACS_SSSB, ACS_SSBS}
pub use ncurses::{ACS_BSSS, ACS_BSBS, ACS_SBSB, ACS_SSSS}

fn NCURSES_BITS(mask: u32, shift: u32) -> u32 {
    mask << (shift + NCURSES_ATTR_SHIFT) as usize
}

pub fn COLOR_PAIR(n: chtype) -> attr_t {
    NCURSES_BITS(n as u32, 0u32) as attr_t
}

pub const COLOR_BLACK: i16 = 0;
pub const COLOR_RED: i16 = 1;
pub const COLOR_GREEN: i16 = 2;
pub const COLOR_YELLOW: i16 = 3;
pub const COLOR_BLUE: i16 = 4;
pub const COLOR_MAGENTA: i16 = 5;
pub const COLOR_CYAN: i16 = 6;
pub const COLOR_WHITE: i16 = 7;

pub const A_ALTCHARSET: attr_t = (1u32 << (14u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_ATTRIBUTES: attr_t = (!0u32 << (0u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_BLINK: attr_t = (1u32 << (11u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_BOLD: attr_t = (1u32 << (13u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_CHARTEXT: attr_t = (1u32 << (0u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_COLOR: attr_t = ((((1u32) << 8) - 1u32) << (0u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_DIM: attr_t = (1u32 << (12u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_ITALIC: attr_t = (1u32 << (23 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_INVIS: attr_t = (1u32 << (15u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_LEFTLINE: attr_t = 0; // Not supported on ncurses
pub const A_NORMAL: attr_t = 0u32 as attr_t;
pub const A_OVERLINE: attr_t = 0; // Not supported on ncurses
pub const A_REVERSE: attr_t = (1u32 << (10 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_RIGHTLINE: attr_t = 0; // Not supported on ncurses
pub const A_STANDOUT: attr_t = (1u32 << (8 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_STRIKEOUT: attr_t = 0; // Not supported on ncurses
pub const A_UNDERLINE: attr_t = (1u32 << (9 + NCURSES_ATTR_SHIFT)) as attr_t;

pub const KEY_RESIZE: i32 = 0632;

pub const KEY_OFFSET: i32 = 0o0400;
pub const KEY_F15: i32 = (KEY_OFFSET + 0x17);
pub const KEY_EVENT: i32 = (KEY_OFFSET + 0o633);

pub const SPECIAL_KEY_CODES: [Input; 108] = [Input::KeyCodeYes,

                                             Input::KeyBreak,
                                             Input::KeyDown,
                                             Input::KeyUp,
                                             Input::KeyLeft,
                                             Input::KeyRight,
                                             Input::KeyHome,
                                             Input::KeyBackspace,

                                             Input::KeyF0,
                                             Input::KeyF1,
                                             Input::KeyF2,
                                             Input::KeyF3,
                                             Input::KeyF4,
                                             Input::KeyF5,
                                             Input::KeyF6,
                                             Input::KeyF7,
                                             Input::KeyF8,
                                             Input::KeyF9,
                                             Input::KeyF10,
                                             Input::KeyF11,
                                             Input::KeyF12,
                                             Input::KeyF13,
                                             Input::KeyF14,
                                             Input::KeyF15,
                                             // ncurses reserves space for 64 function keys, but we've
                                             // only implemented 15. This has to be taken into account
                                             // when converting the integer into an index of this array
                                             Input::KeyDL,
                                             Input::KeyIL,
                                             Input::KeyDC,
                                             Input::KeyIC,
                                             Input::KeyEIC,
                                             Input::KeyClear,
                                             Input::KeyEOS,
                                             Input::KeyEOL,
                                             Input::KeySF,
                                             Input::KeySR,
                                             Input::KeyNPage,
                                             Input::KeyPPage,
                                             Input::KeySTab,
                                             Input::KeyCTab,
                                             Input::KeyCATab,
                                             Input::KeyEnter,
                                             Input::KeySReset,
                                             Input::KeyReset,
                                             Input::KeyPrint,
                                             Input::KeyLL,
                                             Input::KeyA1,
                                             Input::KeyA3,
                                             Input::KeyB2,
                                             Input::KeyC1,
                                             Input::KeyC3,
                                             Input::KeyBTab,
                                             Input::KeyBeg,
                                             Input::KeyCancel,
                                             Input::KeyClose,
                                             Input::KeyCommand,
                                             Input::KeyCopy,
                                             Input::KeyCreate,
                                             Input::KeyEnd,
                                             Input::KeyExit,
                                             Input::KeyFind,
                                             Input::KeyHelp,
                                             Input::KeyMark,
                                             Input::KeyMessage,
                                             Input::KeyMove,
                                             Input::KeyNext,
                                             Input::KeyOpen,
                                             Input::KeyOptions,
                                             Input::KeyPrevious,
                                             Input::KeyRedo,
                                             Input::KeyReference,
                                             Input::KeyRefresh,
                                             Input::KeyReplace,
                                             Input::KeyRestart,
                                             Input::KeyResume,
                                             Input::KeySave,
                                             Input::KeySBeg,
                                             Input::KeySCancel,
                                             Input::KeySCommand,
                                             Input::KeySCopy,
                                             Input::KeySCreate,
                                             Input::KeySDC,
                                             Input::KeySDL,
                                             Input::KeySelect,
                                             Input::KeySEnd,
                                             Input::KeySEOL,
                                             Input::KeySExit,
                                             Input::KeySFind,
                                             Input::KeySHelp,
                                             Input::KeySHome,
                                             Input::KeySIC,

                                             Input::KeySLeft,
                                             Input::KeySMessage,
                                             Input::KeySMove,
                                             Input::KeySNext,
                                             Input::KeySOptions,
                                             Input::KeySPrevious,
                                             Input::KeySPrint,
                                             Input::KeySRedo,
                                             Input::KeySReplace,
                                             Input::KeySRight,
                                             Input::KeySResume,
                                             Input::KeySSave,
                                             Input::KeySSuspend,
                                             Input::KeySUndo,
                                             Input::KeySuspend,
                                             Input::KeyUndo,
                                             Input::KeyMouse,
                                             Input::KeyResize,
                                             Input::KeyEvent];

pub const ALL_MOUSE_EVENTS: mmask_t = ncurses::ALL_MOUSE_EVENTS as mmask_t;<commit_msg>Fixed typo<commit_after>use input::Input;
use ncurses;
use ncurses::ll::{attr_t, chtype, mmask_t};
use ncurses::NCURSES_ATTR_SHIFT;

pub use ncurses::{ACS_LRCORNER, ACS_URCORNER, ACS_ULCORNER, ACS_LLCORNER};
pub use ncurses::{ACS_PLUS, ACS_LTEE, ACS_RTEE, ACS_BTEE, ACS_TTEE, ACS_HLINE, ACS_VLINE};
pub use ncurses::{ACS_S1, ACS_S9, ACS_DIAMOND, ACS_CKBOARD, ACS_DEGREE, ACS_PLMINUS, ACS_BULLET};
pub use ncurses::{ACS_LARROW, ACS_RARROW, ACS_DARROW, ACS_UARROW, ACS_BOARD, ACS_LANTERN, ACS_BLOCK};
pub use ncurses::{ACS_S3, ACS_S7, ACS_LEQUAL, ACS_GEQUAL, ACS_PI, ACS_NEQUAL, ACS_STERLING};
pub use ncurses::{ACS_BSSB, ACS_SSBB, ACS_BBSS, ACS_SBBS, ACS_SBSS, ACS_SSSB, ACS_SSBS};
pub use ncurses::{ACS_BSSS, ACS_BSBS, ACS_SBSB, ACS_SSSS};

fn NCURSES_BITS(mask: u32, shift: u32) -> u32 {
    mask << (shift + NCURSES_ATTR_SHIFT) as usize
}

pub fn COLOR_PAIR(n: chtype) -> attr_t {
    NCURSES_BITS(n as u32, 0u32) as attr_t
}

pub const COLOR_BLACK: i16 = 0;
pub const COLOR_RED: i16 = 1;
pub const COLOR_GREEN: i16 = 2;
pub const COLOR_YELLOW: i16 = 3;
pub const COLOR_BLUE: i16 = 4;
pub const COLOR_MAGENTA: i16 = 5;
pub const COLOR_CYAN: i16 = 6;
pub const COLOR_WHITE: i16 = 7;

pub const A_ALTCHARSET: attr_t = (1u32 << (14u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_ATTRIBUTES: attr_t = (!0u32 << (0u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_BLINK: attr_t = (1u32 << (11u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_BOLD: attr_t = (1u32 << (13u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_CHARTEXT: attr_t = (1u32 << (0u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_COLOR: attr_t = ((((1u32) << 8) - 1u32) << (0u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_DIM: attr_t = (1u32 << (12u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_ITALIC: attr_t = (1u32 << (23 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_INVIS: attr_t = (1u32 << (15u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_LEFTLINE: attr_t = 0; // Not supported on ncurses
pub const A_NORMAL: attr_t = 0u32 as attr_t;
pub const A_OVERLINE: attr_t = 0; // Not supported on ncurses
pub const A_REVERSE: attr_t = (1u32 << (10 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_RIGHTLINE: attr_t = 0; // Not supported on ncurses
pub const A_STANDOUT: attr_t = (1u32 << (8 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_STRIKEOUT: attr_t = 0; // Not supported on ncurses
pub const A_UNDERLINE: attr_t = (1u32 << (9 + NCURSES_ATTR_SHIFT)) as attr_t;

pub const KEY_RESIZE: i32 = 0632;

pub const KEY_OFFSET: i32 = 0o0400;
pub const KEY_F15: i32 = (KEY_OFFSET + 0x17);
pub const KEY_EVENT: i32 = (KEY_OFFSET + 0o633);

pub const SPECIAL_KEY_CODES: [Input; 108] = [Input::KeyCodeYes,

                                             Input::KeyBreak,
                                             Input::KeyDown,
                                             Input::KeyUp,
                                             Input::KeyLeft,
                                             Input::KeyRight,
                                             Input::KeyHome,
                                             Input::KeyBackspace,

                                             Input::KeyF0,
                                             Input::KeyF1,
                                             Input::KeyF2,
                                             Input::KeyF3,
                                             Input::KeyF4,
                                             Input::KeyF5,
                                             Input::KeyF6,
                                             Input::KeyF7,
                                             Input::KeyF8,
                                             Input::KeyF9,
                                             Input::KeyF10,
                                             Input::KeyF11,
                                             Input::KeyF12,
                                             Input::KeyF13,
                                             Input::KeyF14,
                                             Input::KeyF15,
                                             // ncurses reserves space for 64 function keys, but we've
                                             // only implemented 15. This has to be taken into account
                                             // when converting the integer into an index of this array
                                             Input::KeyDL,
                                             Input::KeyIL,
                                             Input::KeyDC,
                                             Input::KeyIC,
                                             Input::KeyEIC,
                                             Input::KeyClear,
                                             Input::KeyEOS,
                                             Input::KeyEOL,
                                             Input::KeySF,
                                             Input::KeySR,
                                             Input::KeyNPage,
                                             Input::KeyPPage,
                                             Input::KeySTab,
                                             Input::KeyCTab,
                                             Input::KeyCATab,
                                             Input::KeyEnter,
                                             Input::KeySReset,
                                             Input::KeyReset,
                                             Input::KeyPrint,
                                             Input::KeyLL,
                                             Input::KeyA1,
                                             Input::KeyA3,
                                             Input::KeyB2,
                                             Input::KeyC1,
                                             Input::KeyC3,
                                             Input::KeyBTab,
                                             Input::KeyBeg,
                                             Input::KeyCancel,
                                             Input::KeyClose,
                                             Input::KeyCommand,
                                             Input::KeyCopy,
                                             Input::KeyCreate,
                                             Input::KeyEnd,
                                             Input::KeyExit,
                                             Input::KeyFind,
                                             Input::KeyHelp,
                                             Input::KeyMark,
                                             Input::KeyMessage,
                                             Input::KeyMove,
                                             Input::KeyNext,
                                             Input::KeyOpen,
                                             Input::KeyOptions,
                                             Input::KeyPrevious,
                                             Input::KeyRedo,
                                             Input::KeyReference,
                                             Input::KeyRefresh,
                                             Input::KeyReplace,
                                             Input::KeyRestart,
                                             Input::KeyResume,
                                             Input::KeySave,
                                             Input::KeySBeg,
                                             Input::KeySCancel,
                                             Input::KeySCommand,
                                             Input::KeySCopy,
                                             Input::KeySCreate,
                                             Input::KeySDC,
                                             Input::KeySDL,
                                             Input::KeySelect,
                                             Input::KeySEnd,
                                             Input::KeySEOL,
                                             Input::KeySExit,
                                             Input::KeySFind,
                                             Input::KeySHelp,
                                             Input::KeySHome,
                                             Input::KeySIC,

                                             Input::KeySLeft,
                                             Input::KeySMessage,
                                             Input::KeySMove,
                                             Input::KeySNext,
                                             Input::KeySOptions,
                                             Input::KeySPrevious,
                                             Input::KeySPrint,
                                             Input::KeySRedo,
                                             Input::KeySReplace,
                                             Input::KeySRight,
                                             Input::KeySResume,
                                             Input::KeySSave,
                                             Input::KeySSuspend,
                                             Input::KeySUndo,
                                             Input::KeySuspend,
                                             Input::KeyUndo,
                                             Input::KeyMouse,
                                             Input::KeyResize,
                                             Input::KeyEvent];

pub const ALL_MOUSE_EVENTS: mmask_t = ncurses::ALL_MOUSE_EVENTS as mmask_t;<|endoftext|>


<commit_before>use crate::FileTime;
use std::ffi::CString;
use std::fs::File;
use std::io;
use std::os::unix::prelude::*;
use std::path::Path;

pub fn set_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> {
    set_times(p, Some(atime), Some(mtime), false)
}

pub fn set_file_mtime(p: &Path, mtime: FileTime) -> io::Result<()> {
    set_times(p, None, Some(mtime), false)
}

pub fn set_file_atime(p: &Path, atime: FileTime) -> io::Result<()> {
    set_times(p, Some(atime), None, false)
}

pub fn set_file_handle_times(
    f: &File,
    atime: Option<FileTime>,
    mtime: Option<FileTime>,
) -> io::Result<()> {
    let times = [super::to_timespec(&atime), super::to_timespec(&mtime)];
    let rc = unsafe { libc::futimens(f.as_raw_fd(), times.as_ptr()) };
    if rc == 0 {
        Ok(())
    } else {
        Err(io::Error::last_os_error())
    }
}

pub fn set_symlink_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> {
    set_times(p, Some(atime), Some(mtime), false)
}

fn set_times(
    p: &Path,
    atime: Option<FileTime>,
    mtime: Option<FileTime>,
    symlink: bool,
) -> io::Result<()> {
    let flags = if symlink {
        libc::AT_SYMLINK_NOFOLLOW
    } else {
        0
    };

    let p = CString::new(p.as_os_str().as_bytes())?;
    let times = [super::to_timespec(&atime), super::to_timespec(&mtime)];
    let rc = unsafe { libc::utimensat(libc::AT_FDCWD, p.as_ptr(), times.as_ptr(), flags) };
    if rc == 0 {
        Ok(())
    } else {
        Err(io::Error::last_os_error())
    }
}
<commit_msg>utimensat.rs: remove use of futimens (#57)<commit_after>use crate::FileTime;
use std::ffi::CString;
use std::fs::File;
use std::io;
use std::os::unix::prelude::*;
use std::path::Path;

pub fn set_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> {
    set_times(p, Some(atime), Some(mtime), false)
}

pub fn set_file_mtime(p: &Path, mtime: FileTime) -> io::Result<()> {
    set_times(p, None, Some(mtime), false)
}

pub fn set_file_atime(p: &Path, atime: FileTime) -> io::Result<()> {
    set_times(p, Some(atime), None, false)
}

pub fn set_file_handle_times(
    f: &File,
    atime: Option<FileTime>,
    mtime: Option<FileTime>,
) -> io::Result<()> {
    let times = [super::to_timespec(&atime), super::to_timespec(&mtime)];
    let rc = unsafe { libc::utimensat(f.as_raw_fd(), core::ptr::null(), times.as_ptr(), 0) };
    if rc == 0 {
        Ok(())
    } else {
        Err(io::Error::last_os_error())
    }
}

pub fn set_symlink_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> {
    set_times(p, Some(atime), Some(mtime), false)
}

fn set_times(
    p: &Path,
    atime: Option<FileTime>,
    mtime: Option<FileTime>,
    symlink: bool,
) -> io::Result<()> {
    let flags = if symlink {
        libc::AT_SYMLINK_NOFOLLOW
    } else {
        0
    };

    let p = CString::new(p.as_os_str().as_bytes())?;
    let times = [super::to_timespec(&atime), super::to_timespec(&mtime)];
    let rc = unsafe { libc::utimensat(libc::AT_FDCWD, p.as_ptr(), times.as_ptr(), flags) };
    if rc == 0 {
        Ok(())
    } else {
        Err(io::Error::last_os_error())
    }
}
<|endoftext|>


<commit_before>use std::io::Read;

use itertools::Itertools;

use crate::common::ordered;

fn compute_groups<'a>(it: impl IntoIterator<Item = &'a usize>) -> Vec<(usize, usize)> {
    let mut it = it.into_iter().copied().dedup_with_count();

    let (mut population, mut last_pos) = it.next().unwrap();
    let mut last_cost = 0;

    let mut costs = vec![(last_pos, 0)];

    for (number, pos) in it {
        let (first, last) = ordered(last_pos, pos);
        let new_cost = last_cost + population * (last - first);

        costs.push((pos, new_cost));

        population += number;
        last_pos = pos;
        last_cost = new_cost;
    }

    costs
}

fn read_input(input: &mut dyn Read) -> Vec<usize> {
    let mut buf = String::new();
    input.read_to_string(&mut buf).unwrap();

    let mut crabs: Vec<usize> = buf
        .trim_end()
        .split(',')
        .map(|s| s.parse().unwrap())
        .collect();

    crabs.sort_unstable();

    crabs
}

pub fn part1(input: &mut dyn Read) -> String {
    let crabs = read_input(input);

    let forward_costs = compute_groups(&crabs);
    let backwards_costs = compute_groups(crabs.iter().rev());

    backwards_costs
        .into_iter()
        .rev()
        .zip(forward_costs)
        .map(|((_, cost_b), (_, cost_f))| cost_f + cost_b)
        .min()
        .unwrap()
        .to_string()
}

pub fn sum_until(end: usize) -> usize {
    (end * (1 + end)) / 2
}

fn cost_at(pos: usize, groups: &[(usize, usize)]) -> usize {
    groups
        .iter()
        .map(|&(number, new_pos)| {
            let (first, last) = ordered(pos, new_pos);

            number * sum_until(last - first)
        })
        .sum()
}

fn ternary_search(groups: &[(usize, usize)], mut min: usize, mut max: usize) -> usize {
    while max - min > 6 {
        let mid1 = min + (max - min) / 3;
        let mid2 = max - (max - min) / 3;

        let cost1 = cost_at(mid1, groups);
        let cost2 = cost_at(mid2, groups);

        if cost1 < cost2 {
            max = mid2 - 1
        } else {
            min = mid1 + 1
        }
    }

    // Ternary search isn't effective at such small intervals so we iterate the remaining part
    (min..=max).map(|pos| cost_at(pos, groups)).min().unwrap()
}

pub fn part2(input: &mut dyn Read) -> String {
    let crabs = read_input(input);
    let groups: Vec<_> = crabs.into_iter().dedup_with_count().collect();

    let min = groups.first().unwrap().1;
    let max = groups.last().unwrap().1;

    ternary_search(&groups, min, max).to_string()
}

#[cfg(test)]
mod tests {
    use crate::test_implementation;

    use super::*;

    const SAMPLE: &[u8] = &*b"16,1,2,0,4,2,7,1,2,14";

    #[test]
    fn sample_part1() {
        test_implementation(part1, SAMPLE, 37);
    }

    #[test]
    fn sample_part2() {
        test_implementation(part2, SAMPLE, 168);
    }

    #[test]
    fn test_maths() {
        assert_eq!(sum_until(1), 1);
        assert_eq!(sum_until(2), 3);
        assert_eq!(sum_until(3), 6);
        assert_eq!(sum_until(4), 10);
    }
}
<commit_msg>Avoid more allocations in day 7 part 1<commit_after>use std::io::Read;

use itertools::Itertools;

use crate::common::ordered;

fn compute_cumulative<'a, I, It>(it: I) -> Vec<usize>
where
    I: IntoIterator<IntoIter = It>,
    It: Iterator<Item = &'a (usize, usize)> + ExactSizeIterator,
{
    let mut it = it.into_iter().copied();
    let mut costs = Vec::with_capacity(it.len());
    costs.push(0);

    let (mut population, mut last_pos) = it.next().unwrap();
    let mut last_cost = 0;

    for (number, pos) in it {
        let (first, last) = ordered(last_pos, pos);
        let new_cost = last_cost + population * (last - first);

        population += number;
        last_pos = pos;
        last_cost = new_cost;

        costs.push(new_cost);
    }

    costs
}

fn read_input(input: &mut dyn Read) -> Vec<(usize, usize)> {
    let mut buf = String::new();
    input.read_to_string(&mut buf).unwrap();

    let mut crabs: Vec<usize> = buf
        .trim_end()
        .split(',')
        .map(|s| s.parse().unwrap())
        .collect();

    crabs.sort_unstable();

    crabs.into_iter().dedup_with_count().collect()
}

pub fn part1(input: &mut dyn Read) -> String {
    let crabs = read_input(input);

    let forwards_costs = compute_cumulative(&crabs);
    let backwards_costs = compute_cumulative(crabs.iter().rev());

    // Note: the optimal position can be proven to be one of the original positions.
    ternary_search(0, forwards_costs.len() - 1, |idx| {
        forwards_costs[idx] + backwards_costs[backwards_costs.len() - 1 - idx]
    })
    .to_string()
}

pub fn sum_until(end: usize) -> usize {
    (end * (1 + end)) / 2
}

fn cost_at(pos: usize, groups: &[(usize, usize)]) -> usize {
    groups
        .iter()
        .map(|&(number, new_pos)| {
            let (first, last) = ordered(pos, new_pos);

            number * sum_until(last - first)
        })
        .sum()
}

fn ternary_search(mut min: usize, mut max: usize, callback: impl Fn(usize) -> usize) -> usize {
    while max - min > 6 {
        let mid1 = min + (max - min) / 3;
        let mid2 = max - (max - min) / 3;

        let cost1 = callback(mid1);
        let cost2 = callback(mid2);

        if cost1 < cost2 {
            max = mid2 - 1
        } else {
            min = mid1 + 1
        }
    }

    // Ternary search isn't effective at such small intervals so we iterate the remaining part
    (min..=max).map(callback).min().unwrap()
}

pub fn part2(input: &mut dyn Read) -> String {
    let groups = read_input(input);

    let min = groups.first().unwrap().1;
    let max = groups.last().unwrap().1;

    ternary_search(min, max, |pos| cost_at(pos, &groups)).to_string()
}

#[cfg(test)]
mod tests {
    use crate::test_implementation;

    use super::*;

    const SAMPLE: &[u8] = &*b"16,1,2,0,4,2,7,1,2,14";

    #[test]
    fn sample_part1() {
        test_implementation(part1, SAMPLE, 37);
    }

    #[test]
    fn sample_part2() {
        test_implementation(part2, SAMPLE, 168);
    }

    #[test]
    fn test_maths() {
        assert_eq!(sum_until(1), 1);
        assert_eq!(sum_until(2), 3);
        assert_eq!(sum_until(3), 6);
        assert_eq!(sum_until(4), 10);
    }
}
<|endoftext|>