<commit_before>use super::prelude::*;
use itertools::Itertools;
use similar::{ChangeTag, TextDiff};
use std::any::{type_name, Any};
use std::collections::VecDeque;
use std::iter::FromIterator;
use std::ops::Deref;

/// Implements patching for strings
///
/// `Add`, `Remove` and `Replace` operations are implemented.
/// The `Move` operation, whilst possible for strings, adds complexity
/// and a performance hit to diffing, but is likely to be uncommon at the
/// word level (word level moves are dealt with in `Vec<InlineContent>`).
impl Patchable for String {
    patchable_is_same!();

    fn is_equal(&self, other: &Self) -> Result<()> {
        if self == other {
            Ok(())
        } else {
            bail!(Error::NotEqual)
        }
    }

    patchable_diff!();

    fn diff_same(&self, differ: &mut Differ, other: &Self) {
        if self == other {
            return;
        }

        let diff = TextDiff::from_chars(self, other);
        let mut ops: Vec<Operation> = Vec::new();
        let mut curr: char = 'e';
        let mut replace = false;
        let mut position: usize = 0;
        let mut start: usize = 0;
        let mut items: usize = 0;
        let mut value: String = String::new();

        let changes = diff.iter_all_changes().collect_vec();
        for (index, change) in changes.iter().enumerate() {
            let last = curr;
            match change.tag() {
                ChangeTag::Equal => {
                    position += 1;
                    curr = 'e';
                }
                ChangeTag::Delete => match last {
                    'd' => {
                        items += 1;
                        value.push_str(change.value());
                    }
                    _ => {
                        curr = 'd';
                        start = position;
                        items = 1;
                        value = change.value().into();
                    }
                },
                ChangeTag::Insert => {
                    match last {
                        'i' => {
                            value.push_str(change.value());
                        }
                        _ => {
                            curr = 'i';
                            if last == 'd' {
                                replace = true;
                            } else {
                                replace = false;
                                start = position;
                            }
                            value = change.value().into();
                        }
                    }
                    position += 1;
                }
            }

            let end = index == changes.len() - 1;
            if (index > 0 && curr != last) || end {
                let keys = VecDeque::from_iter(vec![Key::Index(start)]);
                if (curr == 'e' && last == 'd') || (end && curr == 'd') {
                    ops.push(Operation::Remove(Remove { keys, items }));
                } else if (curr == 'e' && last == 'i') || (end && curr == 'i') {
                    if replace {
                        ops.push(Operation::Replace(Replace {
                            keys,
                            items,
                            value: Box::new(value.clone()),
                        }));
                    } else {
                        ops.push(Operation::Add(Add {
                            keys,
                            value: Box::new(value.clone()),
                        }));
                    }
                };
            }
        }

        differ.append(ops)
    }

    fn apply_add(&mut self, keys: &mut Keys, value: &Box<dyn Any>) {
        let value = if let Some(value) = value.deref().downcast_ref::<Self>() {
            value
        } else {
            unreachable!("Invalid replacement value for {}", type_name::<Self>())
        };

        if let Some(Key::Index(index)) = keys.pop_front() {
            let chars: Vec<char> = self.chars().collect();
            let chars = [
                &chars[..index],
                &value.chars().collect_vec(),
                &chars[index..],
            ]
            .concat();
            *self = chars.into_iter().collect();
        } else {
            invalid_keys!(keys)
        }
    }

    fn apply_remove(&mut self, keys: &mut Keys, items: usize) {
        if let Some(Key::Index(index)) = keys.pop_front() {
            let chars: Vec<char> = self.chars().collect();
            let chars = [&chars[..index], &chars[(index + items)..]].concat();
            *self = chars.into_iter().collect();
        } else {
            invalid_keys!(keys)
        }
    }

    fn apply_replace(&mut self, keys: &mut Keys, items: usize, value: &Box<dyn Any>) {
        let value = if let Some(value) = value.deref().downcast_ref::<Self>() {
            value
        } else {
            unreachable!("Invalid replacement value for {}", type_name::<Self>())
        };

        if keys.is_empty() {
            *self = value.clone();
        } else if let Some(Key::Index(index)) = keys.pop_front() {
            let chars: Vec<char> = self.chars().collect();
            let chars = [
                &chars[..index],
                &value.chars().collect_vec(),
                &chars[(index + items)..],
            ]
            .concat();
            *self = chars.into_iter().collect();
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::{
        assert_json,
        patches::{apply_new, diff, equal},
    };
    use pretty_assertions::assert_eq;

    #[test]
    fn basic() {
        let empty = "".to_string();
        let a = "1".to_string();
        let b = "123".to_string();
        let c = "a2b3".to_string();
        let d = "abcdef".to_string();
        let e = "adefbc".to_string();
        let f = "adbcfe".to_string();

        assert!(equal(&empty, &empty));
        assert!(equal(&a, &a));
        assert!(equal(&b, &b));
        assert!(equal(&c, &c));
        assert!(equal(&d, &d));

        // No diff

        assert_json!(diff(&empty, &empty), []);
        assert_json!(diff(&a, &a), []);
        assert_json!(diff(&d, &d), []);

        // Add

        let patch = diff(&empty, &a);
        assert_json!(
            patch,
            [{ "op": "add", "keys": [0], "value": "1" }]
        );
        assert_eq!(apply_new(&empty, &patch), a);

        let patch = diff(&empty, &d);
        assert_json!(
            patch,
            [{ "op": "add", "keys": [0], "value": "abcdef" }]
        );
        assert_eq!(apply_new(&empty, &patch), d);

        let patch = diff(&a, &b);
        assert_json!(
            patch,
            [{ "op": "add", "keys": [1], "value": "23" }]
        );
        assert_eq!(apply_new(&a, &patch), b);

        // Remove

        let patch = diff(&a, &empty);
        assert_json!(
            patch,
            [{ "op": "remove", "keys": [0], "items": 1 }]
        );

        let patch = diff(&d, &empty);
        assert_json!(
            patch,
            [{ "op": "remove", "keys": [0], "items": 6 }]
        );

        let patch = diff(&b, &a);
        assert_json!(
            patch,
            [{ "op": "remove", "keys": [1], "items": 2 }]
        );

        // Replace

        let patch = diff(&a, &c);
        assert_json!(
            patch,
            [{ "op": "replace", "keys": [0], "items": 1, "value": "a2b3" }]
        );
        assert_eq!(apply_new(&a, &patch), c);

        let patch = diff(&b, &d);
        assert_json!(
            patch,
            [{ "op": "replace", "keys": [0], "items": 3, "value": "abcdef" }]
        );
        assert_eq!(apply_new(&b, &patch), d);

        // Mixed

        let patch = diff(&c, &d);
        assert_json!(
            patch,
            [
                { "op": "remove", "keys": [1], "items": 1 },
                { "op": "replace", "keys": [2], "items": 1, "value": "cdef" }
            ]
        );
        assert_eq!(apply_new(&c, &patch), d);

        let patch = diff(&d, &c);
        assert_json!(
            patch,
            [
                { "op": "add", "keys": [1], "value": "2" },
                { "op": "replace", "keys": [3], "items": 4, "value": "3" }
            ]
        );
        assert_eq!(apply_new(&d, &patch), c);

        let patch = diff(&d, &f);
        assert_json!(
            patch,
            [
                { "op": "add", "keys": [1], "value": "d" },
                { "op": "replace", "keys": [4], "items": 1, "value": "f" },
                { "op": "remove", "keys": [6], "items": 1 }
            ]
        );
        assert_eq!(apply_new(&d, &patch), f);
    }

    /// Test that works with Unicode graphemes (which are made
    /// up of multiple `char`s).
    #[test]
    fn unicode() {
        let a = "ä".to_string();
        let b = "ä1👍🏻2".to_string();
        let c = "1👍🏿2".to_string();

        let patch = diff(&a, &b);
        assert_json!(patch, [
            { "op": "add", "keys": [1], "value": "1👍🏻2" },
        ]);
        assert_eq!(apply_new(&a, &patch), b);

        let patch = diff(&b, &c);
        assert_json!(patch, [
            { "op": "remove", "keys": [0], "items": 1 },
            { "op": "replace", "keys": [2], "items": 1, "value": "🏿" },
        ]);
        assert_eq!(apply_new(&b, &patch), c);

        let patch = diff(&c, &b);
        assert_json!(patch, [
            { "op": "add", "keys": [0], "value": "ä" },
            { "op": "replace", "keys": [3], "items": 1, "value": "🏻" },
        ]);
        assert_eq!(apply_new(&c, &patch), b);
    }

    // Regression tests of minimal failing cases found using property testing
    // and elsewhere.

    #[test]
    fn regression_1() {
        let a = "ab".to_string();
        let b = "bc".to_string();
        let patch = diff(&a, &b);
        assert_json!(patch, [
            { "op": "remove", "keys": [0], "items": 1 },
            { "op": "add", "keys": [1], "value": "c" },
        ]);
        assert_eq!(apply_new(&a, &patch), b);
    }

    #[test]
    fn regression_2() {
        let a = "ac".to_string();
        let b = "bcd".to_string();
        let patch = diff(&a, &b);
        assert_json!(
            patch,
            [
                { "op": "replace", "keys": [0], "items": 1, "value": "b" },
                { "op": "add", "keys": [2], "value": "d" },
            ]
        );
        assert_eq!(apply_new(&a, &patch), b);
    }
}
<commit_msg>refactor(String patches): Use error macros<commit_after>use super::prelude::*;
use itertools::Itertools;
use similar::{ChangeTag, TextDiff};
use std::any::{type_name, Any};
use std::collections::VecDeque;
use std::iter::FromIterator;
use std::ops::Deref;

/// Implements patching for strings
///
/// `Add`, `Remove` and `Replace` operations are implemented.
/// The `Move` operation, whilst possible for strings, adds complexity
/// and a performance hit to diffing, but is likely to be uncommon at the
/// word level (word level moves are dealt with in `Vec<InlineContent>`).
impl Patchable for String {
    patchable_is_same!();

    fn is_equal(&self, other: &Self) -> Result<()> {
        if self == other {
            Ok(())
        } else {
            bail!(Error::NotEqual)
        }
    }

    patchable_diff!();

    fn diff_same(&self, differ: &mut Differ, other: &Self) {
        if self == other {
            return;
        }

        let diff = TextDiff::from_chars(self, other);
        let mut ops: Vec<Operation> = Vec::new();
        let mut curr: char = 'e';
        let mut replace = false;
        let mut position: usize = 0;
        let mut start: usize = 0;
        let mut items: usize = 0;
        let mut value: String = String::new();

        let changes = diff.iter_all_changes().collect_vec();
        for (index, change) in changes.iter().enumerate() {
            let last = curr;
            match change.tag() {
                ChangeTag::Equal => {
                    position += 1;
                    curr = 'e';
                }
                ChangeTag::Delete => match last {
                    'd' => {
                        items += 1;
                        value.push_str(change.value());
                    }
                    _ => {
                        curr = 'd';
                        start = position;
                        items = 1;
                        value = change.value().into();
                    }
                },
                ChangeTag::Insert => {
                    match last {
                        'i' => {
                            value.push_str(change.value());
                        }
                        _ => {
                            curr = 'i';
                            if last == 'd' {
                                replace = true;
                            } else {
                                replace = false;
                                start = position;
                            }
                            value = change.value().into();
                        }
                    }
                    position += 1;
                }
            }

            let end = index == changes.len() - 1;
            if (index > 0 && curr != last) || end {
                let keys = VecDeque::from_iter(vec![Key::Index(start)]);
                if (curr == 'e' && last == 'd') || (end && curr == 'd') {
                    ops.push(Operation::Remove(Remove { keys, items }));
                } else if (curr == 'e' && last == 'i') || (end && curr == 'i') {
                    if replace {
                        ops.push(Operation::Replace(Replace {
                            keys,
                            items,
                            value: Box::new(value.clone()),
                        }));
                    } else {
                        ops.push(Operation::Add(Add {
                            keys,
                            value: Box::new(value.clone()),
                        }));
                    }
                };
            }
        }

        differ.append(ops)
    }

    fn apply_add(&mut self, keys: &mut Keys, value: &Box<dyn Any>) {
        let value = if let Some(value) = value.deref().downcast_ref::<Self>() {
            value
        } else {
            return invalid_value!()
        };

        if let Some(Key::Index(index)) = keys.pop_front() {
            let chars: Vec<char> = self.chars().collect();
            let chars = [
                &chars[..index],
                &value.chars().collect_vec(),
                &chars[index..],
            ]
            .concat();
            *self = chars.into_iter().collect();
        } else {
            invalid_keys!(keys)
        }
    }

    fn apply_remove(&mut self, keys: &mut Keys, items: usize) {
        if let Some(Key::Index(index)) = keys.pop_front() {
            let chars: Vec<char> = self.chars().collect();
            let chars = [&chars[..index], &chars[(index + items)..]].concat();
            *self = chars.into_iter().collect();
        } else {
            invalid_keys!(keys)
        }
    }

    fn apply_replace(&mut self, keys: &mut Keys, items: usize, value: &Box<dyn Any>) {
        let value = if let Some(value) = value.deref().downcast_ref::<Self>() {
            value
        } else {
            return invalid_value!()
        };

        if keys.is_empty() {
            *self = value.clone();
        } else if let Some(Key::Index(index)) = keys.pop_front() {
            let chars: Vec<char> = self.chars().collect();
            let chars = [
                &chars[..index],
                &value.chars().collect_vec(),
                &chars[(index + items)..],
            ]
            .concat();
            *self = chars.into_iter().collect();
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::{
        assert_json,
        patches::{apply_new, diff, equal},
    };
    use pretty_assertions::assert_eq;

    #[test]
    fn basic() {
        let empty = "".to_string();
        let a = "1".to_string();
        let b = "123".to_string();
        let c = "a2b3".to_string();
        let d = "abcdef".to_string();
        let e = "adefbc".to_string();
        let f = "adbcfe".to_string();

        assert!(equal(&empty, &empty));
        assert!(equal(&a, &a));
        assert!(equal(&b, &b));
        assert!(equal(&c, &c));
        assert!(equal(&d, &d));

        // No diff

        assert_json!(diff(&empty, &empty), []);
        assert_json!(diff(&a, &a), []);
        assert_json!(diff(&d, &d), []);

        // Add

        let patch = diff(&empty, &a);
        assert_json!(
            patch,
            [{ "op": "add", "keys": [0], "value": "1" }]
        );
        assert_eq!(apply_new(&empty, &patch), a);

        let patch = diff(&empty, &d);
        assert_json!(
            patch,
            [{ "op": "add", "keys": [0], "value": "abcdef" }]
        );
        assert_eq!(apply_new(&empty, &patch), d);

        let patch = diff(&a, &b);
        assert_json!(
            patch,
            [{ "op": "add", "keys": [1], "value": "23" }]
        );
        assert_eq!(apply_new(&a, &patch), b);

        // Remove

        let patch = diff(&a, &empty);
        assert_json!(
            patch,
            [{ "op": "remove", "keys": [0], "items": 1 }]
        );

        let patch = diff(&d, &empty);
        assert_json!(
            patch,
            [{ "op": "remove", "keys": [0], "items": 6 }]
        );

        let patch = diff(&b, &a);
        assert_json!(
            patch,
            [{ "op": "remove", "keys": [1], "items": 2 }]
        );

        // Replace

        let patch = diff(&a, &c);
        assert_json!(
            patch,
            [{ "op": "replace", "keys": [0], "items": 1, "value": "a2b3" }]
        );
        assert_eq!(apply_new(&a, &patch), c);

        let patch = diff(&b, &d);
        assert_json!(
            patch,
            [{ "op": "replace", "keys": [0], "items": 3, "value": "abcdef" }]
        );
        assert_eq!(apply_new(&b, &patch), d);

        // Mixed

        let patch = diff(&c, &d);
        assert_json!(
            patch,
            [
                { "op": "remove", "keys": [1], "items": 1 },
                { "op": "replace", "keys": [2], "items": 1, "value": "cdef" }
            ]
        );
        assert_eq!(apply_new(&c, &patch), d);

        let patch = diff(&d, &c);
        assert_json!(
            patch,
            [
                { "op": "add", "keys": [1], "value": "2" },
                { "op": "replace", "keys": [3], "items": 4, "value": "3" }
            ]
        );
        assert_eq!(apply_new(&d, &patch), c);

        let patch = diff(&d, &f);
        assert_json!(
            patch,
            [
                { "op": "add", "keys": [1], "value": "d" },
                { "op": "replace", "keys": [4], "items": 1, "value": "f" },
                { "op": "remove", "keys": [6], "items": 1 }
            ]
        );
        assert_eq!(apply_new(&d, &patch), f);
    }

    /// Test that works with Unicode graphemes (which are made
    /// up of multiple `char`s).
    #[test]
    fn unicode() {
        let a = "ä".to_string();
        let b = "ä1👍🏻2".to_string();
        let c = "1👍🏿2".to_string();

        let patch = diff(&a, &b);
        assert_json!(patch, [
            { "op": "add", "keys": [1], "value": "1👍🏻2" },
        ]);
        assert_eq!(apply_new(&a, &patch), b);

        let patch = diff(&b, &c);
        assert_json!(patch, [
            { "op": "remove", "keys": [0], "items": 1 },
            { "op": "replace", "keys": [2], "items": 1, "value": "🏿" },
        ]);
        assert_eq!(apply_new(&b, &patch), c);

        let patch = diff(&c, &b);
        assert_json!(patch, [
            { "op": "add", "keys": [0], "value": "ä" },
            { "op": "replace", "keys": [3], "items": 1, "value": "🏻" },
        ]);
        assert_eq!(apply_new(&c, &patch), b);
    }

    // Regression tests of minimal failing cases found using property testing
    // and elsewhere.

    #[test]
    fn regression_1() {
        let a = "ab".to_string();
        let b = "bc".to_string();
        let patch = diff(&a, &b);
        assert_json!(patch, [
            { "op": "remove", "keys": [0], "items": 1 },
            { "op": "add", "keys": [1], "value": "c" },
        ]);
        assert_eq!(apply_new(&a, &patch), b);
    }

    #[test]
    fn regression_2() {
        let a = "ac".to_string();
        let b = "bcd".to_string();
        let patch = diff(&a, &b);
        assert_json!(
            patch,
            [
                { "op": "replace", "keys": [0], "items": 1, "value": "b" },
                { "op": "add", "keys": [2], "value": "d" },
            ]
        );
        assert_eq!(apply_new(&a, &patch), b);
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Reorder items.
//!
//! `mod`, `extern crate` and `use` declarations are reorderd in alphabetical
//! order. Trait items are reordered in pre-determined order (associated types
//! and constatns comes before methods).

use config::{Config, lists::*};
use syntax::{ast, attr, codemap::Span};

use codemap::LineRangeUtils;
use comment::combine_strs_with_missing_comments;
use imports::{path_to_imported_ident, rewrite_import};
use items::rewrite_mod;
use lists::{itemize_list, write_list, ListFormatting};
use rewrite::{Rewrite, RewriteContext};
use shape::Shape;
use spanned::Spanned;
use utils::mk_sp;
use visitor::{filter_inline_attrs, rewrite_extern_crate, FmtVisitor};

use std::cmp::Ordering;

fn compare_path_segments(a: &ast::PathSegment, b: &ast::PathSegment) -> Ordering {
    a.identifier.name.as_str().cmp(&b.identifier.name.as_str())
}

fn compare_paths(a: &ast::Path, b: &ast::Path) -> Ordering {
    for segment in a.segments.iter().zip(b.segments.iter()) {
        let ord = compare_path_segments(segment.0, segment.1);
        if ord != Ordering::Equal {
            return ord;
        }
    }
    a.segments.len().cmp(&b.segments.len())
}

fn compare_use_trees(a: &ast::UseTree, b: &ast::UseTree, nested: bool) -> Ordering {
    use ast::UseTreeKind::*;

    // `use_nested_groups` is not yet supported, remove the `if !nested` when support will be
    // fully added
    if !nested {
        let paths_cmp = compare_paths(&a.prefix, &b.prefix);
        if paths_cmp != Ordering::Equal {
            return paths_cmp;
        }
    }

    match (&a.kind, &b.kind) {
        (&Simple(ident_a), &Simple(ident_b)) => {
            let name_a = &*path_to_imported_ident(&a.prefix).name.as_str();
            let name_b = &*path_to_imported_ident(&b.prefix).name.as_str();
            let name_ordering = if name_a == "self" {
                if name_b == "self" {
                    Ordering::Equal
                } else {
                    Ordering::Less
                }
            } else if name_b == "self" {
                Ordering::Greater
            } else {
                name_a.cmp(name_b)
            };
            if name_ordering == Ordering::Equal {
                if ident_a.name.as_str() != name_a {
                    if ident_b.name.as_str() != name_b {
                        ident_a.name.as_str().cmp(&ident_b.name.as_str())
                    } else {
                        Ordering::Greater
                    }
                } else {
                    Ordering::Less
                }
            } else {
                name_ordering
            }
        }
        (&Glob, &Glob) => Ordering::Equal,
        (&Simple(_), _) | (&Glob, &Nested(_)) => Ordering::Less,
        (&Nested(ref a_items), &Nested(ref b_items)) => {
            let mut a = a_items
                .iter()
                .map(|&(ref tree, _)| tree.clone())
                .collect::<Vec<_>>();
            let mut b = b_items
                .iter()
                .map(|&(ref tree, _)| tree.clone())
                .collect::<Vec<_>>();
            a.sort_by(|a, b| compare_use_trees(a, b, true));
            b.sort_by(|a, b| compare_use_trees(a, b, true));
            for comparison_pair in a.iter().zip(b.iter()) {
                let ord = compare_use_trees(comparison_pair.0, comparison_pair.1, true);
                if ord != Ordering::Equal {
                    return ord;
                }
            }
            a.len().cmp(&b.len())
        }
        (&Glob, &Simple(_)) | (&Nested(_), _) => Ordering::Greater,
    }
}

/// Choose the ordering between the given two items.
fn compare_items(a: &ast::Item, b: &ast::Item) -> Ordering {
    match (&a.node, &b.node) {
        (&ast::ItemKind::Mod(..), &ast::ItemKind::Mod(..)) => {
            a.ident.name.as_str().cmp(&b.ident.name.as_str())
        }
        (&ast::ItemKind::Use(ref a_tree), &ast::ItemKind::Use(ref b_tree)) => {
            compare_use_trees(a_tree, b_tree, false)
        }
        (&ast::ItemKind::ExternCrate(ref a_name), &ast::ItemKind::ExternCrate(ref b_name)) => {
            // `extern crate foo as bar;`
            //               ^^^ Comparing this.
            let a_orig_name =
                a_name.map_or_else(|| a.ident.name.as_str(), |symbol| symbol.as_str());
            let b_orig_name =
                b_name.map_or_else(|| b.ident.name.as_str(), |symbol| symbol.as_str());
            let result = a_orig_name.cmp(&b_orig_name);
            if result != Ordering::Equal {
                return result;
            }

            // `extern crate foo as bar;`
            //                      ^^^ Comparing this.
            match (a_name, b_name) {
                (Some(..), None) => Ordering::Greater,
                (None, Some(..)) => Ordering::Less,
                (None, None) => Ordering::Equal,
                (Some(..), Some(..)) => a.ident.name.as_str().cmp(&b.ident.name.as_str()),
            }
        }
        _ => unreachable!(),
    }
}

/// Rewrite a list of items with reordering. Every item in `items` must have
/// the same `ast::ItemKind`.
// TODO (some day) remove unused imports, expand globs, compress many single
// imports into a list import.
fn rewrite_reorderable_items(
    context: &RewriteContext,
    reorderable_items: &[&ast::Item],
    shape: Shape,
    span: Span,
) -> Option<String> {
    let items = itemize_list(
        context.codemap,
        reorderable_items.iter(),
        "",
        ";",
        |item| item.span().lo(),
        |item| item.span().hi(),
        |item| {
            let attrs = filter_inline_attrs(&item.attrs, item.span());
            let attrs_str = attrs.rewrite(context, shape)?;

            let missed_span = if attrs.is_empty() {
                mk_sp(item.span.lo(), item.span.lo())
            } else {
                mk_sp(attrs.last().unwrap().span.hi(), item.span.lo())
            };

            let item_str = match item.node {
                ast::ItemKind::Use(ref tree) => {
                    rewrite_import(context, &item.vis, tree, &item.attrs, shape)?
                }
                ast::ItemKind::ExternCrate(..) => rewrite_extern_crate(context, item)?,
                ast::ItemKind::Mod(..) => rewrite_mod(item),
                _ => return None,
            };

            combine_strs_with_missing_comments(
                context,
                &attrs_str,
                &item_str,
                missed_span,
                shape,
                false,
            )
        },
        span.lo(),
        span.hi(),
        false,
    );
    let mut item_pair_vec: Vec<_> = items.zip(reorderable_items.iter()).collect();
    item_pair_vec.sort_by(|a, b| compare_items(a.1, b.1));
    let item_vec: Vec<_> = item_pair_vec.into_iter().map(|pair| pair.0).collect();

    let fmt = ListFormatting {
        tactic: DefinitiveListTactic::Vertical,
        separator: "",
        trailing_separator: SeparatorTactic::Never,
        separator_place: SeparatorPlace::Back,
        shape,
        ends_with_newline: true,
        preserve_newline: false,
        config: context.config,
    };

    write_list(&item_vec, &fmt)
}

fn contains_macro_use_attr(item: &ast::Item) -> bool {
    attr::contains_name(&filter_inline_attrs(&item.attrs, item.span()), "macro_use")
}

/// A simplified version of `ast::ItemKind`.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
enum ReorderableItemKind {
    ExternCrate,
    Mod,
    Use,
    /// An item that cannot be reordered. Either has an unreorderable item kind
    /// or an `macro_use` attribute.
    Other,
}

impl ReorderableItemKind {
    pub fn from(item: &ast::Item) -> Self {
        match item.node {
            _ if contains_macro_use_attr(item) => ReorderableItemKind::Other,
            ast::ItemKind::ExternCrate(..) => ReorderableItemKind::ExternCrate,
            ast::ItemKind::Mod(..) => ReorderableItemKind::Mod,
            ast::ItemKind::Use(..) => ReorderableItemKind::Use,
            _ => ReorderableItemKind::Other,
        }
    }

    pub fn is_same_item_kind(&self, item: &ast::Item) -> bool {
        ReorderableItemKind::from(item) == *self
    }

    pub fn is_reorderable(&self, config: &Config) -> bool {
        match *self {
            ReorderableItemKind::ExternCrate => config.reorder_extern_crates(),
            ReorderableItemKind::Mod => config.reorder_modules(),
            ReorderableItemKind::Use => config.reorder_imports(),
            ReorderableItemKind::Other => false,
        }
    }

    pub fn in_group(&self, config: &Config) -> bool {
        match *self {
            ReorderableItemKind::ExternCrate => config.reorder_extern_crates_in_group(),
            ReorderableItemKind::Mod => config.reorder_modules(),
            ReorderableItemKind::Use => config.reorder_imports_in_group(),
            ReorderableItemKind::Other => false,
        }
    }
}

impl<'b, 'a: 'b> FmtVisitor<'a> {
    /// Format items with the same item kind and reorder them. If `in_group` is
    /// `true`, then the items separated by an empty line will not be reordered
    /// together.
    fn walk_reorderable_items(
        &mut self,
        items: &[&ast::Item],
        item_kind: ReorderableItemKind,
        in_group: bool,
    ) -> usize {
        let mut last = self.codemap.lookup_line_range(items[0].span());
        let item_length = items
            .iter()
            .take_while(|ppi| {
                item_kind.is_same_item_kind(&***ppi) && (!in_group || {
                    let current = self.codemap.lookup_line_range(ppi.span());
                    let in_same_group = current.lo < last.hi + 2;
                    last = current;
                    in_same_group
                })
            })
            .count();
        let items = &items[..item_length];

        let at_least_one_in_file_lines = items
            .iter()
            .any(|item| !out_of_file_lines_range!(self, item.span));

        if at_least_one_in_file_lines && !items.is_empty() {
            let lo = items.first().unwrap().span().lo();
            let hi = items.last().unwrap().span().hi();
            let span = mk_sp(lo, hi);
            let rw = rewrite_reorderable_items(&self.get_context(), items, self.shape(), span);
            self.push_rewrite(span, rw);
        } else {
            for item in items {
                self.push_rewrite(item.span, None);
            }
        }

        item_length
    }

    /// Visit and format the given items. Items are reordered If they are
    /// consecutive and reorderable.
    pub fn visit_items_with_reordering(&mut self, mut items: &[&ast::Item]) {
        while !items.is_empty() {
            // If the next item is a `use`, `extern crate` or `mod`, then extract it and any
            // subsequent items that have the same item kind to be reordered within
            // `walk_reorderable_items`. Otherwise, just format the next item for output.
            let item_kind = ReorderableItemKind::from(items[0]);
            if item_kind.is_reorderable(self.config) {
                let visited_items_num =
                    self.walk_reorderable_items(items, item_kind, item_kind.in_group(self.config));
                let (_, rest) = items.split_at(visited_items_num);
                items = rest;
            } else {
                // Reaching here means items were not reordered. There must be at least
                // one item left in `items`, so calling `unwrap()` here is safe.
                let (item, rest) = items.split_first().unwrap();
                self.visit_item(item);
                items = rest;
            }
        }
    }
}
<commit_msg>Add TODO<commit_after>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Reorder items.
//!
//! `mod`, `extern crate` and `use` declarations are reorderd in alphabetical
//! order. Trait items are reordered in pre-determined order (associated types
//! and constatns comes before methods).

// TODO(#2455): Reorder trait items.

use config::{Config, lists::*};
use syntax::{ast, attr, codemap::Span};

use codemap::LineRangeUtils;
use comment::combine_strs_with_missing_comments;
use imports::{path_to_imported_ident, rewrite_import};
use items::rewrite_mod;
use lists::{itemize_list, write_list, ListFormatting};
use rewrite::{Rewrite, RewriteContext};
use shape::Shape;
use spanned::Spanned;
use utils::mk_sp;
use visitor::{filter_inline_attrs, rewrite_extern_crate, FmtVisitor};

use std::cmp::Ordering;

fn compare_path_segments(a: &ast::PathSegment, b: &ast::PathSegment) -> Ordering {
    a.identifier.name.as_str().cmp(&b.identifier.name.as_str())
}

fn compare_paths(a: &ast::Path, b: &ast::Path) -> Ordering {
    for segment in a.segments.iter().zip(b.segments.iter()) {
        let ord = compare_path_segments(segment.0, segment.1);
        if ord != Ordering::Equal {
            return ord;
        }
    }
    a.segments.len().cmp(&b.segments.len())
}

fn compare_use_trees(a: &ast::UseTree, b: &ast::UseTree, nested: bool) -> Ordering {
    use ast::UseTreeKind::*;

    // `use_nested_groups` is not yet supported, remove the `if !nested` when support will be
    // fully added
    if !nested {
        let paths_cmp = compare_paths(&a.prefix, &b.prefix);
        if paths_cmp != Ordering::Equal {
            return paths_cmp;
        }
    }

    match (&a.kind, &b.kind) {
        (&Simple(ident_a), &Simple(ident_b)) => {
            let name_a = &*path_to_imported_ident(&a.prefix).name.as_str();
            let name_b = &*path_to_imported_ident(&b.prefix).name.as_str();
            let name_ordering = if name_a == "self" {
                if name_b == "self" {
                    Ordering::Equal
                } else {
                    Ordering::Less
                }
            } else if name_b == "self" {
                Ordering::Greater
            } else {
                name_a.cmp(name_b)
            };
            if name_ordering == Ordering::Equal {
                if ident_a.name.as_str() != name_a {
                    if ident_b.name.as_str() != name_b {
                        ident_a.name.as_str().cmp(&ident_b.name.as_str())
                    } else {
                        Ordering::Greater
                    }
                } else {
                    Ordering::Less
                }
            } else {
                name_ordering
            }
        }
        (&Glob, &Glob) => Ordering::Equal,
        (&Simple(_), _) | (&Glob, &Nested(_)) => Ordering::Less,
        (&Nested(ref a_items), &Nested(ref b_items)) => {
            let mut a = a_items
                .iter()
                .map(|&(ref tree, _)| tree.clone())
                .collect::<Vec<_>>();
            let mut b = b_items
                .iter()
                .map(|&(ref tree, _)| tree.clone())
                .collect::<Vec<_>>();
            a.sort_by(|a, b| compare_use_trees(a, b, true));
            b.sort_by(|a, b| compare_use_trees(a, b, true));
            for comparison_pair in a.iter().zip(b.iter()) {
                let ord = compare_use_trees(comparison_pair.0, comparison_pair.1, true);
                if ord != Ordering::Equal {
                    return ord;
                }
            }
            a.len().cmp(&b.len())
        }
        (&Glob, &Simple(_)) | (&Nested(_), _) => Ordering::Greater,
    }
}

/// Choose the ordering between the given two items.
fn compare_items(a: &ast::Item, b: &ast::Item) -> Ordering {
    match (&a.node, &b.node) {
        (&ast::ItemKind::Mod(..), &ast::ItemKind::Mod(..)) => {
            a.ident.name.as_str().cmp(&b.ident.name.as_str())
        }
        (&ast::ItemKind::Use(ref a_tree), &ast::ItemKind::Use(ref b_tree)) => {
            compare_use_trees(a_tree, b_tree, false)
        }
        (&ast::ItemKind::ExternCrate(ref a_name), &ast::ItemKind::ExternCrate(ref b_name)) => {
            // `extern crate foo as bar;`
            //               ^^^ Comparing this.
            let a_orig_name =
                a_name.map_or_else(|| a.ident.name.as_str(), |symbol| symbol.as_str());
            let b_orig_name =
                b_name.map_or_else(|| b.ident.name.as_str(), |symbol| symbol.as_str());
            let result = a_orig_name.cmp(&b_orig_name);
            if result != Ordering::Equal {
                return result;
            }

            // `extern crate foo as bar;`
            //                      ^^^ Comparing this.
            match (a_name, b_name) {
                (Some(..), None) => Ordering::Greater,
                (None, Some(..)) => Ordering::Less,
                (None, None) => Ordering::Equal,
                (Some(..), Some(..)) => a.ident.name.as_str().cmp(&b.ident.name.as_str()),
            }
        }
        _ => unreachable!(),
    }
}

/// Rewrite a list of items with reordering. Every item in `items` must have
/// the same `ast::ItemKind`.
// TODO (some day) remove unused imports, expand globs, compress many single
// imports into a list import.
fn rewrite_reorderable_items(
    context: &RewriteContext,
    reorderable_items: &[&ast::Item],
    shape: Shape,
    span: Span,
) -> Option<String> {
    let items = itemize_list(
        context.codemap,
        reorderable_items.iter(),
        "",
        ";",
        |item| item.span().lo(),
        |item| item.span().hi(),
        |item| {
            let attrs = filter_inline_attrs(&item.attrs, item.span());
            let attrs_str = attrs.rewrite(context, shape)?;

            let missed_span = if attrs.is_empty() {
                mk_sp(item.span.lo(), item.span.lo())
            } else {
                mk_sp(attrs.last().unwrap().span.hi(), item.span.lo())
            };

            let item_str = match item.node {
                ast::ItemKind::Use(ref tree) => {
                    rewrite_import(context, &item.vis, tree, &item.attrs, shape)?
                }
                ast::ItemKind::ExternCrate(..) => rewrite_extern_crate(context, item)?,
                ast::ItemKind::Mod(..) => rewrite_mod(item),
                _ => return None,
            };

            combine_strs_with_missing_comments(
                context,
                &attrs_str,
                &item_str,
                missed_span,
                shape,
                false,
            )
        },
        span.lo(),
        span.hi(),
        false,
    );
    let mut item_pair_vec: Vec<_> = items.zip(reorderable_items.iter()).collect();
    item_pair_vec.sort_by(|a, b| compare_items(a.1, b.1));
    let item_vec: Vec<_> = item_pair_vec.into_iter().map(|pair| pair.0).collect();

    let fmt = ListFormatting {
        tactic: DefinitiveListTactic::Vertical,
        separator: "",
        trailing_separator: SeparatorTactic::Never,
        separator_place: SeparatorPlace::Back,
        shape,
        ends_with_newline: true,
        preserve_newline: false,
        config: context.config,
    };

    write_list(&item_vec, &fmt)
}

fn contains_macro_use_attr(item: &ast::Item) -> bool {
    attr::contains_name(&filter_inline_attrs(&item.attrs, item.span()), "macro_use")
}

/// A simplified version of `ast::ItemKind`.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
enum ReorderableItemKind {
    ExternCrate,
    Mod,
    Use,
    /// An item that cannot be reordered. Either has an unreorderable item kind
    /// or an `macro_use` attribute.
    Other,
}

impl ReorderableItemKind {
    pub fn from(item: &ast::Item) -> Self {
        match item.node {
            _ if contains_macro_use_attr(item) => ReorderableItemKind::Other,
            ast::ItemKind::ExternCrate(..) => ReorderableItemKind::ExternCrate,
            ast::ItemKind::Mod(..) => ReorderableItemKind::Mod,
            ast::ItemKind::Use(..) => ReorderableItemKind::Use,
            _ => ReorderableItemKind::Other,
        }
    }

    pub fn is_same_item_kind(&self, item: &ast::Item) -> bool {
        ReorderableItemKind::from(item) == *self
    }

    pub fn is_reorderable(&self, config: &Config) -> bool {
        match *self {
            ReorderableItemKind::ExternCrate => config.reorder_extern_crates(),
            ReorderableItemKind::Mod => config.reorder_modules(),
            ReorderableItemKind::Use => config.reorder_imports(),
            ReorderableItemKind::Other => false,
        }
    }

    pub fn in_group(&self, config: &Config) -> bool {
        match *self {
            ReorderableItemKind::ExternCrate => config.reorder_extern_crates_in_group(),
            ReorderableItemKind::Mod => config.reorder_modules(),
            ReorderableItemKind::Use => config.reorder_imports_in_group(),
            ReorderableItemKind::Other => false,
        }
    }
}

impl<'b, 'a: 'b> FmtVisitor<'a> {
    /// Format items with the same item kind and reorder them. If `in_group` is
    /// `true`, then the items separated by an empty line will not be reordered
    /// together.
    fn walk_reorderable_items(
        &mut self,
        items: &[&ast::Item],
        item_kind: ReorderableItemKind,
        in_group: bool,
    ) -> usize {
        let mut last = self.codemap.lookup_line_range(items[0].span());
        let item_length = items
            .iter()
            .take_while(|ppi| {
                item_kind.is_same_item_kind(&***ppi) && (!in_group || {
                    let current = self.codemap.lookup_line_range(ppi.span());
                    let in_same_group = current.lo < last.hi + 2;
                    last = current;
                    in_same_group
                })
            })
            .count();
        let items = &items[..item_length];

        let at_least_one_in_file_lines = items
            .iter()
            .any(|item| !out_of_file_lines_range!(self, item.span));

        if at_least_one_in_file_lines && !items.is_empty() {
            let lo = items.first().unwrap().span().lo();
            let hi = items.last().unwrap().span().hi();
            let span = mk_sp(lo, hi);
            let rw = rewrite_reorderable_items(&self.get_context(), items, self.shape(), span);
            self.push_rewrite(span, rw);
        } else {
            for item in items {
                self.push_rewrite(item.span, None);
            }
        }

        item_length
    }

    /// Visit and format the given items. Items are reordered If they are
    /// consecutive and reorderable.
    pub fn visit_items_with_reordering(&mut self, mut items: &[&ast::Item]) {
        while !items.is_empty() {
            // If the next item is a `use`, `extern crate` or `mod`, then extract it and any
            // subsequent items that have the same item kind to be reordered within
            // `walk_reorderable_items`. Otherwise, just format the next item for output.
            let item_kind = ReorderableItemKind::from(items[0]);
            if item_kind.is_reorderable(self.config) {
                let visited_items_num =
                    self.walk_reorderable_items(items, item_kind, item_kind.in_group(self.config));
                let (_, rest) = items.split_at(visited_items_num);
                items = rest;
            } else {
                // Reaching here means items were not reordered. There must be at least
                // one item left in `items`, so calling `unwrap()` here is safe.
                let (item, rest) = items.split_first().unwrap();
                self.visit_item(item);
                items = rest;
            }
        }
    }
}
<|endoftext|>


<commit_before>//! This module handles the expected information a crate should have
//! and manages the serialising and deserialising of this information
//! to and from structs. The serlializing is only utilised in
//! integration tests.
use std::collections::HashMap;

use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use semver;

use models::krate::MAX_NAME_LENGTH;

use models::Keyword as CrateKeyword;
use models::DependencyKind;
use models::Crate;

#[derive(Deserialize, Serialize, Debug)]
pub struct NewCrate {
    pub name: CrateName,
    pub vers: CrateVersion,
    pub deps: Vec<CrateDependency>,
    pub features: HashMap<FeatureName, Vec<Feature>>,
    pub authors: Vec<String>,
    pub description: Option<String>,
    pub homepage: Option<String>,
    pub documentation: Option<String>,
    pub readme: Option<String>,
    pub readme_file: Option<String>,
    pub keywords: Option<KeywordList>,
    pub categories: Option<CategoryList>,
    pub license: Option<String>,
    pub license_file: Option<String>,
    pub repository: Option<String>,
    pub badges: Option<HashMap<String, HashMap<String, String>>>,
    #[serde(default)]
    pub links: Option<String>,
}

#[derive(PartialEq, Eq, Hash, Serialize, Debug, Deref)]
pub struct CrateName(pub String);
#[derive(Debug, Deref)]
pub struct CrateVersion(pub semver::Version);
#[derive(Debug, Deref)]
pub struct CrateVersionReq(pub semver::VersionReq);
#[derive(Serialize, Debug, Deref)]
pub struct KeywordList(pub Vec<Keyword>);
#[derive(Serialize, Debug, Deref)]
pub struct Keyword(pub String);
#[derive(Serialize, Debug, Deref)]
pub struct CategoryList(pub Vec<Category>);
#[derive(Serialize, Deserialize, Debug, Deref)]
pub struct Category(pub String);
#[derive(Serialize, Debug, Deref)]
pub struct Feature(pub String);
#[derive(PartialEq, Eq, Hash, Serialize, Debug, Deref)]
pub struct FeatureName(pub String);

#[derive(Serialize, Deserialize, Debug)]
pub struct CrateDependency {
    pub optional: bool,
    pub default_features: bool,
    pub name: CrateName,
    pub features: Vec<Feature>,
    pub version_req: CrateVersionReq,
    pub target: Option<String>,
    pub kind: Option<DependencyKind>,
}

impl<'de> Deserialize<'de> for CrateName {
    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<CrateName, D::Error> {
        let s = String::deserialize(d)?;
        if !Crate::valid_name(&s) {
            let value = de::Unexpected::Str(&s);
            let expected = format!(
                "a valid crate name to start with a letter, contain only letters, \
                 numbers, hyphens, or underscores and have at most {} characters",
                MAX_NAME_LENGTH
            );
            Err(de::Error::invalid_value(value, &expected.as_ref()))
        } else {
            Ok(CrateName(s))
        }
    }
}

impl<T: ?Sized> PartialEq<T> for CrateName
where
    String: PartialEq<T>,
{
    fn eq(&self, rhs: &T) -> bool {
        self.0 == *rhs
    }
}

impl<'de> Deserialize<'de> for Keyword {
    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Keyword, D::Error> {
        let s = String::deserialize(d)?;
        if !CrateKeyword::valid_name(&s) {
            let value = de::Unexpected::Str(&s);
            let expected = "a valid keyword specifier";
            Err(de::Error::invalid_value(value, &expected))
        } else {
            Ok(Keyword(s))
        }
    }
}

impl<'de> Deserialize<'de> for FeatureName {
    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
        let s = String::deserialize(d)?;
        if !Crate::valid_feature_name(&s) {
            let value = de::Unexpected::Str(&s);
            let expected = "a valid feature name containing only letters, \
                            numbers, hyphens, or underscores";
            Err(de::Error::invalid_value(value, &expected))
        } else {
            Ok(FeatureName(s))
        }
    }
}

impl<'de> Deserialize<'de> for Feature {
    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Feature, D::Error> {
        let s = String::deserialize(d)?;
        if !Crate::valid_feature(&s) {
            let value = de::Unexpected::Str(&s);
            let expected = "a valid feature name";
            Err(de::Error::invalid_value(value, &expected))
        } else {
            Ok(Feature(s))
        }
    }
}

impl<'de> Deserialize<'de> for CrateVersion {
    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<CrateVersion, D::Error> {
        let s = String::deserialize(d)?;
        match semver::Version::parse(&s) {
            Ok(v) => Ok(CrateVersion(v)),
            Err(..) => {
                let value = de::Unexpected::Str(&s);
                let expected = "a valid semver";
                Err(de::Error::invalid_value(value, &expected))
            }
        }
    }
}

impl<'de> Deserialize<'de> for CrateVersionReq {
    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<CrateVersionReq, D::Error> {
        let s = String::deserialize(d)?;
        match semver::VersionReq::parse(&s) {
            Ok(v) => Ok(CrateVersionReq(v)),
            Err(..) => {
                let value = de::Unexpected::Str(&s);
                let expected = "a valid version req";
                Err(de::Error::invalid_value(value, &expected))
            }
        }
    }
}

impl<T: ?Sized> PartialEq<T> for CrateVersionReq
where
    semver::VersionReq: PartialEq<T>,
{
    fn eq(&self, rhs: &T) -> bool {
        self.0 == *rhs
    }
}

impl<'de> Deserialize<'de> for KeywordList {
    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<KeywordList, D::Error> {
        let inner = <Vec<Keyword> as Deserialize<'de>>::deserialize(d)?;
        if inner.len() > 5 {
            let expected = "at most 5 keywords per crate";
            return Err(de::Error::invalid_length(inner.len(), &expected));
        }
        for val in &inner {
            if val.len() > 20 {
                let expected = "a keyword with less than 20 characters";
                return Err(de::Error::invalid_length(val.len(), &expected));
            }
        }
        Ok(KeywordList(inner))
    }
}

impl<'de> Deserialize<'de> for CategoryList {
    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<CategoryList, D::Error> {
        let inner = <Vec<Category> as Deserialize<'de>>::deserialize(d)?;
        if inner.len() > 5 {
            let expected = "at most 5 categories per crate";
            Err(de::Error::invalid_length(inner.len(), &expected))
        } else {
            Ok(CategoryList(inner))
        }
    }
}

impl Serialize for CrateVersion {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(&(**self).to_string())
    }
}

impl Serialize for CrateVersionReq {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(&(**self).to_string())
    }
}

use diesel::pg::Pg;
use diesel::serialize::{self, Output, ToSql};
use diesel::sql_types::Text;
use std::io::Write;

impl ToSql<Text, Pg> for Feature {
    fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
        ToSql::<Text, Pg>::to_sql(&**self, out)
    }
}
<commit_msg>Regression test for #1334<commit_after>//! This module handles the expected information a crate should have
//! and manages the serialising and deserialising of this information
//! to and from structs. The serlializing is only utilised in
//! integration tests.
use std::collections::HashMap;

use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use semver;

use models::krate::MAX_NAME_LENGTH;

use models::Keyword as CrateKeyword;
use models::DependencyKind;
use models::Crate;

#[derive(Deserialize, Serialize, Debug)]
pub struct NewCrate {
    pub name: CrateName,
    pub vers: CrateVersion,
    pub deps: Vec<CrateDependency>,
    pub features: HashMap<FeatureName, Vec<Feature>>,
    pub authors: Vec<String>,
    pub description: Option<String>,
    pub homepage: Option<String>,
    pub documentation: Option<String>,
    pub readme: Option<String>,
    pub readme_file: Option<String>,
    pub keywords: Option<KeywordList>,
    pub categories: Option<CategoryList>,
    pub license: Option<String>,
    pub license_file: Option<String>,
    pub repository: Option<String>,
    pub badges: Option<HashMap<String, HashMap<String, String>>>,
    #[serde(default)]
    pub links: Option<String>,
}

#[derive(PartialEq, Eq, Hash, Serialize, Debug, Deref)]
pub struct CrateName(pub String);
#[derive(Debug, Deref)]
pub struct CrateVersion(pub semver::Version);
#[derive(Debug, Deref)]
pub struct CrateVersionReq(pub semver::VersionReq);
#[derive(Serialize, Debug, Deref)]
pub struct KeywordList(pub Vec<Keyword>);
#[derive(Serialize, Debug, Deref)]
pub struct Keyword(pub String);
#[derive(Serialize, Debug, Deref)]
pub struct CategoryList(pub Vec<Category>);
#[derive(Serialize, Deserialize, Debug, Deref)]
pub struct Category(pub String);
#[derive(Serialize, Debug, Deref)]
pub struct Feature(pub String);
#[derive(PartialEq, Eq, Hash, Serialize, Debug, Deref)]
pub struct FeatureName(pub String);

#[derive(Serialize, Deserialize, Debug)]
pub struct CrateDependency {
    pub optional: bool,
    pub default_features: bool,
    pub name: CrateName,
    pub features: Vec<Feature>,
    pub version_req: CrateVersionReq,
    pub target: Option<String>,
    pub kind: Option<DependencyKind>,
}

impl<'de> Deserialize<'de> for CrateName {
    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<CrateName, D::Error> {
        let s = String::deserialize(d)?;
        if !Crate::valid_name(&s) {
            let value = de::Unexpected::Str(&s);
            let expected = format!(
                "a valid crate name to start with a letter, contain only letters, \
                 numbers, hyphens, or underscores and have at most {} characters",
                MAX_NAME_LENGTH
            );
            Err(de::Error::invalid_value(value, &expected.as_ref()))
        } else {
            Ok(CrateName(s))
        }
    }
}

impl<T: ?Sized> PartialEq<T> for CrateName
where
    String: PartialEq<T>,
{
    fn eq(&self, rhs: &T) -> bool {
        self.0 == *rhs
    }
}

impl<'de> Deserialize<'de> for Keyword {
    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Keyword, D::Error> {
        let s = String::deserialize(d)?;
        if !CrateKeyword::valid_name(&s) {
            let value = de::Unexpected::Str(&s);
            let expected = "a valid keyword specifier";
            Err(de::Error::invalid_value(value, &expected))
        } else {
            Ok(Keyword(s))
        }
    }
}

impl<'de> Deserialize<'de> for FeatureName {
    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
        let s = String::deserialize(d)?;
        if !Crate::valid_feature_name(&s) {
            let value = de::Unexpected::Str(&s);
            let expected = "a valid feature name containing only letters, \
                            numbers, hyphens, or underscores";
            Err(de::Error::invalid_value(value, &expected))
        } else {
            Ok(FeatureName(s))
        }
    }
}

impl<'de> Deserialize<'de> for Feature {
    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Feature, D::Error> {
        let s = String::deserialize(d)?;
        if !Crate::valid_feature(&s) {
            let value = de::Unexpected::Str(&s);
            let expected = "a valid feature name";
            Err(de::Error::invalid_value(value, &expected))
        } else {
            Ok(Feature(s))
        }
    }
}

impl<'de> Deserialize<'de> for CrateVersion {
    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<CrateVersion, D::Error> {
        let s = String::deserialize(d)?;
        match semver::Version::parse(&s) {
            Ok(v) => Ok(CrateVersion(v)),
            Err(..) => {
                let value = de::Unexpected::Str(&s);
                let expected = "a valid semver";
                Err(de::Error::invalid_value(value, &expected))
            }
        }
    }
}

impl<'de> Deserialize<'de> for CrateVersionReq {
    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<CrateVersionReq, D::Error> {
        let s = String::deserialize(d)?;
        match semver::VersionReq::parse(&s) {
            Ok(v) => Ok(CrateVersionReq(v)),
            Err(..) => {
                let value = de::Unexpected::Str(&s);
                let expected = "a valid version req";
                Err(de::Error::invalid_value(value, &expected))
            }
        }
    }
}

impl<T: ?Sized> PartialEq<T> for CrateVersionReq
where
    semver::VersionReq: PartialEq<T>,
{
    fn eq(&self, rhs: &T) -> bool {
        self.0 == *rhs
    }
}

impl<'de> Deserialize<'de> for KeywordList {
    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<KeywordList, D::Error> {
        let inner = <Vec<Keyword> as Deserialize<'de>>::deserialize(d)?;
        if inner.len() > 5 {
            let expected = "at most 5 keywords per crate";
            return Err(de::Error::invalid_length(inner.len(), &expected));
        }
        for val in &inner {
            if val.len() > 20 {
                let expected = "a keyword with less than 20 characters";
                return Err(de::Error::invalid_length(val.len(), &expected));
            }
        }
        Ok(KeywordList(inner))
    }
}

impl<'de> Deserialize<'de> for CategoryList {
    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<CategoryList, D::Error> {
        let inner = <Vec<Category> as Deserialize<'de>>::deserialize(d)?;
        if inner.len() > 5 {
            let expected = "at most 5 categories per crate";
            Err(de::Error::invalid_length(inner.len(), &expected))
        } else {
            Ok(CategoryList(inner))
        }
    }
}

impl Serialize for CrateVersion {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(&(**self).to_string())
    }
}

impl Serialize for CrateVersionReq {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(&(**self).to_string())
    }
}

use diesel::pg::Pg;
use diesel::serialize::{self, Output, ToSql};
use diesel::sql_types::Text;
use std::io::Write;

impl ToSql<Text, Pg> for Feature {
    fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
        ToSql::<Text, Pg>::to_sql(&**self, out)
    }
}

#[test]
fn feature_deserializes_for_valid_features() {
    use serde_json as json;

    assert!(json::from_str::<Feature>("\"foo\"").is_ok());
    assert!(json::from_str::<Feature>("\"\"").is_err());
    assert!(json::from_str::<Feature>("\"/\"").is_err());
    assert!(json::from_str::<Feature>("\"%/%\"").is_err());
    assert!(json::from_str::<Feature>("\"a/a\"").is_ok());
    assert!(json::from_str::<Feature>("\"32-column-tables\"").is_ok());
}
<|endoftext|>


<commit_before>// Functionality that is shared between the cxxbridge macro and the cmd.

pub mod atom;
mod attrs;
pub mod check;
mod derive;
mod discriminant;
mod doc;
pub mod error;
pub mod file;
pub mod ident;
mod impls;
pub mod mangle;
pub mod namespace;
mod parse;
pub mod qualified;
pub mod report;
pub mod set;
pub mod symbol;
mod tokens;
pub mod types;

use self::discriminant::Discriminant;
use self::namespace::Namespace;
use self::parse::kw;
use self::symbol::Symbol;
use proc_macro2::{Ident, Span};
use syn::punctuated::Punctuated;
use syn::token::{Brace, Bracket, Paren};
use syn::{Expr, Lifetime, Token, Type as RustType};

pub use self::atom::Atom;
pub use self::derive::Derive;
pub use self::doc::Doc;
pub use self::parse::parse_items;
pub use self::types::Types;

#[derive(Clone)]
/// A C++ identifier in a particular namespace.
/// It is intentional that this does not impl Display,
/// because we want to force users actively to decide whether to output
/// it as a qualified name or as an unqualfiied name.
pub struct CppName {
    pub ns: Namespace,
    pub ident: Ident,
}

pub enum Api {
    Include(Include),
    Struct(Struct),
    Enum(Enum),
    CxxType(ExternType),
    CxxFunction(ExternFn),
    RustType(ExternType),
    RustFunction(ExternFn),
    TypeAlias(TypeAlias),
    Impl(Impl),
}

pub struct Include {
    pub path: String,
    pub kind: IncludeKind,
    pub begin_span: Span,
    pub end_span: Span,
}

/// Whether to emit `#include "path"` or `#include <path>`.
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum IncludeKind {
    /// `#include "quoted/path/to"`
    Quoted,
    /// `#include <bracketed/path/to>`
    Bracketed,
}

pub struct ExternType {
    pub doc: Doc,
    pub type_token: Token![type],
    pub ident: Pair,
    pub semi_token: Token![;],
    pub trusted: bool,
}

pub struct Struct {
    pub doc: Doc,
    pub derives: Vec<Derive>,
    pub struct_token: Token![struct],
    pub ident: Pair,
    pub brace_token: Brace,
    pub fields: Vec<Var>,
}

pub struct Enum {
    pub doc: Doc,
    pub enum_token: Token![enum],
    pub ident: Pair,
    pub brace_token: Brace,
    pub variants: Vec<Variant>,
    pub repr: Atom,
}

/// A type with a defined Rust name and a fully resolved,
/// qualified, namespaced, C++ name.
#[derive(Clone)]
pub struct Pair {
    pub cxx: CppName,
    pub rust: Ident,
}

pub struct ExternFn {
    pub lang: Lang,
    pub doc: Doc,
    pub ident: Pair,
    pub sig: Signature,
    pub semi_token: Token![;],
}

pub struct TypeAlias {
    pub doc: Doc,
    pub type_token: Token![type],
    pub ident: Pair,
    pub eq_token: Token![=],
    pub ty: RustType,
    pub semi_token: Token![;],
}

pub struct Impl {
    pub impl_token: Token![impl],
    pub ty: Type,
    pub brace_token: Brace,
}

pub struct Signature {
    pub unsafety: Option<Token![unsafe]>,
    pub fn_token: Token![fn],
    pub receiver: Option<Receiver>,
    pub args: Punctuated<Var, Token![,]>,
    pub ret: Option<Type>,
    pub throws: bool,
    pub paren_token: Paren,
    pub throws_tokens: Option<(kw::Result, Token![<], Token![>])>,
}

#[derive(Eq, PartialEq, Hash)]
pub struct Var {
    pub ident: Ident,
    pub ty: Type,
}

pub struct Receiver {
    pub ampersand: Token![&],
    pub lifetime: Option<Lifetime>,
    pub mutability: Option<Token![mut]>,
    pub var: Token![self],
    pub ty: ResolvableName,
    pub shorthand: bool,
}

pub struct Variant {
    pub ident: Ident,
    pub discriminant: Discriminant,
    pub expr: Option<Expr>,
}

pub enum Type {
    Ident(ResolvableName),
    RustBox(Box<Ty1>),
    RustVec(Box<Ty1>),
    UniquePtr(Box<Ty1>),
    Ref(Box<Ref>),
    Str(Box<Ref>),
    CxxVector(Box<Ty1>),
    Fn(Box<Signature>),
    Void(Span),
    Slice(Box<Slice>),
    SliceRefU8(Box<Ref>),
}

pub struct Ty1 {
    pub name: ResolvableName,
    pub langle: Token![<],
    pub inner: Type,
    pub rangle: Token![>],
}

pub struct Ref {
    pub ampersand: Token![&],
    pub lifetime: Option<Lifetime>,
    pub mutability: Option<Token![mut]>,
    pub inner: Type,
}

pub struct Slice {
    pub bracket: Bracket,
    pub inner: Type,
}

#[derive(Copy, Clone, PartialEq)]
pub enum Lang {
    Cxx,
    Rust,
}

/// Wrapper for a type which needs to be resolved
/// before it can be printed in C++.
#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct ResolvableName {
    pub rust: Ident,
}
<commit_msg>Collect name-related structs to the bottom of syntax tree definition<commit_after>// Functionality that is shared between the cxxbridge macro and the cmd.

pub mod atom;
mod attrs;
pub mod check;
mod derive;
mod discriminant;
mod doc;
pub mod error;
pub mod file;
pub mod ident;
mod impls;
pub mod mangle;
pub mod namespace;
mod parse;
pub mod qualified;
pub mod report;
pub mod set;
pub mod symbol;
mod tokens;
pub mod types;

use self::discriminant::Discriminant;
use self::namespace::Namespace;
use self::parse::kw;
use self::symbol::Symbol;
use proc_macro2::{Ident, Span};
use syn::punctuated::Punctuated;
use syn::token::{Brace, Bracket, Paren};
use syn::{Expr, Lifetime, Token, Type as RustType};

pub use self::atom::Atom;
pub use self::derive::Derive;
pub use self::doc::Doc;
pub use self::parse::parse_items;
pub use self::types::Types;

pub enum Api {
    Include(Include),
    Struct(Struct),
    Enum(Enum),
    CxxType(ExternType),
    CxxFunction(ExternFn),
    RustType(ExternType),
    RustFunction(ExternFn),
    TypeAlias(TypeAlias),
    Impl(Impl),
}

pub struct Include {
    pub path: String,
    pub kind: IncludeKind,
    pub begin_span: Span,
    pub end_span: Span,
}

/// Whether to emit `#include "path"` or `#include <path>`.
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum IncludeKind {
    /// `#include "quoted/path/to"`
    Quoted,
    /// `#include <bracketed/path/to>`
    Bracketed,
}

pub struct ExternType {
    pub doc: Doc,
    pub type_token: Token![type],
    pub ident: Pair,
    pub semi_token: Token![;],
    pub trusted: bool,
}

pub struct Struct {
    pub doc: Doc,
    pub derives: Vec<Derive>,
    pub struct_token: Token![struct],
    pub ident: Pair,
    pub brace_token: Brace,
    pub fields: Vec<Var>,
}

pub struct Enum {
    pub doc: Doc,
    pub enum_token: Token![enum],
    pub ident: Pair,
    pub brace_token: Brace,
    pub variants: Vec<Variant>,
    pub repr: Atom,
}

pub struct ExternFn {
    pub lang: Lang,
    pub doc: Doc,
    pub ident: Pair,
    pub sig: Signature,
    pub semi_token: Token![;],
}

pub struct TypeAlias {
    pub doc: Doc,
    pub type_token: Token![type],
    pub ident: Pair,
    pub eq_token: Token![=],
    pub ty: RustType,
    pub semi_token: Token![;],
}

pub struct Impl {
    pub impl_token: Token![impl],
    pub ty: Type,
    pub brace_token: Brace,
}

pub struct Signature {
    pub unsafety: Option<Token![unsafe]>,
    pub fn_token: Token![fn],
    pub receiver: Option<Receiver>,
    pub args: Punctuated<Var, Token![,]>,
    pub ret: Option<Type>,
    pub throws: bool,
    pub paren_token: Paren,
    pub throws_tokens: Option<(kw::Result, Token![<], Token![>])>,
}

#[derive(Eq, PartialEq, Hash)]
pub struct Var {
    pub ident: Ident,
    pub ty: Type,
}

pub struct Receiver {
    pub ampersand: Token![&],
    pub lifetime: Option<Lifetime>,
    pub mutability: Option<Token![mut]>,
    pub var: Token![self],
    pub ty: ResolvableName,
    pub shorthand: bool,
}

pub struct Variant {
    pub ident: Ident,
    pub discriminant: Discriminant,
    pub expr: Option<Expr>,
}

pub enum Type {
    Ident(ResolvableName),
    RustBox(Box<Ty1>),
    RustVec(Box<Ty1>),
    UniquePtr(Box<Ty1>),
    Ref(Box<Ref>),
    Str(Box<Ref>),
    CxxVector(Box<Ty1>),
    Fn(Box<Signature>),
    Void(Span),
    Slice(Box<Slice>),
    SliceRefU8(Box<Ref>),
}

pub struct Ty1 {
    pub name: ResolvableName,
    pub langle: Token![<],
    pub inner: Type,
    pub rangle: Token![>],
}

pub struct Ref {
    pub ampersand: Token![&],
    pub lifetime: Option<Lifetime>,
    pub mutability: Option<Token![mut]>,
    pub inner: Type,
}

pub struct Slice {
    pub bracket: Bracket,
    pub inner: Type,
}

#[derive(Copy, Clone, PartialEq)]
pub enum Lang {
    Cxx,
    Rust,
}

/// A type with a defined Rust name and a fully resolved,
/// qualified, namespaced, C++ name.
#[derive(Clone)]
pub struct Pair {
    pub cxx: CppName,
    pub rust: Ident,
}

#[derive(Clone)]
/// A C++ identifier in a particular namespace.
/// It is intentional that this does not impl Display,
/// because we want to force users actively to decide whether to output
/// it as a qualified name or as an unqualfiied name.
pub struct CppName {
    pub ns: Namespace,
    pub ident: Ident,
}

/// Wrapper for a type which needs to be resolved
/// before it can be printed in C++.
#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct ResolvableName {
    pub rust: Ident,
}
<|endoftext|>


<commit_before>use diesel::{ExpressionMethods, QueryDsl, QueryResult, RunQueryDsl};
use juniper::FieldResult;

use juniper_ext::*;
use root::ApiContext;
use schema::users;

use super::*;

#[derive(Debug, juniper::GraphQLInputObject, Insertable)]
#[table_name = "users"]
pub struct UserInput {
    /// Id of the user
    pub id: String,
    /// Display name of the user
    pub display_name: String,
    /// Login token of the user
    pub token: String,
}

#[derive(Debug, juniper::GraphQLInputObject, AsChangeset)]
#[table_name = "users"]
pub struct UserUpdateInput {
    pub id: String,
    pub display_name: Option<String>,
    pub token: Option<String>,
}

#[derive(Queryable)]
struct UserData {
    id: String,
    display_name: String,
    #[allow(dead_code)]
    token: String,
}

pub struct User<'a> {
    #[allow(dead_code)]
    context: &'a ApiContext<'a>,
    data: UserData,
}

/// Wraps a String that identifies a user
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, GraphQLNewtype)]
pub struct UserId(pub String);

impl<'a> User<'a> {
    /// Find a user from his token
    pub fn by_token(context: &'a ApiContext, token: &str) -> FieldResult<Self> {
        Ok(Self {
            context,
            data: users::table
                .filter(users::dsl::token.eq(token))
                .first(&context.database)?,
        })
    }

    /// Find a user from his ID
    pub fn by_id(context: &'a ApiContext, user_id: UserId) -> FieldResult<Self> {
        Ok(Self {
            context,
            data: users::table.find(user_id.0).first(&context.database)?,
        })
    }

    /// List all users
    pub fn list(context: &'a ApiContext) -> FieldResult<Vec<Self>> {
        Ok(users::table
            .load(&context.database)?
            .into_iter()
            .map(|data| Self { context, data })
            .collect())
    }

    /// Insert a new user in the db
    pub fn insert<T: IntoIterator<Item = UserInput>>(
        context: &ApiContext,
        inputs: T,
    ) -> QueryResult<()> {
        for input in inputs.into_iter() {
            diesel::insert_into(users::table)
                .values(input)
                .execute(&context.database)?;
        }
        Ok(())
    }

    pub fn update<T: IntoIterator<Item = UserUpdateInput>>(
        context: &ApiContext,
        inputs: T,
    ) -> QueryResult<()> {
        for input in inputs.into_iter() {
            diesel::update(users::table)
                .filter(users::dsl::id.eq(&input.id))
                .set(&input)
                .execute(&context.database)?;
        }
        Ok(())
    }

    /// Delete a user from the db
    pub fn delete<T: IntoIterator<Item = String>>(context: &ApiContext, ids: T) -> QueryResult<()> {
        diesel::delete(users::table)
            .filter(users::dsl::id.eq_any(ids))
            .execute(&context.database)?;
        Ok(())
    }
}

#[graphql]
impl User<'_> {
    /// Id of the user
    pub fn id(&self) -> UserId {
        UserId(self.data.id.clone())
    }

    /// Display name of the user, i.e. the full name
    pub fn display_name(&self) -> &String {
        &self.data.display_name
    }

    pub fn contest_view(&self) -> FieldResult<ContestView> {
        ContestView::new(&self.context, Some(self.id()))
    }
}
<commit_msg>Fix compile error<commit_after>use diesel::{ExpressionMethods, QueryDsl, QueryResult, RunQueryDsl};
use juniper::FieldResult;

use juniper_ext::*;
use root::ApiContext;
use schema::users;

use super::*;
use crate::api::contest::ContestView;

#[derive(Debug, juniper::GraphQLInputObject, Insertable)]
#[table_name = "users"]
pub struct UserInput {
    /// Id of the user
    pub id: String,
    /// Display name of the user
    pub display_name: String,
    /// Login token of the user
    pub token: String,
}

#[derive(Debug, juniper::GraphQLInputObject, AsChangeset)]
#[table_name = "users"]
pub struct UserUpdateInput {
    pub id: String,
    pub display_name: Option<String>,
    pub token: Option<String>,
}

#[derive(Queryable)]
struct UserData {
    id: String,
    display_name: String,
    #[allow(dead_code)]
    token: String,
}

pub struct User<'a> {
    #[allow(dead_code)]
    context: &'a ApiContext<'a>,
    data: UserData,
}

/// Wraps a String that identifies a user
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, GraphQLNewtype)]
pub struct UserId(pub String);

impl<'a> User<'a> {
    /// Find a user from his token
    pub fn by_token(context: &'a ApiContext, token: &str) -> FieldResult<Self> {
        Ok(Self {
            context,
            data: users::table
                .filter(users::dsl::token.eq(token))
                .first(&context.database)?,
        })
    }

    /// Find a user from his ID
    pub fn by_id(context: &'a ApiContext, user_id: UserId) -> FieldResult<Self> {
        Ok(Self {
            context,
            data: users::table.find(user_id.0).first(&context.database)?,
        })
    }

    /// List all users
    pub fn list(context: &'a ApiContext) -> FieldResult<Vec<Self>> {
        Ok(users::table
            .load(&context.database)?
            .into_iter()
            .map(|data| Self { context, data })
            .collect())
    }

    /// Insert a new user in the db
    pub fn insert<T: IntoIterator<Item = UserInput>>(
        context: &ApiContext,
        inputs: T,
    ) -> QueryResult<()> {
        for input in inputs.into_iter() {
            diesel::insert_into(users::table)
                .values(input)
                .execute(&context.database)?;
        }
        Ok(())
    }

    pub fn update<T: IntoIterator<Item = UserUpdateInput>>(
        context: &ApiContext,
        inputs: T,
    ) -> QueryResult<()> {
        for input in inputs.into_iter() {
            diesel::update(users::table)
                .filter(users::dsl::id.eq(&input.id))
                .set(&input)
                .execute(&context.database)?;
        }
        Ok(())
    }

    /// Delete a user from the db
    pub fn delete<T: IntoIterator<Item = String>>(context: &ApiContext, ids: T) -> QueryResult<()> {
        diesel::delete(users::table)
            .filter(users::dsl::id.eq_any(ids))
            .execute(&context.database)?;
        Ok(())
    }
}

#[graphql]
impl User<'_> {
    /// Id of the user
    pub fn id(&self) -> UserId {
        UserId(self.data.id.clone())
    }

    /// Display name of the user, i.e. the full name
    pub fn display_name(&self) -> &String {
        &self.data.display_name
    }

    pub fn contest_view(&self) -> FieldResult<ContestView> {
        ContestView::new(&self.context, Some(self.id()))
    }
}
<|endoftext|>