<commit_before>extern crate glib;

extern crate gtk;
use gtk::{Inhibit, WidgetExt};

extern crate cairo;

use std::rc::Rc;
use std::cell::RefCell;

use std::sync::{Arc, Mutex};

use ::media::{Context, AudioBuffer};

pub struct AudioController {
    container: gtk::Container,
    drawingarea: gtk::DrawingArea,

    audio_buffer: Arc<Mutex<AudioBuffer>>,
    can_draw: bool,
    position: u64,
}

impl AudioController {
    pub fn new(builder: &gtk::Builder) -> Rc<RefCell<Self>> {
        let this = Rc::new(RefCell::new(AudioController {
            container: builder.get_object("audio-container").unwrap(),
            drawingarea: builder.get_object("audio-drawingarea").unwrap(),

            audio_buffer: Arc::new(Mutex::new(AudioBuffer::new())),
            can_draw: false,
            position: 0,
        }));

        {
            let this_ref = this.borrow();
            let this_weak = Rc::downgrade(&this);
            this_ref.drawingarea.connect_draw(move |drawing_area, cairo_ctx| {
                let this = this_weak.upgrade()
                    .expect("Main controller is no longer available for select_media");
                let result = this.borrow_mut().draw(drawing_area, cairo_ctx);
                result
            });
        }

        this
    }

    pub fn cleanup(&mut self) {
        self.can_draw = false;
        self.position = 0;
    }

    pub fn new_media(&mut self, ctx: &Context) {
        let has_audio = {
            let ctx_info = ctx.info.lock()
                .expect("Failed to lock media info while initializing audio controller");
            ctx_info.audio_best.is_some()
        };

        if has_audio {
            let position = ctx.get_position();
            if position.is_negative() {
                panic!("Audio controller found a negative initial position");
            }
            self.position = position as u64;

            self.audio_buffer = ctx.audio_buffer.clone();
            {
                let audio_buffer = &mut self.audio_buffer.lock()
                    .expect("Failed to lock audio buffer while initializing audio controller");
                audio_buffer.set_first_pts(self.position);
            }

            self.can_draw = true;
            self.drawingarea.queue_draw();
            self.container.show();
        }
        else {
            self.container.hide();
        }
    }

    pub fn have_position(&mut self, position: i64) {
        if position.is_negative() {
            panic!("Audio controller received a negative position");
        }

        let position = position as u64;

        if self.position != position {
            self.position = position;
            self.drawingarea.queue_draw();
        }
    }

    fn draw(&mut self, drawing_area: &gtk::DrawingArea, cr: &cairo::Context) -> Inhibit {
        if !self.can_draw {
            return Inhibit(false);
        }
        let allocation = drawing_area.get_allocation();
        let width = allocation.width;
        if width.is_negative() {
            return Inhibit(false);
        }
        let width = width as u64;

        let display_window_duration = 2_000_000_000; // 2s TODO: adapt according to zoom

        // TODO: make width and height adapt to zoom
        cr.scale((width / 2) as f64, (allocation.height / 2) as f64);
        cr.set_line_width(0.0015f64);
        cr.set_source_rgb(0.8f64, 0.8f64, 0.8f64);

        let first_display_pos = {
            let audio_buffer = &mut self.audio_buffer.lock()
                .expect("Couldn't lock audio buffer in audio controller draw");
            audio_buffer.set_pts(self.position);

            if audio_buffer.duration == 0 {
                return Inhibit(false);
            }

            let diplay_window_sample_nb = display_window_duration / audio_buffer.sample_duration;
            let sample_per_pixel =
                if diplay_window_sample_nb > width {
                    diplay_window_sample_nb / width
                } else {
                    1
                };

            let pixel_duration = sample_per_pixel * audio_buffer.sample_duration;

            let display_duration = audio_buffer.duration.min(display_window_duration);
            let half_duration = display_duration / 2;

            let first_display_pos =
                if self.position > audio_buffer.last_pts - half_duration {
                    audio_buffer.last_pts - display_duration
                } else if self.position > audio_buffer.first_pts + half_duration {
                    self.position - half_duration
                } else {
                    0
                };

            // align first display pos as a multiple of pixel duration
            // in order to avoid discontinuities when origin shifts between redraws
            let aligned_first_display_pos = (first_display_pos / pixel_duration) * pixel_duration;

            let first_sample =
                (aligned_first_display_pos / audio_buffer.sample_duration) as usize
                - audio_buffer.first_sample_offset;

            let sample_step = sample_per_pixel as usize;
            let last_sample =
                first_sample
                + (display_duration / audio_buffer.sample_duration) as usize
                + sample_step; // add one step to compensate the offset due to aligned_first_display_pos
            let last_sample = last_sample.min(audio_buffer.samples.len());

            let mut relative_pts =
                (0f64 - ((first_display_pos - aligned_first_display_pos) as f64))
                 / 1_000_000_000f64;
            let duration_step = pixel_duration as f64 / 1_000_000_000f64;

            let mut sample_idx = first_sample;

            cr.move_to(relative_pts, audio_buffer.samples[sample_idx]);
            relative_pts += duration_step;
            sample_idx += sample_step;

            while sample_idx < last_sample {
                cr.line_to(relative_pts, audio_buffer.samples[sample_idx]);
                relative_pts += duration_step;
                sample_idx += sample_step;
            }

            first_display_pos
        };

        cr.stroke();

        // draw current pos
        let x = (self.position - first_display_pos) as f64 / 1_000_000_000f64;
        cr.set_source_rgb(1f64, 1f64, 0f64);
        cr.set_line_width(0.004f64);
        cr.move_to(x, 0f64);
        cr.line_to(x, 2f64);
        cr.stroke();

        Inhibit(false)
    }
}
<commit_msg>Better handling for AudioBuffer duration smaller than window duration (#19)<commit_after>extern crate glib;

extern crate gtk;
use gtk::{Inhibit, WidgetExt};

extern crate cairo;

use std::rc::Rc;
use std::cell::RefCell;

use std::sync::{Arc, Mutex};

use ::media::{Context, AudioBuffer};

pub struct AudioController {
    container: gtk::Container,
    drawingarea: gtk::DrawingArea,

    audio_buffer: Arc<Mutex<AudioBuffer>>,
    can_draw: bool,
    position: u64,
}

impl AudioController {
    pub fn new(builder: &gtk::Builder) -> Rc<RefCell<Self>> {
        let this = Rc::new(RefCell::new(AudioController {
            container: builder.get_object("audio-container").unwrap(),
            drawingarea: builder.get_object("audio-drawingarea").unwrap(),

            audio_buffer: Arc::new(Mutex::new(AudioBuffer::new())),
            can_draw: false,
            position: 0,
        }));

        {
            let this_ref = this.borrow();
            let this_weak = Rc::downgrade(&this);
            this_ref.drawingarea.connect_draw(move |drawing_area, cairo_ctx| {
                let this = this_weak.upgrade()
                    .expect("Main controller is no longer available for select_media");
                let result = this.borrow_mut().draw(drawing_area, cairo_ctx);
                result
            });
        }

        this
    }

    pub fn cleanup(&mut self) {
        self.can_draw = false;
        self.position = 0;
    }

    pub fn new_media(&mut self, ctx: &Context) {
        let has_audio = {
            let ctx_info = ctx.info.lock()
                .expect("Failed to lock media info while initializing audio controller");
            ctx_info.audio_best.is_some()
        };

        if has_audio {
            let position = ctx.get_position();
            if position.is_negative() {
                panic!("Audio controller found a negative initial position");
            }
            self.position = position as u64;

            self.audio_buffer = ctx.audio_buffer.clone();
            {
                let audio_buffer = &mut self.audio_buffer.lock()
                    .expect("Failed to lock audio buffer while initializing audio controller");
                audio_buffer.set_first_pts(self.position);
            }

            self.can_draw = true;
            self.drawingarea.queue_draw();
            self.container.show();
        }
        else {
            self.container.hide();
        }
    }

    pub fn have_position(&mut self, position: i64) {
        if position.is_negative() {
            panic!("Audio controller received a negative position");
        }

        let position = position as u64;

        if self.position != position {
            self.position = position;
            self.drawingarea.queue_draw();
        }
    }

    fn draw(&mut self, drawing_area: &gtk::DrawingArea, cr: &cairo::Context) -> Inhibit {
        if !self.can_draw {
            return Inhibit(false);
        }
        let allocation = drawing_area.get_allocation();
        let width = allocation.width;
        if width.is_negative() {
            return Inhibit(false);
        }
        let width = width as u64;

        let display_window_duration = 2_000_000_000; // 2s TODO: adapt according to zoom

        // TODO: make width and height adapt to zoom
        cr.scale((width / 2) as f64, (allocation.height / 2) as f64);
        cr.set_line_width(0.0015f64);
        cr.set_source_rgb(0.8f64, 0.8f64, 0.8f64);

        let first_display_pos = {
            let audio_buffer = &mut self.audio_buffer.lock()
                .expect("Couldn't lock audio buffer in audio controller draw");
            audio_buffer.set_pts(self.position);

            if audio_buffer.duration == 0 {
                return Inhibit(false);
            }

            let diplay_window_sample_nb = display_window_duration / audio_buffer.sample_duration;
            let sample_per_pixel =
                if diplay_window_sample_nb > width {
                    diplay_window_sample_nb / width
                } else {
                    1
                };

            let pixel_duration = sample_per_pixel * audio_buffer.sample_duration;

            let (first_display_pos, display_duration) =
                if audio_buffer.duration < display_window_duration {
                    (0, audio_buffer.duration)
                } else {
                    let half_duration = display_window_duration / 2;
                    let first_display_pos =
                        if self.position > audio_buffer.last_pts - half_duration {
                            audio_buffer.last_pts - display_window_duration
                        } else if self.position > audio_buffer.first_pts + half_duration {
                            self.position - half_duration
                        } else {
                            0
                        };
                    (first_display_pos, display_window_duration)
                };

            // align first display pos as a multiple of pixel duration
            // in order to avoid discontinuities when origin shifts between redraws
            let aligned_first_display_pos = (first_display_pos / pixel_duration) * pixel_duration;

            let first_sample =
                (aligned_first_display_pos / audio_buffer.sample_duration) as usize
                - audio_buffer.first_sample_offset;

            let sample_step = sample_per_pixel as usize;
            let last_sample =
                first_sample
                + (display_duration / audio_buffer.sample_duration) as usize
                + sample_step; // add one step to compensate the offset due to aligned_first_display_pos
            let last_sample = last_sample.min(audio_buffer.samples.len());

            let mut relative_pts =
                (0f64 - ((first_display_pos - aligned_first_display_pos) as f64))
                 / 1_000_000_000f64;
            let duration_step = pixel_duration as f64 / 1_000_000_000f64;

            let mut sample_idx = first_sample;

            cr.move_to(relative_pts, audio_buffer.samples[sample_idx]);
            relative_pts += duration_step;
            sample_idx += sample_step;

            while sample_idx < last_sample {
                cr.line_to(relative_pts, audio_buffer.samples[sample_idx]);
                relative_pts += duration_step;
                sample_idx += sample_step;
            }

            first_display_pos
        };

        cr.stroke();

        // draw current pos
        let x = (self.position - first_display_pos) as f64 / 1_000_000_000f64;
        cr.set_source_rgb(1f64, 1f64, 0f64);
        cr.set_line_width(0.004f64);
        cr.move_to(x, 0f64);
        cr.line_to(x, 2f64);
        cr.stroke();

        Inhibit(false)
    }
}
<|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 super::apply_transforms::Programs;
pub use super::artifact_content::ArtifactContent;
use super::build_ir::SourceHashes;
use crate::config::ProjectConfig;
use crate::errors::BuildProjectError;
use common::{NamedItem, SourceLocationKey};
use graphql_ir::{FragmentDefinition, OperationDefinition};
use graphql_text_printer::print_full_operation;
use interner::StringKey;
use relay_transforms::{
    RefetchableDerivedFromMetadata, SplitOperationMetadata, DIRECTIVE_SPLIT_OPERATION,
};
use relay_typegen::TypegenLanguage;
use std::path::PathBuf;
use std::sync::Arc;

/// Represents a generated output artifact.
pub struct Artifact {
    pub source_definition_names: Vec<StringKey>,
    pub path: PathBuf,
    pub content: ArtifactContent,
    /// The source file responsible for generating this file.
    /// For example: `my_project/Component.react.js`
    pub source_file: SourceLocationKey,
}

pub fn generate_artifacts(
    project_config: &ProjectConfig,
    programs: &Programs,
    source_hashes: Arc<SourceHashes>,
) -> Result<Vec<Artifact>, BuildProjectError> {
    let mut artifacts = Vec::new();
    for normalization_operation in programs.normalization.operations() {
        if let Some(directive) = normalization_operation
            .directives
            .named(*DIRECTIVE_SPLIT_OPERATION)
        {
            // Generate normalization file for SplitOperation
            let metadata = SplitOperationMetadata::from(directive);
            let source_fragment = programs
                .source
                .fragment(metadata.derived_from)
                .expect("Expected the source document for the SplitOperation to exist.");
            let source_hash = source_hashes.get(&metadata.derived_from).cloned().unwrap();
            let source_file = source_fragment.name.location.source_location();

            artifacts.push(Artifact {
                source_definition_names: metadata.parent_sources.into_iter().collect(),
                path: path_for_artifact(
                    project_config,
                    source_file,
                    normalization_operation.name.item,
                ),
                content: ArtifactContent::SplitOperation {
                    normalization_operation: Arc::clone(normalization_operation),
                    source_hash,
                },
                source_file,
            });
        } else if let Some(source_name) =
            RefetchableDerivedFromMetadata::from_directives(&normalization_operation.directives)
        {
            let source_fragment = programs
                .source
                .fragment(source_name)
                .expect("Expected the source document for the SplitOperation to exist.");
            let source_hash = source_hashes.get(&source_name).cloned().unwrap();

            artifacts.push(generate_normalization_artifact(
                source_name,
                project_config,
                programs,
                normalization_operation,
                source_hash,
                source_fragment.name.location.source_location(),
            )?);
        } else {
            let source_hash = source_hashes
                .get(&normalization_operation.name.item)
                .cloned()
                .unwrap();
            artifacts.push(generate_normalization_artifact(
                normalization_operation.name.item,
                project_config,
                programs,
                normalization_operation,
                source_hash,
                normalization_operation.name.location.source_location(),
            )?);
        }
    }

    for reader_fragment in programs.reader.fragments() {
        let source_hash = source_hashes
            .get(&reader_fragment.name.item)
            .cloned()
            .unwrap();
        artifacts.push(generate_reader_artifact(
            project_config,
            programs,
            reader_fragment,
            source_hash,
        ));
    }

    Ok(artifacts)
}

fn generate_normalization_artifact<'a>(
    source_definition_name: StringKey,
    project_config: &ProjectConfig,
    programs: &'a Programs,
    normalization_operation: &Arc<OperationDefinition>,
    source_hash: String,
    source_file: SourceLocationKey,
) -> Result<Artifact, BuildProjectError> {
    let name = normalization_operation.name.item;
    let print_operation = programs
        .operation_text
        .operation(name)
        .expect("a query text operation should be generated for this operation");
    let text = print_full_operation(&programs.operation_text, print_operation);
    let reader_operation = programs
        .reader
        .operation(name)
        .expect("a reader fragment should be generated for this operation");
    let typegen_operation = programs
        .typegen
        .operation(name)
        .expect("a type fragment should be generated for this operation");
    Ok(Artifact {
        source_definition_names: vec![source_definition_name],
        path: path_for_artifact(project_config, source_file, name),
        content: ArtifactContent::Operation {
            normalization_operation: Arc::clone(normalization_operation),
            reader_operation: Arc::clone(reader_operation),
            typegen_operation: Arc::clone(typegen_operation),
            source_hash,
            text,
            id_and_text_hash: None,
        },
        source_file: normalization_operation.name.location.source_location(),
    })
}

fn generate_reader_artifact(
    project_config: &ProjectConfig,
    programs: &Programs,
    reader_fragment: &Arc<FragmentDefinition>,
    source_hash: String,
) -> Artifact {
    let name = reader_fragment.name.item;
    let typegen_fragment = programs
        .typegen
        .fragment(name)
        .expect("a type fragment should be generated for this fragment");
    Artifact {
        source_definition_names: vec![name],
        path: path_for_artifact(
            project_config,
            reader_fragment.name.location.source_location(),
            name,
        ),
        content: ArtifactContent::Fragment {
            reader_fragment: Arc::clone(reader_fragment),
            typegen_fragment: Arc::clone(typegen_fragment),
            source_hash,
        },
        source_file: reader_fragment.name.location.source_location(),
    }
}

/// This function will create a correct path for artifact based on the project configuration
pub fn create_path_for_artifact(
    project_config: &ProjectConfig,
    source_file: SourceLocationKey,
    artifact_file_name: String,
    use_extra_artifact_dir: bool,
) -> PathBuf {
    // For artifacts output dir, first, we will check if we need to use extra output dir
    // and if it's specified in the options, we will return that path
    if use_extra_artifact_dir {
        if let Some(extra_artifacts_output) = &project_config.extra_artifacts_output {
            return extra_artifacts_output.join(artifact_file_name);
        }
    }

    // Otherwise, we will use default project output dif (and settings)
    match &project_config.output {
        Some(output) => {
            if project_config.shard_output {
                if let Some(ref regex) = project_config.shard_strip_regex {
                    let full_source_path = regex.replace_all(source_file.path(), "");
                    let mut output = output.join(full_source_path.to_string());
                    output.pop();
                    output
                } else {
                    output.join(source_file.get_dir())
                }
                .join(artifact_file_name)
            } else {
                output.join(artifact_file_name)
            }
        }
        None => {
            let path = source_file.get_dir();
            path.join(format!("__generated__/{}", artifact_file_name))
        }
    }
}

fn path_for_artifact(
    project_config: &ProjectConfig,
    source_file: SourceLocationKey,
    definition_name: StringKey,
) -> PathBuf {
    create_path_for_artifact(
        project_config,
        source_file,
        match &project_config.typegen_config.language {
            TypegenLanguage::Flow => format!("{}.graphql.js", definition_name),
            TypegenLanguage::TypeScript => format!("{}.graphql.ts", definition_name),
        },
        false,
    )
}
<commit_msg>remove use_extra_artifact_dir bool flag<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use super::apply_transforms::Programs;
pub use super::artifact_content::ArtifactContent;
use super::build_ir::SourceHashes;
use crate::config::ProjectConfig;
use crate::errors::BuildProjectError;
use common::{NamedItem, SourceLocationKey};
use graphql_ir::{FragmentDefinition, OperationDefinition};
use graphql_text_printer::print_full_operation;
use interner::StringKey;
use relay_transforms::{
    RefetchableDerivedFromMetadata, SplitOperationMetadata, DIRECTIVE_SPLIT_OPERATION,
};
use relay_typegen::TypegenLanguage;
use std::path::PathBuf;
use std::sync::Arc;

/// Represents a generated output artifact.
pub struct Artifact {
    pub source_definition_names: Vec<StringKey>,
    pub path: PathBuf,
    pub content: ArtifactContent,
    /// The source file responsible for generating this file.
    /// For example: `my_project/Component.react.js`
    pub source_file: SourceLocationKey,
}

pub fn generate_artifacts(
    project_config: &ProjectConfig,
    programs: &Programs,
    source_hashes: Arc<SourceHashes>,
) -> Result<Vec<Artifact>, BuildProjectError> {
    let mut artifacts = Vec::new();
    for normalization_operation in programs.normalization.operations() {
        if let Some(directive) = normalization_operation
            .directives
            .named(*DIRECTIVE_SPLIT_OPERATION)
        {
            // Generate normalization file for SplitOperation
            let metadata = SplitOperationMetadata::from(directive);
            let source_fragment = programs
                .source
                .fragment(metadata.derived_from)
                .expect("Expected the source document for the SplitOperation to exist.");
            let source_hash = source_hashes.get(&metadata.derived_from).cloned().unwrap();
            let source_file = source_fragment.name.location.source_location();

            artifacts.push(Artifact {
                source_definition_names: metadata.parent_sources.into_iter().collect(),
                path: path_for_artifact(
                    project_config,
                    source_file,
                    normalization_operation.name.item,
                ),
                content: ArtifactContent::SplitOperation {
                    normalization_operation: Arc::clone(normalization_operation),
                    source_hash,
                },
                source_file,
            });
        } else if let Some(source_name) =
            RefetchableDerivedFromMetadata::from_directives(&normalization_operation.directives)
        {
            let source_fragment = programs
                .source
                .fragment(source_name)
                .expect("Expected the source document for the SplitOperation to exist.");
            let source_hash = source_hashes.get(&source_name).cloned().unwrap();

            artifacts.push(generate_normalization_artifact(
                source_name,
                project_config,
                programs,
                normalization_operation,
                source_hash,
                source_fragment.name.location.source_location(),
            )?);
        } else {
            let source_hash = source_hashes
                .get(&normalization_operation.name.item)
                .cloned()
                .unwrap();
            artifacts.push(generate_normalization_artifact(
                normalization_operation.name.item,
                project_config,
                programs,
                normalization_operation,
                source_hash,
                normalization_operation.name.location.source_location(),
            )?);
        }
    }

    for reader_fragment in programs.reader.fragments() {
        let source_hash = source_hashes
            .get(&reader_fragment.name.item)
            .cloned()
            .unwrap();
        artifacts.push(generate_reader_artifact(
            project_config,
            programs,
            reader_fragment,
            source_hash,
        ));
    }

    Ok(artifacts)
}

fn generate_normalization_artifact<'a>(
    source_definition_name: StringKey,
    project_config: &ProjectConfig,
    programs: &'a Programs,
    normalization_operation: &Arc<OperationDefinition>,
    source_hash: String,
    source_file: SourceLocationKey,
) -> Result<Artifact, BuildProjectError> {
    let name = normalization_operation.name.item;
    let print_operation = programs
        .operation_text
        .operation(name)
        .expect("a query text operation should be generated for this operation");
    let text = print_full_operation(&programs.operation_text, print_operation);
    let reader_operation = programs
        .reader
        .operation(name)
        .expect("a reader fragment should be generated for this operation");
    let typegen_operation = programs
        .typegen
        .operation(name)
        .expect("a type fragment should be generated for this operation");
    Ok(Artifact {
        source_definition_names: vec![source_definition_name],
        path: path_for_artifact(project_config, source_file, name),
        content: ArtifactContent::Operation {
            normalization_operation: Arc::clone(normalization_operation),
            reader_operation: Arc::clone(reader_operation),
            typegen_operation: Arc::clone(typegen_operation),
            source_hash,
            text,
            id_and_text_hash: None,
        },
        source_file: normalization_operation.name.location.source_location(),
    })
}

fn generate_reader_artifact(
    project_config: &ProjectConfig,
    programs: &Programs,
    reader_fragment: &Arc<FragmentDefinition>,
    source_hash: String,
) -> Artifact {
    let name = reader_fragment.name.item;
    let typegen_fragment = programs
        .typegen
        .fragment(name)
        .expect("a type fragment should be generated for this fragment");
    Artifact {
        source_definition_names: vec![name],
        path: path_for_artifact(
            project_config,
            reader_fragment.name.location.source_location(),
            name,
        ),
        content: ArtifactContent::Fragment {
            reader_fragment: Arc::clone(reader_fragment),
            typegen_fragment: Arc::clone(typegen_fragment),
            source_hash,
        },
        source_file: reader_fragment.name.location.source_location(),
    }
}

/// This function will create a correct path for artifact based on the project configuration
pub fn create_path_for_artifact(
    project_config: &ProjectConfig,
    source_file: SourceLocationKey,
    artifact_file_name: String,
) -> PathBuf {
    if let Some(output) = &project_config.output {
        // If an output directory is specified, output into that directory.
        if project_config.shard_output {
            if let Some(ref regex) = project_config.shard_strip_regex {
                let full_source_path = regex.replace_all(source_file.path(), "");
                let mut output = output.join(full_source_path.to_string());
                output.pop();
                output
            } else {
                output.join(source_file.get_dir())
            }
            .join(artifact_file_name)
        } else {
            output.join(artifact_file_name)
        }
    } else {
        // Otherwise, output into a file relative to the source.
        source_file
            .get_dir()
            .join("__generated__")
            .join(artifact_file_name)
    }
}

fn path_for_artifact(
    project_config: &ProjectConfig,
    source_file: SourceLocationKey,
    definition_name: StringKey,
) -> PathBuf {
    create_path_for_artifact(
        project_config,
        source_file,
        match &project_config.typegen_config.language {
            TypegenLanguage::Flow => format!("{}.graphql.js", definition_name),
            TypegenLanguage::TypeScript => format!("{}.graphql.ts", definition_name),
        },
    )
}
<|endoftext|>


<commit_before>#![stable(feature = "futures_api", since = "1.36.0")]

use crate::fmt;
use crate::marker::{PhantomData, Unpin};

/// A `RawWaker` allows the implementor of a task executor to create a [`Waker`]
/// which provides customized wakeup behavior.
///
/// [vtable]: https://en.wikipedia.org/wiki/Virtual_method_table
///
/// It consists of a data pointer and a [virtual function pointer table (vtable)][vtable] that
/// customizes the behavior of the `RawWaker`.
///
/// [`Waker`]: struct.Waker.html
#[derive(PartialEq, Debug)]
#[stable(feature = "futures_api", since = "1.36.0")]
pub struct RawWaker {
    /// A data pointer, which can be used to store arbitrary data as required
    /// by the executor. This could be e.g. a type-erased pointer to an `Arc`
    /// that is associated with the task.
    /// The value of this field gets passed to all functions that are part of
    /// the vtable as the first parameter.
    data: *const (),
    /// Virtual function pointer table that customizes the behavior of this waker.
    vtable: &'static RawWakerVTable,
}

impl RawWaker {
    /// Creates a new `RawWaker` from the provided `data` pointer and `vtable`.
    ///
    /// The `data` pointer can be used to store arbitrary data as required
    /// by the executor. This could be e.g. a type-erased pointer to an `Arc`
    /// that is associated with the task.
    /// The value of this poiner will get passed to all functions that are part
    /// of the `vtable` as the first parameter.
    ///
    /// The `vtable` customizes the behavior of a `Waker` which gets created
    /// from a `RawWaker`. For each operation on the `Waker`, the associated
    /// function in the `vtable` of the underlying `RawWaker` will be called.
    #[rustc_promotable]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub const fn new(data: *const (), vtable: &'static RawWakerVTable) -> RawWaker {
        RawWaker {
            data,
            vtable,
        }
    }
}

/// A virtual function pointer table (vtable) that specifies the behavior
/// of a [`RawWaker`].
///
/// The pointer passed to all functions inside the vtable is the `data` pointer
/// from the enclosing [`RawWaker`] object.
///
/// The functions inside this struct are only intended be called on the `data`
/// pointer of a properly constructed [`RawWaker`] object from inside the
/// [`RawWaker`] implementation. Calling one of the contained functions using
/// any other `data` pointer will cause undefined behavior.
///
/// [`RawWaker`]: struct.RawWaker.html
#[stable(feature = "futures_api", since = "1.36.0")]
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct RawWakerVTable {
    /// This function will be called when the [`RawWaker`] gets cloned, e.g. when
    /// the [`Waker`] in which the [`RawWaker`] is stored gets cloned.
    ///
    /// The implementation of this function must retain all resources that are
    /// required for this additional instance of a [`RawWaker`] and associated
    /// task. Calling `wake` on the resulting [`RawWaker`] should result in a wakeup
    /// of the same task that would have been awoken by the original [`RawWaker`].
    ///
    /// [`Waker`]: struct.Waker.html
    /// [`RawWaker`]: struct.RawWaker.html
    clone: unsafe fn(*const ()) -> RawWaker,

    /// This function will be called when `wake` is called on the [`Waker`].
    /// It must wake up the task associated with this [`RawWaker`].
    ///
    /// The implementation of this function must make sure to release any
    /// resources that are associated with this instance of a [`RawWaker`] and
    /// associated task.
    ///
    /// [`Waker`]: struct.Waker.html
    /// [`RawWaker`]: struct.RawWaker.html
    wake: unsafe fn(*const ()),

    /// This function will be called when `wake_by_ref` is called on the [`Waker`].
    /// It must wake up the task associated with this [`RawWaker`].
    ///
    /// This function is similar to `wake`, but must not consume the provided data
    /// pointer.
    ///
    /// [`Waker`]: struct.Waker.html
    /// [`RawWaker`]: struct.RawWaker.html
    wake_by_ref: unsafe fn(*const ()),

    /// This function gets called when a [`RawWaker`] gets dropped.
    ///
    /// The implementation of this function must make sure to release any
    /// resources that are associated with this instance of a [`RawWaker`] and
    /// associated task.
    ///
    /// [`RawWaker`]: struct.RawWaker.html
    drop: unsafe fn(*const ()),
}

impl RawWakerVTable {
    /// Creates a new `RawWakerVTable` from the provided `clone`, `wake`,
    /// `wake_by_ref`, and `drop` functions.
    ///
    /// # `clone`
    ///
    /// This function will be called when the [`RawWaker`] gets cloned, e.g. when
    /// the [`Waker`] in which the [`RawWaker`] is stored gets cloned.
    ///
    /// The implementation of this function must retain all resources that are
    /// required for this additional instance of a [`RawWaker`] and associated
    /// task. Calling `wake` on the resulting [`RawWaker`] should result in a wakeup
    /// of the same task that would have been awoken by the original [`RawWaker`].
    ///
    /// # `wake`
    ///
    /// This function will be called when `wake` is called on the [`Waker`].
    /// It must wake up the task associated with this [`RawWaker`].
    ///
    /// The implementation of this function must make sure to release any
    /// resources that are associated with this instance of a [`RawWaker`] and
    /// associated task.
    ///
    /// # `wake_by_ref`
    ///
    /// This function will be called when `wake_by_ref` is called on the [`Waker`].
    /// It must wake up the task associated with this [`RawWaker`].
    ///
    /// This function is similar to `wake`, but must not consume the provided data
    /// pointer.
    ///
    /// # `drop`
    ///
    /// This function gets called when a [`RawWaker`] gets dropped.
    ///
    /// The implementation of this function must make sure to release any
    /// resources that are associated with this instance of a [`RawWaker`] and
    /// associated task.
    ///
    /// [`Waker`]: struct.Waker.html
    /// [`RawWaker`]: struct.RawWaker.html
    #[rustc_promotable]
    #[stable(feature = "futures_api", since = "1.36.0")]
    // `rustc_allow_const_fn_ptr` is a hack that should not be used anywhere else
    // without first consulting with T-Lang.
    //
    // FIXME: remove whenever we have a stable way to accept fn pointers from const fn
    // (see https://github.com/rust-rfcs/const-eval/issues/19#issuecomment-472799062)
    #[rustc_allow_const_fn_ptr]
    pub const fn new(
        clone: unsafe fn(*const ()) -> RawWaker,
        wake: unsafe fn(*const ()),
        wake_by_ref: unsafe fn(*const ()),
        drop: unsafe fn(*const ()),
    ) -> Self {
        Self {
            clone,
            wake,
            wake_by_ref,
            drop,
        }
    }
}

/// The `Context` of an asynchronous task.
///
/// Currently, `Context` only serves to provide access to a `&Waker`
/// which can be used to wake the current task.
#[stable(feature = "futures_api", since = "1.36.0")]
pub struct Context<'a> {
    waker: &'a Waker,
    // Ensure we future-proof against variance changes by forcing
    // the lifetime to be invariant (argument-position lifetimes
    // are contravariant while return-position lifetimes are
    // covariant).
    _marker: PhantomData<fn(&'a ()) -> &'a ()>,
}

impl<'a> Context<'a> {
    /// Create a new `Context` from a `&Waker`.
    #[stable(feature = "futures_api", since = "1.36.0")]
    #[inline]
    pub fn from_waker(waker: &'a Waker) -> Self {
        Context {
            waker,
            _marker: PhantomData,
        }
    }

    /// Returns a reference to the `Waker` for the current task.
    #[stable(feature = "futures_api", since = "1.36.0")]
    #[inline]
    pub fn waker(&self) -> &'a Waker {
        &self.waker
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl fmt::Debug for Context<'_> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Context")
            .field("waker", &self.waker)
            .finish()
    }
}

/// A `Waker` is a handle for waking up a task by notifying its executor that it
/// is ready to be run.
///
/// This handle encapsulates a [`RawWaker`] instance, which defines the
/// executor-specific wakeup behavior.
///
/// Implements [`Clone`], [`Send`], and [`Sync`].
///
/// [`RawWaker`]: struct.RawWaker.html
#[repr(transparent)]
#[stable(feature = "futures_api", since = "1.36.0")]
pub struct Waker {
    waker: RawWaker,
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl Unpin for Waker {}
#[stable(feature = "futures_api", since = "1.36.0")]
unsafe impl Send for Waker {}
#[stable(feature = "futures_api", since = "1.36.0")]
unsafe impl Sync for Waker {}

impl Waker {
    /// Wake up the task associated with this `Waker`.
    #[inline]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn wake(self) {
        // The actual wakeup call is delegated through a virtual function call
        // to the implementation which is defined by the executor.
        let wake = self.waker.vtable.wake;
        let data = self.waker.data;

        // Don't call `drop` -- the waker will be consumed by `wake`.
        crate::mem::forget(self);

        // SAFETY: This is safe because `Waker::from_raw` is the only way
        // to initialize `wake` and `data` requiring the user to acknowledge
        // that the contract of `RawWaker` is upheld.
        unsafe { (wake)(data) };
    }

    /// Wake up the task associated with this `Waker` without consuming the `Waker`.
    ///
    /// This is similar to `wake`, but may be slightly less efficient in the case
    /// where an owned `Waker` is available. This method should be preferred to
    /// calling `waker.clone().wake()`.
    #[inline]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn wake_by_ref(&self) {
        // The actual wakeup call is delegated through a virtual function call
        // to the implementation which is defined by the executor.

        // SAFETY: see `wake`
        unsafe { (self.waker.vtable.wake_by_ref)(self.waker.data) }
    }

    /// Returns `true` if this `Waker` and another `Waker` have awoken the same task.
    ///
    /// This function works on a best-effort basis, and may return false even
    /// when the `Waker`s would awaken the same task. However, if this function
    /// returns `true`, it is guaranteed that the `Waker`s will awaken the same task.
    ///
    /// This function is primarily used for optimization purposes.
    #[inline]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn will_wake(&self, other: &Waker) -> bool {
        self.waker == other.waker
    }

    /// Creates a new `Waker` from [`RawWaker`].
    ///
    /// The behavior of the returned `Waker` is undefined if the contract defined
    /// in [`RawWaker`]'s and [`RawWakerVTable`]'s documentation is not upheld.
    /// Therefore this method is unsafe.
    ///
    /// [`RawWaker`]: struct.RawWaker.html
    /// [`RawWakerVTable`]: struct.RawWakerVTable.html
    #[inline]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub unsafe fn from_raw(waker: RawWaker) -> Waker {
        Waker {
            waker,
        }
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl Clone for Waker {
    #[inline]
    fn clone(&self) -> Self {
        Waker {
            // SAFETY: This is safe because `Waker::from_raw` is the only way
            // to initialize `clone` and `data` requiring the user to acknowledge
            // that the contract of [`RawWaker`] is upheld.
            waker: unsafe { (self.waker.vtable.clone)(self.waker.data) },
        }
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl Drop for Waker {
    #[inline]
    fn drop(&mut self) {
        // SAFETY: This is safe because `Waker::from_raw` is the only way
        // to initialize `drop` and `data` requiring the user to acknowledge
        // that the contract of `RawWaker` is upheld.
        unsafe { (self.waker.vtable.drop)(self.waker.data) }
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl fmt::Debug for Waker {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let vtable_ptr = self.waker.vtable as *const RawWakerVTable;
        f.debug_struct("Waker")
            .field("data", &self.waker.data)
            .field("vtable", &vtable_ptr)
            .finish()
    }
}
<commit_msg>Rollup merge of #62689 - 0e4ef622:patch-1, r=Xanewok<commit_after>#![stable(feature = "futures_api", since = "1.36.0")]

use crate::fmt;
use crate::marker::{PhantomData, Unpin};

/// A `RawWaker` allows the implementor of a task executor to create a [`Waker`]
/// which provides customized wakeup behavior.
///
/// [vtable]: https://en.wikipedia.org/wiki/Virtual_method_table
///
/// It consists of a data pointer and a [virtual function pointer table (vtable)][vtable] that
/// customizes the behavior of the `RawWaker`.
///
/// [`Waker`]: struct.Waker.html
#[derive(PartialEq, Debug)]
#[stable(feature = "futures_api", since = "1.36.0")]
pub struct RawWaker {
    /// A data pointer, which can be used to store arbitrary data as required
    /// by the executor. This could be e.g. a type-erased pointer to an `Arc`
    /// that is associated with the task.
    /// The value of this field gets passed to all functions that are part of
    /// the vtable as the first parameter.
    data: *const (),
    /// Virtual function pointer table that customizes the behavior of this waker.
    vtable: &'static RawWakerVTable,
}

impl RawWaker {
    /// Creates a new `RawWaker` from the provided `data` pointer and `vtable`.
    ///
    /// The `data` pointer can be used to store arbitrary data as required
    /// by the executor. This could be e.g. a type-erased pointer to an `Arc`
    /// that is associated with the task.
    /// The value of this pointer will get passed to all functions that are part
    /// of the `vtable` as the first parameter.
    ///
    /// The `vtable` customizes the behavior of a `Waker` which gets created
    /// from a `RawWaker`. For each operation on the `Waker`, the associated
    /// function in the `vtable` of the underlying `RawWaker` will be called.
    #[rustc_promotable]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub const fn new(data: *const (), vtable: &'static RawWakerVTable) -> RawWaker {
        RawWaker {
            data,
            vtable,
        }
    }
}

/// A virtual function pointer table (vtable) that specifies the behavior
/// of a [`RawWaker`].
///
/// The pointer passed to all functions inside the vtable is the `data` pointer
/// from the enclosing [`RawWaker`] object.
///
/// The functions inside this struct are only intended be called on the `data`
/// pointer of a properly constructed [`RawWaker`] object from inside the
/// [`RawWaker`] implementation. Calling one of the contained functions using
/// any other `data` pointer will cause undefined behavior.
///
/// [`RawWaker`]: struct.RawWaker.html
#[stable(feature = "futures_api", since = "1.36.0")]
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct RawWakerVTable {
    /// This function will be called when the [`RawWaker`] gets cloned, e.g. when
    /// the [`Waker`] in which the [`RawWaker`] is stored gets cloned.
    ///
    /// The implementation of this function must retain all resources that are
    /// required for this additional instance of a [`RawWaker`] and associated
    /// task. Calling `wake` on the resulting [`RawWaker`] should result in a wakeup
    /// of the same task that would have been awoken by the original [`RawWaker`].
    ///
    /// [`Waker`]: struct.Waker.html
    /// [`RawWaker`]: struct.RawWaker.html
    clone: unsafe fn(*const ()) -> RawWaker,

    /// This function will be called when `wake` is called on the [`Waker`].
    /// It must wake up the task associated with this [`RawWaker`].
    ///
    /// The implementation of this function must make sure to release any
    /// resources that are associated with this instance of a [`RawWaker`] and
    /// associated task.
    ///
    /// [`Waker`]: struct.Waker.html
    /// [`RawWaker`]: struct.RawWaker.html
    wake: unsafe fn(*const ()),

    /// This function will be called when `wake_by_ref` is called on the [`Waker`].
    /// It must wake up the task associated with this [`RawWaker`].
    ///
    /// This function is similar to `wake`, but must not consume the provided data
    /// pointer.
    ///
    /// [`Waker`]: struct.Waker.html
    /// [`RawWaker`]: struct.RawWaker.html
    wake_by_ref: unsafe fn(*const ()),

    /// This function gets called when a [`RawWaker`] gets dropped.
    ///
    /// The implementation of this function must make sure to release any
    /// resources that are associated with this instance of a [`RawWaker`] and
    /// associated task.
    ///
    /// [`RawWaker`]: struct.RawWaker.html
    drop: unsafe fn(*const ()),
}

impl RawWakerVTable {
    /// Creates a new `RawWakerVTable` from the provided `clone`, `wake`,
    /// `wake_by_ref`, and `drop` functions.
    ///
    /// # `clone`
    ///
    /// This function will be called when the [`RawWaker`] gets cloned, e.g. when
    /// the [`Waker`] in which the [`RawWaker`] is stored gets cloned.
    ///
    /// The implementation of this function must retain all resources that are
    /// required for this additional instance of a [`RawWaker`] and associated
    /// task. Calling `wake` on the resulting [`RawWaker`] should result in a wakeup
    /// of the same task that would have been awoken by the original [`RawWaker`].
    ///
    /// # `wake`
    ///
    /// This function will be called when `wake` is called on the [`Waker`].
    /// It must wake up the task associated with this [`RawWaker`].
    ///
    /// The implementation of this function must make sure to release any
    /// resources that are associated with this instance of a [`RawWaker`] and
    /// associated task.
    ///
    /// # `wake_by_ref`
    ///
    /// This function will be called when `wake_by_ref` is called on the [`Waker`].
    /// It must wake up the task associated with this [`RawWaker`].
    ///
    /// This function is similar to `wake`, but must not consume the provided data
    /// pointer.
    ///
    /// # `drop`
    ///
    /// This function gets called when a [`RawWaker`] gets dropped.
    ///
    /// The implementation of this function must make sure to release any
    /// resources that are associated with this instance of a [`RawWaker`] and
    /// associated task.
    ///
    /// [`Waker`]: struct.Waker.html
    /// [`RawWaker`]: struct.RawWaker.html
    #[rustc_promotable]
    #[stable(feature = "futures_api", since = "1.36.0")]
    // `rustc_allow_const_fn_ptr` is a hack that should not be used anywhere else
    // without first consulting with T-Lang.
    //
    // FIXME: remove whenever we have a stable way to accept fn pointers from const fn
    // (see https://github.com/rust-rfcs/const-eval/issues/19#issuecomment-472799062)
    #[rustc_allow_const_fn_ptr]
    pub const fn new(
        clone: unsafe fn(*const ()) -> RawWaker,
        wake: unsafe fn(*const ()),
        wake_by_ref: unsafe fn(*const ()),
        drop: unsafe fn(*const ()),
    ) -> Self {
        Self {
            clone,
            wake,
            wake_by_ref,
            drop,
        }
    }
}

/// The `Context` of an asynchronous task.
///
/// Currently, `Context` only serves to provide access to a `&Waker`
/// which can be used to wake the current task.
#[stable(feature = "futures_api", since = "1.36.0")]
pub struct Context<'a> {
    waker: &'a Waker,
    // Ensure we future-proof against variance changes by forcing
    // the lifetime to be invariant (argument-position lifetimes
    // are contravariant while return-position lifetimes are
    // covariant).
    _marker: PhantomData<fn(&'a ()) -> &'a ()>,
}

impl<'a> Context<'a> {
    /// Create a new `Context` from a `&Waker`.
    #[stable(feature = "futures_api", since = "1.36.0")]
    #[inline]
    pub fn from_waker(waker: &'a Waker) -> Self {
        Context {
            waker,
            _marker: PhantomData,
        }
    }

    /// Returns a reference to the `Waker` for the current task.
    #[stable(feature = "futures_api", since = "1.36.0")]
    #[inline]
    pub fn waker(&self) -> &'a Waker {
        &self.waker
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl fmt::Debug for Context<'_> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Context")
            .field("waker", &self.waker)
            .finish()
    }
}

/// A `Waker` is a handle for waking up a task by notifying its executor that it
/// is ready to be run.
///
/// This handle encapsulates a [`RawWaker`] instance, which defines the
/// executor-specific wakeup behavior.
///
/// Implements [`Clone`], [`Send`], and [`Sync`].
///
/// [`RawWaker`]: struct.RawWaker.html
#[repr(transparent)]
#[stable(feature = "futures_api", since = "1.36.0")]
pub struct Waker {
    waker: RawWaker,
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl Unpin for Waker {}
#[stable(feature = "futures_api", since = "1.36.0")]
unsafe impl Send for Waker {}
#[stable(feature = "futures_api", since = "1.36.0")]
unsafe impl Sync for Waker {}

impl Waker {
    /// Wake up the task associated with this `Waker`.
    #[inline]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn wake(self) {
        // The actual wakeup call is delegated through a virtual function call
        // to the implementation which is defined by the executor.
        let wake = self.waker.vtable.wake;
        let data = self.waker.data;

        // Don't call `drop` -- the waker will be consumed by `wake`.
        crate::mem::forget(self);

        // SAFETY: This is safe because `Waker::from_raw` is the only way
        // to initialize `wake` and `data` requiring the user to acknowledge
        // that the contract of `RawWaker` is upheld.
        unsafe { (wake)(data) };
    }

    /// Wake up the task associated with this `Waker` without consuming the `Waker`.
    ///
    /// This is similar to `wake`, but may be slightly less efficient in the case
    /// where an owned `Waker` is available. This method should be preferred to
    /// calling `waker.clone().wake()`.
    #[inline]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn wake_by_ref(&self) {
        // The actual wakeup call is delegated through a virtual function call
        // to the implementation which is defined by the executor.

        // SAFETY: see `wake`
        unsafe { (self.waker.vtable.wake_by_ref)(self.waker.data) }
    }

    /// Returns `true` if this `Waker` and another `Waker` have awoken the same task.
    ///
    /// This function works on a best-effort basis, and may return false even
    /// when the `Waker`s would awaken the same task. However, if this function
    /// returns `true`, it is guaranteed that the `Waker`s will awaken the same task.
    ///
    /// This function is primarily used for optimization purposes.
    #[inline]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn will_wake(&self, other: &Waker) -> bool {
        self.waker == other.waker
    }

    /// Creates a new `Waker` from [`RawWaker`].
    ///
    /// The behavior of the returned `Waker` is undefined if the contract defined
    /// in [`RawWaker`]'s and [`RawWakerVTable`]'s documentation is not upheld.
    /// Therefore this method is unsafe.
    ///
    /// [`RawWaker`]: struct.RawWaker.html
    /// [`RawWakerVTable`]: struct.RawWakerVTable.html
    #[inline]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub unsafe fn from_raw(waker: RawWaker) -> Waker {
        Waker {
            waker,
        }
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl Clone for Waker {
    #[inline]
    fn clone(&self) -> Self {
        Waker {
            // SAFETY: This is safe because `Waker::from_raw` is the only way
            // to initialize `clone` and `data` requiring the user to acknowledge
            // that the contract of [`RawWaker`] is upheld.
            waker: unsafe { (self.waker.vtable.clone)(self.waker.data) },
        }
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl Drop for Waker {
    #[inline]
    fn drop(&mut self) {
        // SAFETY: This is safe because `Waker::from_raw` is the only way
        // to initialize `drop` and `data` requiring the user to acknowledge
        // that the contract of `RawWaker` is upheld.
        unsafe { (self.waker.vtable.drop)(self.waker.data) }
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl fmt::Debug for Waker {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let vtable_ptr = self.waker.vtable as *const RawWakerVTable;
        f.debug_struct("Waker")
            .field("data", &self.waker.data)
            .field("vtable", &vtable_ptr)
            .finish()
    }
}
<|endoftext|>


<commit_before>use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_middle::ty::{self, TyCtxt};
use rustc_trait_selection::traits::{self, SkipLeakCheck};
use smallvec::SmallVec;

pub fn crate_inherent_impls_overlap_check(tcx: TyCtxt<'_>, crate_num: CrateNum) {
    assert_eq!(crate_num, LOCAL_CRATE);
    let krate = tcx.hir().krate();
    krate.visit_all_item_likes(&mut InherentOverlapChecker { tcx });
}

struct InherentOverlapChecker<'tcx> {
    tcx: TyCtxt<'tcx>,
}

impl InherentOverlapChecker<'tcx> {
    /// Checks whether any associated items in impls 1 and 2 share the same identifier and
    /// namespace.
    fn impls_have_common_items(
        &self,
        impl_items1: &ty::AssociatedItems<'_>,
        impl_items2: &ty::AssociatedItems<'_>,
    ) -> bool {
        let mut impl_items1 = &impl_items1;
        let mut impl_items2 = &impl_items2;

        // Performance optimization: iterate over the smaller list
        if impl_items1.len() > impl_items2.len() {
            std::mem::swap(&mut impl_items1, &mut impl_items2);
        }

        for item1 in impl_items1.in_definition_order() {
            let collision = impl_items2.filter_by_name_unhygienic(item1.ident.name).any(|item2| {
                // Symbols and namespace match, compare hygienically.
                item1.kind.namespace() == item2.kind.namespace()
                    && item1.ident.normalize_to_macros_2_0()
                        == item2.ident.normalize_to_macros_2_0()
            });

            if collision {
                return true;
            }
        }

        false
    }

    fn check_for_common_items_in_impls(
        &self,
        impl1: DefId,
        impl2: DefId,
        overlap: traits::OverlapResult<'_>,
    ) {
        let impl_items1 = self.tcx.associated_items(impl1);
        let impl_items2 = self.tcx.associated_items(impl2);

        for item1 in impl_items1.in_definition_order() {
            let collision = impl_items2.filter_by_name_unhygienic(item1.ident.name).find(|item2| {
                // Symbols and namespace match, compare hygienically.
                item1.kind.namespace() == item2.kind.namespace()
                    && item1.ident.normalize_to_macros_2_0()
                        == item2.ident.normalize_to_macros_2_0()
            });

            if let Some(item2) = collision {
                let name = item1.ident.normalize_to_macros_2_0();
                let mut err = struct_span_err!(
                    self.tcx.sess,
                    self.tcx.span_of_impl(item1.def_id).unwrap(),
                    E0592,
                    "duplicate definitions with name `{}`",
                    name
                );
                err.span_label(
                    self.tcx.span_of_impl(item1.def_id).unwrap(),
                    format!("duplicate definitions for `{}`", name),
                );
                err.span_label(
                    self.tcx.span_of_impl(item2.def_id).unwrap(),
                    format!("other definition for `{}`", name),
                );

                for cause in &overlap.intercrate_ambiguity_causes {
                    cause.add_intercrate_ambiguity_hint(&mut err);
                }

                if overlap.involves_placeholder {
                    traits::add_placeholder_note(&mut err);
                }

                err.emit();
            }
        }
    }

    fn check_for_overlapping_inherent_impls(&self, impl1_def_id: DefId, impl2_def_id: DefId) {
        traits::overlapping_impls(
            self.tcx,
            impl1_def_id,
            impl2_def_id,
            // We go ahead and just skip the leak check for
            // inherent impls without warning.
            SkipLeakCheck::Yes,
            |overlap| {
                self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap);
                false
            },
            || true,
        );
    }
}

impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> {
    fn visit_item(&mut self, item: &'v hir::Item<'v>) {
        match item.kind {
            hir::ItemKind::Enum(..)
            | hir::ItemKind::Struct(..)
            | hir::ItemKind::Trait(..)
            | hir::ItemKind::Union(..) => {
                let ty_def_id = self.tcx.hir().local_def_id(item.hir_id);
                let impls = self.tcx.inherent_impls(ty_def_id);

                // If there is only one inherent impl block,
                // there is nothing to overlap check it with
                if impls.len() <= 1 {
                    return;
                }

                let impls_items = impls
                    .iter()
                    .map(|impl_def_id| (impl_def_id, self.tcx.associated_items(*impl_def_id)))
                    .collect::<SmallVec<[_; 8]>>();

                for (i, &(&impl1_def_id, impl_items1)) in impls_items.iter().enumerate() {
                    for &(&impl2_def_id, impl_items2) in &impls_items[(i + 1)..] {
                        if self.impls_have_common_items(impl_items1, impl_items2) {
                            self.check_for_overlapping_inherent_impls(impl1_def_id, impl2_def_id);
                        }
                    }
                }
            }
            _ => {}
        }
    }

    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'v>) {}

    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'v>) {}

    fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'v>) {}
}
<commit_msg>Move hygienic comparison into own function<commit_after>use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_middle::ty::{self, TyCtxt};
use rustc_trait_selection::traits::{self, SkipLeakCheck};
use smallvec::SmallVec;

pub fn crate_inherent_impls_overlap_check(tcx: TyCtxt<'_>, crate_num: CrateNum) {
    assert_eq!(crate_num, LOCAL_CRATE);
    let krate = tcx.hir().krate();
    krate.visit_all_item_likes(&mut InherentOverlapChecker { tcx });
}

struct InherentOverlapChecker<'tcx> {
    tcx: TyCtxt<'tcx>,
}

impl InherentOverlapChecker<'tcx> {
    /// Checks whether any associated items in impls 1 and 2 share the same identifier and
    /// namespace.
    fn impls_have_common_items(
        &self,
        impl_items1: &ty::AssociatedItems<'_>,
        impl_items2: &ty::AssociatedItems<'_>,
    ) -> bool {
        let mut impl_items1 = &impl_items1;
        let mut impl_items2 = &impl_items2;

        // Performance optimization: iterate over the smaller list
        if impl_items1.len() > impl_items2.len() {
            std::mem::swap(&mut impl_items1, &mut impl_items2);
        }

        for item1 in impl_items1.in_definition_order() {
            let collision = impl_items2
                .filter_by_name_unhygienic(item1.ident.name)
                .any(|item2| self.compare_hygienically(item1, item2));

            if collision {
                return true;
            }
        }

        false
    }

    fn compare_hygienically(&self, item1: &'tcx ty::AssocItem, item2: &'tcx ty::AssocItem) -> bool {
        // Symbols and namespace match, compare hygienically.
        item1.kind.namespace() == item2.kind.namespace()
            && item1.ident.normalize_to_macros_2_0() == item2.ident.normalize_to_macros_2_0()
    }

    fn check_for_common_items_in_impls(
        &self,
        impl1: DefId,
        impl2: DefId,
        overlap: traits::OverlapResult<'_>,
    ) {
        let impl_items1 = self.tcx.associated_items(impl1);
        let impl_items2 = self.tcx.associated_items(impl2);

        for item1 in impl_items1.in_definition_order() {
            let collision = impl_items2
                .filter_by_name_unhygienic(item1.ident.name)
                .find(|item2| self.compare_hygienically(item1, item2));

            if let Some(item2) = collision {
                let name = item1.ident.normalize_to_macros_2_0();
                let mut err = struct_span_err!(
                    self.tcx.sess,
                    self.tcx.span_of_impl(item1.def_id).unwrap(),
                    E0592,
                    "duplicate definitions with name `{}`",
                    name
                );
                err.span_label(
                    self.tcx.span_of_impl(item1.def_id).unwrap(),
                    format!("duplicate definitions for `{}`", name),
                );
                err.span_label(
                    self.tcx.span_of_impl(item2.def_id).unwrap(),
                    format!("other definition for `{}`", name),
                );

                for cause in &overlap.intercrate_ambiguity_causes {
                    cause.add_intercrate_ambiguity_hint(&mut err);
                }

                if overlap.involves_placeholder {
                    traits::add_placeholder_note(&mut err);
                }

                err.emit();
            }
        }
    }

    fn check_for_overlapping_inherent_impls(&self, impl1_def_id: DefId, impl2_def_id: DefId) {
        traits::overlapping_impls(
            self.tcx,
            impl1_def_id,
            impl2_def_id,
            // We go ahead and just skip the leak check for
            // inherent impls without warning.
            SkipLeakCheck::Yes,
            |overlap| {
                self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap);
                false
            },
            || true,
        );
    }
}

impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> {
    fn visit_item(&mut self, item: &'v hir::Item<'v>) {
        match item.kind {
            hir::ItemKind::Enum(..)
            | hir::ItemKind::Struct(..)
            | hir::ItemKind::Trait(..)
            | hir::ItemKind::Union(..) => {
                let ty_def_id = self.tcx.hir().local_def_id(item.hir_id);
                let impls = self.tcx.inherent_impls(ty_def_id);

                // If there is only one inherent impl block,
                // there is nothing to overlap check it with
                if impls.len() <= 1 {
                    return;
                }

                let impls_items = impls
                    .iter()
                    .map(|impl_def_id| (impl_def_id, self.tcx.associated_items(*impl_def_id)))
                    .collect::<SmallVec<[_; 8]>>();

                for (i, &(&impl1_def_id, impl_items1)) in impls_items.iter().enumerate() {
                    for &(&impl2_def_id, impl_items2) in &impls_items[(i + 1)..] {
                        if self.impls_have_common_items(impl_items1, impl_items2) {
                            self.check_for_overlapping_inherent_impls(impl1_def_id, impl2_def_id);
                        }
                    }
                }
            }
            _ => {}
        }
    }

    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'v>) {}

    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'v>) {}

    fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'v>) {}
}
<|endoftext|>


<commit_before>use quickcheck_dep::{quickcheck, Arbitrary, TestResult};
use time::{Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset, Weekday};

macro_rules! test_shrink {
    ($type:ty,
     $fn_name:ident,
     $($method:ident()).+
     $(, min=$min_value:literal)?
    ) => {
        quickcheck! {
            fn $fn_name(v: $type) -> TestResult {
                let method_value = v.$($method()).+;
                if method_value == test_shrink!(@min_or_zero $($min_value)?) {
                    TestResult::discard()
                } else {
                    TestResult::from_bool(v.shrink().any(|shrunk|
                        if method_value > 0 {
                            shrunk.$($method()).+ < v.$($method()).+
                        } else {
                            shrunk.$($method()).+ > v.$($method()).+
                        }
                    ))
                }
            }
        }
    };
    (@min_or_zero) => { 0 };
    (@min_or_zero $min:literal) => { $min };
}

quickcheck! {
    fn date_roundtrip(d: Date) -> bool {
        Date::from_ordinal_date(d.year(), d.ordinal()) == Ok(d)
    }

    fn julian_day_roundtrip(d: Date) -> bool {
        Date::from_julian_day(d.to_julian_day()) == Ok(d)
    }

    fn duration_roundtrip(d: Duration) -> bool {
        Duration::new(d.whole_seconds(), d.subsec_nanoseconds()) == d
    }

    fn time_roundtrip(t: Time) -> bool {
        Time::from_hms_nano(t.hour(), t.minute(), t.second(), t.nanosecond()) == Ok(t)
    }

    fn primitive_date_time_roundtrip(a: PrimitiveDateTime) -> bool {
        PrimitiveDateTime::new(a.date(), a.time()) == a
    }

    fn utc_offset_roundtrip(o: UtcOffset) -> bool {
        let (hours, minutes, seconds) = o.as_hms();
        UtcOffset::from_hms(hours, minutes, seconds) == Ok(o)
    }

    fn offset_date_time_roundtrip(a: OffsetDateTime) -> bool {
        PrimitiveDateTime::new(a.date(), a.time()).assume_offset(a.offset()) == a
    }

    fn unix_timestamp_roundtrip(odt: OffsetDateTime) -> TestResult {
        match odt.date() {
            Date::MIN | Date::MAX => TestResult::discard(),
            _ => TestResult::from_bool({
                // nanoseconds are not stored in the basic Unix timestamp
                let odt = odt - Duration::nanoseconds(odt.nanosecond().into());
                OffsetDateTime::from_unix_timestamp(odt.unix_timestamp()) == Ok(odt)
            })
        }
    }

    fn unix_timestamp_nanos_roundtrip(odt: OffsetDateTime) -> TestResult {
        match odt.date() {
            Date::MIN | Date::MAX => TestResult::discard(),
            _ => TestResult::from_bool(
                OffsetDateTime::from_unix_timestamp_nanos(odt.unix_timestamp_nanos()) == Ok(odt)
            )
        }
    }

    fn weekday_supports_arbitrary(w: Weekday) -> bool {
        (1..=7).contains(&w.number_from_monday())
    }

    fn weekday_can_shrink(w: Weekday) -> bool {
        match w {
            Weekday::Monday => w.shrink().next() == None,
            _ => w.shrink().next() == Some(w.previous())
        }
    }

    fn month_supports_arbitrary(m: Month) -> bool {
        (1..=12).contains(&(m as u8))
    }

    fn month_can_shrink(m: Month) -> bool {
        match m {
            Month::January => m.shrink().next() == None,
            _ => m.shrink().next() == Some(m.previous())
        }
    }
}

test_shrink!(Date, date_can_shrink_year, year());
test_shrink!(Date, date_can_shrink_ordinal, ordinal(), min = 1);

test_shrink!(Duration, duration_can_shrink_seconds, whole_seconds());
test_shrink!(Duration, duration_can_shrink_ns, subsec_nanoseconds());

test_shrink!(Time, time_can_shrink_hour, hour());
test_shrink!(Time, time_can_shrink_minute, minute());
test_shrink!(Time, time_can_shrink_second, second());
test_shrink!(Time, time_can_shrink_nanosecond, nanosecond());

test_shrink!(
    PrimitiveDateTime,
    primitive_date_time_can_shrink_year,
    year()
);
test_shrink!(
    PrimitiveDateTime,
    primitive_date_time_can_shrink_ordinal,
    ordinal(),
    min = 1
);
test_shrink!(
    PrimitiveDateTime,
    primitive_date_time_can_shrink_hour,
    hour()
);
test_shrink!(
    PrimitiveDateTime,
    primitive_date_time_can_shrink_minute,
    minute()
);
test_shrink!(
    PrimitiveDateTime,
    primitive_date_time_can_shrink_second,
    second()
);
test_shrink!(
    PrimitiveDateTime,
    primitive_date_time_can_shrink_nanosecond,
    nanosecond()
);

test_shrink!(UtcOffset, utc_offset_can_shrink, whole_seconds());

test_shrink!(
    OffsetDateTime,
    offset_date_time_can_shrink_offset,
    offset().whole_seconds()
);
test_shrink!(OffsetDateTime, offset_date_time_can_shrink_year, year());
test_shrink!(
    OffsetDateTime,
    offset_date_time_can_shrink_ordinal,
    ordinal(),
    min = 1
);
test_shrink!(OffsetDateTime, offset_date_time_can_shrink_hour, hour());
test_shrink!(OffsetDateTime, offset_date_time_can_shrink_minute, minute());
test_shrink!(OffsetDateTime, offset_date_time_can_shrink_second, second());
test_shrink!(
    OffsetDateTime,
    offset_date_time_can_shrink_nanosecond,
    nanosecond()
);
<commit_msg>Add additional roundtrip tests<commit_after>use quickcheck_dep::{quickcheck, Arbitrary, TestResult};
use time::{Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset, Weekday};

macro_rules! test_shrink {
    ($type:ty,
     $fn_name:ident,
     $($method:ident()).+
     $(, min=$min_value:literal)?
    ) => {
        quickcheck! {
            fn $fn_name(v: $type) -> TestResult {
                let method_value = v.$($method()).+;
                if method_value == test_shrink!(@min_or_zero $($min_value)?) {
                    TestResult::discard()
                } else {
                    TestResult::from_bool(v.shrink().any(|shrunk|
                        if method_value > 0 {
                            shrunk.$($method()).+ < v.$($method()).+
                        } else {
                            shrunk.$($method()).+ > v.$($method()).+
                        }
                    ))
                }
            }
        }
    };
    (@min_or_zero) => { 0 };
    (@min_or_zero $min:literal) => { $min };
}

quickcheck! {
    fn date_yo_roundtrip(d: Date) -> bool {
        Date::from_ordinal_date(d.year(), d.ordinal()) == Ok(d)
    }

    fn date_ymd_roundtrip(d: Date) -> bool {
        Date::from_calendar_date(d.year(), d.month(), d.day()) == Ok(d)
    }

    fn date_ywd_roundtrip(d: Date) -> bool {
        let (year, week, weekday) = d.to_iso_week_date();
        Date::from_iso_week_date(year, week, weekday) == Ok(d)
    }

    fn julian_day_roundtrip(d: Date) -> bool {
        Date::from_julian_day(d.to_julian_day()) == Ok(d)
    }

    fn duration_roundtrip(d: Duration) -> bool {
        Duration::new(d.whole_seconds(), d.subsec_nanoseconds()) == d
    }

    fn time_roundtrip(t: Time) -> bool {
        Time::from_hms_nano(t.hour(), t.minute(), t.second(), t.nanosecond()) == Ok(t)
    }

    fn primitive_date_time_roundtrip(a: PrimitiveDateTime) -> bool {
        PrimitiveDateTime::new(a.date(), a.time()) == a
    }

    fn utc_offset_roundtrip(o: UtcOffset) -> bool {
        let (hours, minutes, seconds) = o.as_hms();
        UtcOffset::from_hms(hours, minutes, seconds) == Ok(o)
    }

    fn offset_date_time_roundtrip(a: OffsetDateTime) -> bool {
        PrimitiveDateTime::new(a.date(), a.time()).assume_offset(a.offset()) == a
    }

    fn unix_timestamp_roundtrip(odt: OffsetDateTime) -> TestResult {
        match odt.date() {
            Date::MIN | Date::MAX => TestResult::discard(),
            _ => TestResult::from_bool({
                // nanoseconds are not stored in the basic Unix timestamp
                let odt = odt - Duration::nanoseconds(odt.nanosecond().into());
                OffsetDateTime::from_unix_timestamp(odt.unix_timestamp()) == Ok(odt)
            })
        }
    }

    fn unix_timestamp_nanos_roundtrip(odt: OffsetDateTime) -> TestResult {
        match odt.date() {
            Date::MIN | Date::MAX => TestResult::discard(),
            _ => TestResult::from_bool(
                OffsetDateTime::from_unix_timestamp_nanos(odt.unix_timestamp_nanos()) == Ok(odt)
            )
        }
    }

    fn weekday_supports_arbitrary(w: Weekday) -> bool {
        (1..=7).contains(&w.number_from_monday())
    }

    fn weekday_can_shrink(w: Weekday) -> bool {
        match w {
            Weekday::Monday => w.shrink().next() == None,
            _ => w.shrink().next() == Some(w.previous())
        }
    }

    fn month_supports_arbitrary(m: Month) -> bool {
        (1..=12).contains(&(m as u8))
    }

    fn month_can_shrink(m: Month) -> bool {
        match m {
            Month::January => m.shrink().next() == None,
            _ => m.shrink().next() == Some(m.previous())
        }
    }
}

test_shrink!(Date, date_can_shrink_year, year());
test_shrink!(Date, date_can_shrink_ordinal, ordinal(), min = 1);

test_shrink!(Duration, duration_can_shrink_seconds, whole_seconds());
test_shrink!(Duration, duration_can_shrink_ns, subsec_nanoseconds());

test_shrink!(Time, time_can_shrink_hour, hour());
test_shrink!(Time, time_can_shrink_minute, minute());
test_shrink!(Time, time_can_shrink_second, second());
test_shrink!(Time, time_can_shrink_nanosecond, nanosecond());

test_shrink!(
    PrimitiveDateTime,
    primitive_date_time_can_shrink_year,
    year()
);
test_shrink!(
    PrimitiveDateTime,
    primitive_date_time_can_shrink_ordinal,
    ordinal(),
    min = 1
);
test_shrink!(
    PrimitiveDateTime,
    primitive_date_time_can_shrink_hour,
    hour()
);
test_shrink!(
    PrimitiveDateTime,
    primitive_date_time_can_shrink_minute,
    minute()
);
test_shrink!(
    PrimitiveDateTime,
    primitive_date_time_can_shrink_second,
    second()
);
test_shrink!(
    PrimitiveDateTime,
    primitive_date_time_can_shrink_nanosecond,
    nanosecond()
);

test_shrink!(UtcOffset, utc_offset_can_shrink, whole_seconds());

test_shrink!(
    OffsetDateTime,
    offset_date_time_can_shrink_offset,
    offset().whole_seconds()
);
test_shrink!(OffsetDateTime, offset_date_time_can_shrink_year, year());
test_shrink!(
    OffsetDateTime,
    offset_date_time_can_shrink_ordinal,
    ordinal(),
    min = 1
);
test_shrink!(OffsetDateTime, offset_date_time_can_shrink_hour, hour());
test_shrink!(OffsetDateTime, offset_date_time_can_shrink_minute, minute());
test_shrink!(OffsetDateTime, offset_date_time_can_shrink_second, second());
test_shrink!(
    OffsetDateTime,
    offset_date_time_can_shrink_nanosecond,
    nanosecond()
);
<|endoftext|>


<commit_before>extern crate chill;
extern crate serde_json;

macro_rules! unexpected_result {
    ($result:expr) => {
        match $result {
            Err(e) => panic!("Got unexpected error result {:?}", e),
            Ok(x) => panic!("Got unexpected OK result {:?}", x),
        }
    }
}

fn make_server_and_client() -> (chill::testing::FakeServer, chill::Client) {
    let server = chill::testing::FakeServer::new().unwrap();
    let client = chill::Client::new(server.uri()).unwrap();
    (server, client)
}

#[test]
fn create_database_ok() {
    let (_server, client) = make_server_and_client();
    client.create_database("/baseball").unwrap().run().unwrap();
}

#[test]
fn create_database_nok_database_exists() {
    let (_server, client) = make_server_and_client();
    client.create_database("/baseball").unwrap().run().unwrap();
    match client.create_database("/baseball").unwrap().run() {
        Err(chill::Error::DatabaseExists(..)) => (),
        x @ _ => {
            panic!("Unexpected result: {:?}", x);
        }
    }
}

#[test]
fn create_document_ok_default() {

    let (_server, client) = make_server_and_client();
    client.create_database("/baseball").unwrap().run().unwrap();

    let up_content = serde_json::builder::ObjectBuilder::new()
                         .insert("name", "Babe Ruth")
                         .insert("nickname", "The Bambino")
                         .unwrap();

    let (doc_id, _rev) = client.create_document("/baseball", &up_content).unwrap().run().unwrap();

    let doc = client.read_document(("/baseball", &doc_id))
                    .unwrap()
                    .run()
                    .unwrap();
    let down_content = doc.get_content().unwrap();
    assert_eq!(up_content, down_content);
}

#[test]
fn create_document_ok_with_document_id() {

    let (_server, client) = make_server_and_client();
    client.create_database("/baseball").unwrap().run().unwrap();

    let up_content = serde_json::builder::ObjectBuilder::new()
                         .insert("name", "Babe Ruth")
                         .insert("nickname", "The Bambino")
                         .unwrap();

    let (doc_id, _rev) = client.create_document("/baseball", &up_content)
                               .unwrap()
                               .with_document_id("babe_ruth")
                               .run()
                               .unwrap();
    assert_eq!(chill::DocumentId::from("babe_ruth"), doc_id);

    let doc = client.read_document(("/baseball", &doc_id))
                    .unwrap()
                    .run()
                    .unwrap();
    let down_content = doc.get_content().unwrap();
    assert_eq!(up_content, down_content);
}

#[test]
fn create_document_nok_document_conflict() {

    let (_server, client) = make_server_and_client();
    client.create_database("/baseball").unwrap().run().unwrap();

    let up_content = serde_json::builder::ObjectBuilder::new()
                         .insert("name", "Babe Ruth")
                         .insert("nickname", "The Bambino")
                         .unwrap();

    let (doc_id, _rev) = client.create_document("/baseball", &up_content).unwrap().run().unwrap();

    match client.create_document("/baseball", &up_content)
                .unwrap()
                .with_document_id(&doc_id)
                .run() {
        Err(chill::Error::DocumentConflict(..)) => (),
        x @ _ => unexpected_result!(x),
    }
}

#[test]
fn read_document_ok_default() {

    let (_server, client) = make_server_and_client();
    client.create_database("/baseball").unwrap().run().unwrap();

    let up_content = serde_json::builder::ObjectBuilder::new()
                         .insert("name", "Babe Ruth")
                         .insert("nickname", "The Bambino")
                         .unwrap();

    let (doc_id, _rev) = client.create_document("/baseball", &up_content).unwrap().run().unwrap();

    let doc = client.read_document(("/baseball", &doc_id))
                    .unwrap()
                    .run()
                    .unwrap();
    let down_content = doc.get_content().unwrap();
    assert_eq!(up_content, down_content);
}

#[test]
fn read_document_ok_with_revision() {

    let (_server, client) = make_server_and_client();
    client.create_database("/baseball").unwrap().run().unwrap();

    let up_content = serde_json::builder::ObjectBuilder::new()
                         .insert("name", "Babe Ruth")
                         .insert("nickname", "The Bambino")
                         .unwrap();

    let (doc_id, rev) = client.create_document("/baseball", &up_content).unwrap().run().unwrap();

    let doc = client.read_document(("/baseball", &doc_id))
                    .unwrap()
                    .with_revision(&rev)
                    .run()
                    .unwrap();
    let down_content = doc.get_content().unwrap();
    assert_eq!(up_content, down_content);
}

#[test]
fn read_document_nok_not_found() {

    let (_server, client) = make_server_and_client();
    client.create_database("/baseball").unwrap().run().unwrap();

    match client.read_document("/baseball/babe_ruth").unwrap().run() {
        Err(chill::Error::NotFound(..)) => (),
        x @ _ => unexpected_result!(x),
    }
}

#[test]
fn update_document_ok() {

    let (_server, client) = make_server_and_client();
    client.create_database("/baseball").unwrap().run().unwrap();

    let up_content = serde_json::builder::ObjectBuilder::new()
                         .insert("name", "Babe Ruth")
                         .insert("nickname", "The Bambino")
                         .unwrap();

    let (doc_id, _rev) = client.create_document("/baseball", &up_content).unwrap().run().unwrap();

    let mut doc = client.read_document(("/baseball", &doc_id))
                        .unwrap()
                        .run()
                        .unwrap();

    let up_content = match doc.get_content::<serde_json::Value>().unwrap() {
        serde_json::Value::Object(mut fields) => {
            fields.insert("birthday".to_string(),
                          serde_json::Value::String("1895-02-06".to_string()));
            serde_json::Value::Object(fields)
        }
        _ => {
            panic!("Invalid JSON type");
        }
    };

    doc.set_content(&up_content).unwrap();

    let updated_rev = client.update_document(&doc).unwrap().run().unwrap();

    let doc = client.read_document(("/baseball", doc.id()))
                    .unwrap()
                    .run()
                    .unwrap();
    let down_content: serde_json::Value = doc.get_content().unwrap();
    assert_eq!(up_content, down_content);
    assert_eq!(&updated_rev, doc.revision());
}

#[test]
fn delete_document_ok() {

    let (_server, client) = make_server_and_client();
    client.create_database("/baseball").unwrap().run().unwrap();

    let up_content = serde_json::builder::ObjectBuilder::new()
                         .insert("name", "Babe Ruth")
                         .insert("nickname", "The Bambino")
                         .unwrap();

    let (doc_id, rev1) = client.create_document("/baseball", &up_content).unwrap().run().unwrap();

    let _rev2 = client.delete_document(("/baseball", &doc_id), &rev1)
                      .unwrap()
                      .run()
                      .unwrap();

    match client.read_document(("/baseball", &doc_id)).unwrap().run() {
        Err(chill::Error::NotFound(..)) => (),
        x @ _ => {
            panic!("Unexpected result: {:?}", x);
        }
    }

    // FIXME: Check that _rev2 is valid. We need to be able to get a document at
    // a specific revision to check this.
}
<commit_msg>Verify document is deleted in integration test<commit_after>extern crate chill;
extern crate serde_json;

macro_rules! unexpected_result {
    ($result:expr) => {
        match $result {
            Err(e) => panic!("Got unexpected error result {:?}", e),
            Ok(x) => panic!("Got unexpected OK result {:?}", x),
        }
    }
}

fn make_server_and_client() -> (chill::testing::FakeServer, chill::Client) {
    let server = chill::testing::FakeServer::new().unwrap();
    let client = chill::Client::new(server.uri()).unwrap();
    (server, client)
}

#[test]
fn create_database_ok() {
    let (_server, client) = make_server_and_client();
    client.create_database("/baseball").unwrap().run().unwrap();
}

#[test]
fn create_database_nok_database_exists() {
    let (_server, client) = make_server_and_client();
    client.create_database("/baseball").unwrap().run().unwrap();
    match client.create_database("/baseball").unwrap().run() {
        Err(chill::Error::DatabaseExists(..)) => (),
        x @ _ => {
            panic!("Unexpected result: {:?}", x);
        }
    }
}

#[test]
fn create_document_ok_default() {

    let (_server, client) = make_server_and_client();
    client.create_database("/baseball").unwrap().run().unwrap();

    let up_content = serde_json::builder::ObjectBuilder::new()
                         .insert("name", "Babe Ruth")
                         .insert("nickname", "The Bambino")
                         .unwrap();

    let (doc_id, _rev) = client.create_document("/baseball", &up_content).unwrap().run().unwrap();

    let doc = client.read_document(("/baseball", &doc_id))
                    .unwrap()
                    .run()
                    .unwrap();
    let down_content = doc.get_content().unwrap();
    assert_eq!(up_content, down_content);
}

#[test]
fn create_document_ok_with_document_id() {

    let (_server, client) = make_server_and_client();
    client.create_database("/baseball").unwrap().run().unwrap();

    let up_content = serde_json::builder::ObjectBuilder::new()
                         .insert("name", "Babe Ruth")
                         .insert("nickname", "The Bambino")
                         .unwrap();

    let (doc_id, _rev) = client.create_document("/baseball", &up_content)
                               .unwrap()
                               .with_document_id("babe_ruth")
                               .run()
                               .unwrap();
    assert_eq!(chill::DocumentId::from("babe_ruth"), doc_id);

    let doc = client.read_document(("/baseball", &doc_id))
                    .unwrap()
                    .run()
                    .unwrap();
    let down_content = doc.get_content().unwrap();
    assert_eq!(up_content, down_content);
}

#[test]
fn create_document_nok_document_conflict() {

    let (_server, client) = make_server_and_client();
    client.create_database("/baseball").unwrap().run().unwrap();

    let up_content = serde_json::builder::ObjectBuilder::new()
                         .insert("name", "Babe Ruth")
                         .insert("nickname", "The Bambino")
                         .unwrap();

    let (doc_id, _rev) = client.create_document("/baseball", &up_content).unwrap().run().unwrap();

    match client.create_document("/baseball", &up_content)
                .unwrap()
                .with_document_id(&doc_id)
                .run() {
        Err(chill::Error::DocumentConflict(..)) => (),
        x @ _ => unexpected_result!(x),
    }
}

#[test]
fn read_document_ok_default() {

    let (_server, client) = make_server_and_client();
    client.create_database("/baseball").unwrap().run().unwrap();

    let up_content = serde_json::builder::ObjectBuilder::new()
                         .insert("name", "Babe Ruth")
                         .insert("nickname", "The Bambino")
                         .unwrap();

    let (doc_id, _rev) = client.create_document("/baseball", &up_content).unwrap().run().unwrap();

    let doc = client.read_document(("/baseball", &doc_id))
                    .unwrap()
                    .run()
                    .unwrap();
    let down_content = doc.get_content().unwrap();
    assert_eq!(up_content, down_content);
}

#[test]
fn read_document_ok_with_revision() {

    let (_server, client) = make_server_and_client();
    client.create_database("/baseball").unwrap().run().unwrap();

    let up_content = serde_json::builder::ObjectBuilder::new()
                         .insert("name", "Babe Ruth")
                         .insert("nickname", "The Bambino")
                         .unwrap();

    let (doc_id, rev) = client.create_document("/baseball", &up_content).unwrap().run().unwrap();

    let doc = client.read_document(("/baseball", &doc_id))
                    .unwrap()
                    .with_revision(&rev)
                    .run()
                    .unwrap();
    let down_content = doc.get_content().unwrap();
    assert_eq!(up_content, down_content);
}

#[test]
fn read_document_nok_not_found() {

    let (_server, client) = make_server_and_client();
    client.create_database("/baseball").unwrap().run().unwrap();

    match client.read_document("/baseball/babe_ruth").unwrap().run() {
        Err(chill::Error::NotFound(..)) => (),
        x @ _ => unexpected_result!(x),
    }
}

#[test]
fn update_document_ok() {

    let (_server, client) = make_server_and_client();
    client.create_database("/baseball").unwrap().run().unwrap();

    let up_content = serde_json::builder::ObjectBuilder::new()
                         .insert("name", "Babe Ruth")
                         .insert("nickname", "The Bambino")
                         .unwrap();

    let (doc_id, _rev) = client.create_document("/baseball", &up_content).unwrap().run().unwrap();

    let mut doc = client.read_document(("/baseball", &doc_id))
                        .unwrap()
                        .run()
                        .unwrap();

    let up_content = match doc.get_content::<serde_json::Value>().unwrap() {
        serde_json::Value::Object(mut fields) => {
            fields.insert("birthday".to_string(),
                          serde_json::Value::String("1895-02-06".to_string()));
            serde_json::Value::Object(fields)
        }
        _ => {
            panic!("Invalid JSON type");
        }
    };

    doc.set_content(&up_content).unwrap();

    let updated_rev = client.update_document(&doc).unwrap().run().unwrap();

    let doc = client.read_document(("/baseball", doc.id()))
                    .unwrap()
                    .run()
                    .unwrap();
    let down_content: serde_json::Value = doc.get_content().unwrap();
    assert_eq!(up_content, down_content);
    assert_eq!(&updated_rev, doc.revision());
}

#[test]
fn delete_document_ok() {

    let (_server, client) = make_server_and_client();
    client.create_database("/baseball").unwrap().run().unwrap();

    let up_content = serde_json::builder::ObjectBuilder::new()
                         .insert("name", "Babe Ruth")
                         .insert("nickname", "The Bambino")
                         .unwrap();

    let (doc_id, rev1) = client.create_document("/baseball", &up_content).unwrap().run().unwrap();

    let rev2 = client.delete_document(("/baseball", &doc_id), &rev1)
                     .unwrap()
                     .run()
                     .unwrap();

    match client.read_document(("/baseball", &doc_id)).unwrap().run() {
        Err(chill::Error::NotFound(..)) => (),
        x @ _ => {
            panic!("Unexpected result: {:?}", x);
        }
    }

    let doc = client.read_document(("/baseball", &doc_id))
                    .unwrap()
                    .with_revision(&rev2)
                    .run()
                    .unwrap();
    assert!(doc.is_deleted());
}
<|endoftext|>