<commit_before>// rustfmt-normalize_comments: true
// Match expressions.

fn foo() {
    // A match expression.
    match x {
        // Some comment.
        a => foo(),
        b if 0 < 42 => foo(),
        c => {
            // Another comment.
            // Comment.
            an_expression;
            foo()
        }
        Foo(ref bar) => {
            aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
        }
        Pattern1 | Pattern2 | Pattern3 => false,
        Paternnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
        | Paternnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn => blah,
        Patternnnnnnnnnnnnnnnnnnn
        | Patternnnnnnnnnnnnnnnnnnn
        | Patternnnnnnnnnnnnnnnnnnn
        | Patternnnnnnnnnnnnnnnnnnn => meh,

        Patternnnnnnnnnnnnnnnnnnn | Patternnnnnnnnnnnnnnnnnnn if looooooooooooooooooong_guard => {
            meh
        }

        Patternnnnnnnnnnnnnnnnnnnnnnnnn | Patternnnnnnnnnnnnnnnnnnnnnnnnn
            if looooooooooooooooooooooooooooooooooooooooong_guard =>
        {
            meh
        }

        // Test that earlier patterns can take the guard space
        (aaaa, bbbbb, ccccccc, aaaaa, bbbbbbbb, cccccc, aaaa, bbbbbbbb, cccccc, dddddd)
        | Patternnnnnnnnnnnnnnnnnnnnnnnnn
            if loooooooooooooooooooooooooooooooooooooooooong_guard => {}

        _ => {}
        ast::PathParameters::AngleBracketedParameters(ref data)
            if data.lifetimes.len() > 0 || data.types.len() > 0 || data.bindings.len() > 0 => {}
    }

    let whatever = match something {
        /// DOC COMMENT!
        Some(_) => 42,
        // Comment on an attribute.
        #[an_attribute]
        // Comment after an attribute.
        None => 0,
        #[rustfmt_skip]
        Blurb     =>     {                  }
    };
}

// Test that a match on an overflow line is laid out properly.
fn main() {
    let sub_span =
        match xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx {
            Some(sub_span) => Some(sub_span),
            None => sub_span,
        };
}

// Test that one-line bodies align.
fn main() {
    match r {
        Variableeeeeeeeeeeeeeeeee => (
            "variable",
            vec!["id", "name", "qualname", "value", "type", "scopeid"],
            true,
            true,
        ),
        Enummmmmmmmmmmmmmmmmmmmm => (
            "enum",
            vec!["id", "qualname", "scopeid", "value"],
            true,
            true,
        ),
        Variantttttttttttttttttttttttt => (
            "variant",
            vec!["id", "name", "qualname", "type", "value", "scopeid"],
            true,
            true,
        ),
    };

    match x {
        y => { /*Block with comment. Preserve me.*/ }
        z => {
            stmt();
        }
    }
}

fn matches() {
    match 1 {
        -1 => 10,
        1 => 1, // foo
        2 => 2,
        // bar
        3 => 3,
        _ => 0, // baz
    }
}

fn match_skip() {
    let _ = match Some(1) {
        #[rustfmt_skip]
        Some( n ) => n,
        None => 1,
    };
}

fn issue339() {
    match a {
        b => {}
        c => {}
        d => {}
        e => {}
        // collapsing here is safe
        ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff => {}
        // collapsing here exceeds line length
        ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffg => {
        }
        h => {
            // comment above block
        }
        i => {} // comment below block
        j => {
            // comment inside block
        }
        j2 => {
            // comments inside...
        } // ... and after
        // TODO uncomment when vertical whitespace is handled better
        // k => {
        //
        //     // comment with WS above
        // }
        // l => {
        //     // comment with ws below
        //
        // }
        m => {}
        n => {}
        o => {}
        p => {
            // Dont collapse me
        }
        q => {}
        r => {}
        s => 0, // s comment
        // t comment
        t => 1,
        u => 2,
        v => {} /* funky block
                 * comment */
                /* final comment */
    }
}

fn issue355() {
    match mac {
        a => println!("a", b),
        b => vec![1, 2],
        c => vec![3; 4],
        d => println!("a", b),
        e => vec![1, 2],
        f => vec![3; 4],
        h => println!("a", b), // h comment
        i => vec![1, 2],       // i comment
        j => vec![3; 4],       // j comment
        // k comment
        k => println!("a", b),
        // l comment
        l => vec![1, 2],
        // m comment
        m => vec![3; 4],
        // Rewrite splits macro
        nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn => {
            println!("a", b)
        }
        // Rewrite splits macro
        oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo => {
            vec![1, 2]
        }
        // Macro support fails to recognise this macro as splittable
        // We push the whole expr to a new line, TODO split this macro as well
        pppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp => {
            vec![3; 4]
        }
        // q, r and s: Rewrite splits match arm
        qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq => {
            println!("a", b)
        }
        rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr => {
            vec![1, 2]
        }
        ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss => {
            vec![3; 4]
        }
        // Funky bracketing styles
        t => println!{"a", b},
        u => vec![1, 2],
        v => vec![3; 4],
        w => println!["a", b],
        x => vec![1, 2],
        y => vec![3; 4],
        // Brackets with comments
        tc => println!{"a", b}, // comment
        uc => vec![1, 2],       // comment
        vc => vec![3; 4],       // comment
        wc => println!["a", b], // comment
        xc => vec![1, 2],       // comment
        yc => vec![3; 4],       // comment
        yd => looooooooooooooooooooooooooooooooooooooooooooooooooooooooong_func(
            aaaaaaaaaa,
            bbbbbbbbbb,
            cccccccccc,
            dddddddddd,
        ),
    }
}

fn issue280() {
    {
        match x {
            CompressionMode::DiscardNewline | CompressionMode::CompressWhitespaceNewline => {
                ch == '\n'
            }
            ast::ItemConst(ref typ, ref expr) => {
                self.process_static_or_const_item(item, &typ, &expr)
            }
        }
    }
}

fn issue383() {
    match resolution.last_private {
        LastImport { .. } => false,
        _ => true,
    };
}

fn issue507() {
    match 1 {
        1 => unsafe { std::intrinsics::abort() },
        _ => (),
    }
}

fn issue508() {
    match s.type_id() {
        Some(
            NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLCanvasElement)),
        ) => true,
        Some(
            NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLObjectElement)),
        ) => s.has_object_data(),
        Some(NodeTypeId::Element(_)) => false,
    }
}

fn issue496() {
    {
        {
            {
                match def {
                    def::DefConst(def_id) | def::DefAssociatedConst(def_id) => {
                        match const_eval::lookup_const_by_id(cx.tcx, def_id, Some(self.pat.id)) {
                            Some(const_expr) => x,
                        }
                    }
                }
            }
        }
    }
}

fn issue494() {
    {
        match stmt.node {
            hir::StmtExpr(ref expr, id) | hir::StmtSemi(ref expr, id) => {
                result.push(StmtRef::Mirror(Box::new(Stmt {
                    span: stmt.span,
                    kind: StmtKind::Expr {
                        scope: cx.tcx.region_maps.node_extent(id),
                        expr: expr.to_ref(),
                    },
                })))
            }
        }
    }
}

fn issue386() {
    match foo {
        BiEq | BiLt | BiLe | BiNe | BiGt | BiGe => true,
        BiAnd
        | BiOr
        | BiAdd
        | BiSub
        | BiMul
        | BiDiv
        | BiRem
        | BiBitXor
        | BiBitAnd
        | BiBitOr
        | BiShl
        | BiShr => false,
    }
}

fn guards() {
    match foo {
        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
            if foooooooooooooo && barrrrrrrrrrrr => {}
        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
        | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
            if foooooooooooooo && barrrrrrrrrrrr => {}
        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
            if fooooooooooooooooooooo
                && (bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
                    || cccccccccccccccccccccccccccccccccccccccc) => {}
    }
}

fn issue1371() {
    Some(match type_ {
        sfEvtClosed => Closed,
        sfEvtResized => {
            let e = unsafe { *event.size.as_ref() };

            Resized {
                width: e.width,
                height: e.height,
            }
        }
        sfEvtLostFocus => LostFocus,
        sfEvtGainedFocus => GainedFocus,
        sfEvtTextEntered => TextEntered {
            unicode: unsafe {
                ::std::char::from_u32((*event.text.as_ref()).unicode)
                    .expect("Invalid unicode encountered on TextEntered event")
            },
        },
        sfEvtKeyPressed => {
            let e = unsafe { event.key.as_ref() };

            KeyPressed {
                code: unsafe { ::std::mem::transmute(e.code) },
                alt: e.alt.to_bool(),
                ctrl: e.control.to_bool(),
                shift: e.shift.to_bool(),
                system: e.system.to_bool(),
            }
        }
        sfEvtKeyReleased => {
            let e = unsafe { event.key.as_ref() };

            KeyReleased {
                code: unsafe { ::std::mem::transmute(e.code) },
                alt: e.alt.to_bool(),
                ctrl: e.control.to_bool(),
                shift: e.shift.to_bool(),
                system: e.system.to_bool(),
            }
        }
    })
}

fn issue1395() {
    let bar = Some(true);
    let foo = Some(true);
    let mut x = false;
    bar.and_then(|_| match foo {
        None => None,
        Some(b) => {
            x = true;
            Some(b)
        }
    });
}

fn issue1456() {
    Ok(Recording {
        artists: match reader.evaluate(".//mb:recording/mb:artist-credit/mb:name-credit")? {
            Nodeset(nodeset) => {
                let res: Result<Vec<ArtistRef>, ReadError> = nodeset
                    .iter()
                    .map(|node| {
                        XPathNodeReader::new(node, &context).and_then(|r| ArtistRef::from_xml(&r))
                    })
                    .collect();
                res?
            }
            _ => Vec::new(),
        },
    })
}

fn issue1460() {
    let _ = match foo {
        REORDER_BUFFER_CHANGE_INTERNAL_SPEC_INSERT => {
            "internal_spec_insert_internal_spec_insert_internal_spec_insert"
        }
        _ => "reorder_something",
    };
}

fn issue525() {
    foobar(
        f,
        "{}",
        match *self {
            TaskState::Started => "started",
            TaskState::Success => "success",
            TaskState::Failed => "failed",
        },
    );
}

// #1838, #1839
fn match_with_near_max_width() {
    let (this_line_uses_99_characters_and_is_formatted_properly, x012345) = match some_expression {
        _ => unimplemented!(),
    };

    let (should_be_formatted_like_the_line_above_using_100_characters, x0) = match some_expression {
        _ => unimplemented!(),
    };

    let (should_put_the_brace_on_the_next_line_using_101_characters, x0000) = match some_expression
    {
        _ => unimplemented!(),
    };
    match m {
        Variant::Tag
        | Variant::Tag2
        | Variant::Tag3
        | Variant::Tag4
        | Variant::Tag5
        | Variant::Tag6 => {}
    }
}

fn match_with_trailing_spaces() {
    match x {
        #![allow(simple_match)]
        Some(..) => 0,
        None => 1,
    }
}

fn issue_2099() {
    let a = match x {};
    let b = match x {};

    match x {}
}

// #2021
impl<'tcx> Const<'tcx> {
    pub fn from_constval<'a>() -> Const<'tcx> {
        let val = match *cv {
            ConstVal::Variant(_) | ConstVal::Aggregate(..) | ConstVal::Unevaluated(..) => bug!(
                "MIR must not use `{:?}` (aggregates are expanded to MIR rvalues)",
                cv
            ),
        };
    }
}

// #2151
fn issue_2151() {
    match either {
        x => {}
        y => (),
    }
}

// #2152
fn issue_2152() {
    match m {
        "aaaaaaaaaaaaa" | "bbbbbbbbbbbbb" | "cccccccccccccccccccccccccccccccccccccccccccc"
            if true => {}
        "bind" | "writev" | "readv" | "sendmsg" | "recvmsg" if android && (aarch64 || x86_64) => {
            true
        }
    }
}
<commit_msg>Update a test for #1807<commit_after>// rustfmt-normalize_comments: true
// Match expressions.

fn foo() {
    // A match expression.
    match x {
        // Some comment.
        a => foo(),
        b if 0 < 42 => foo(),
        c => {
            // Another comment.
            // Comment.
            an_expression;
            foo()
        }
        Foo(ref bar) => {
            aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
        }
        Pattern1 | Pattern2 | Pattern3 => false,
        Paternnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
        | Paternnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn => blah,
        Patternnnnnnnnnnnnnnnnnnn
        | Patternnnnnnnnnnnnnnnnnnn
        | Patternnnnnnnnnnnnnnnnnnn
        | Patternnnnnnnnnnnnnnnnnnn => meh,

        Patternnnnnnnnnnnnnnnnnnn | Patternnnnnnnnnnnnnnnnnnn if looooooooooooooooooong_guard => {
            meh
        }

        Patternnnnnnnnnnnnnnnnnnnnnnnnn | Patternnnnnnnnnnnnnnnnnnnnnnnnn
            if looooooooooooooooooooooooooooooooooooooooong_guard =>
        {
            meh
        }

        // Test that earlier patterns can take the guard space
        (aaaa, bbbbb, ccccccc, aaaaa, bbbbbbbb, cccccc, aaaa, bbbbbbbb, cccccc, dddddd)
        | Patternnnnnnnnnnnnnnnnnnnnnnnnn
            if loooooooooooooooooooooooooooooooooooooooooong_guard => {}

        _ => {}
        ast::PathParameters::AngleBracketedParameters(ref data)
            if data.lifetimes.len() > 0 || data.types.len() > 0 || data.bindings.len() > 0 => {}
    }

    let whatever = match something {
        /// DOC COMMENT!
        Some(_) => 42,
        // Comment on an attribute.
        #[an_attribute]
        // Comment after an attribute.
        None => 0,
        #[rustfmt_skip]
        Blurb     =>     {                  }
    };
}

// Test that a match on an overflow line is laid out properly.
fn main() {
    let sub_span =
        match xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx {
            Some(sub_span) => Some(sub_span),
            None => sub_span,
        };
}

// Test that one-line bodies align.
fn main() {
    match r {
        Variableeeeeeeeeeeeeeeeee => (
            "variable",
            vec!["id", "name", "qualname", "value", "type", "scopeid"],
            true,
            true,
        ),
        Enummmmmmmmmmmmmmmmmmmmm => (
            "enum",
            vec!["id", "qualname", "scopeid", "value"],
            true,
            true,
        ),
        Variantttttttttttttttttttttttt => (
            "variant",
            vec!["id", "name", "qualname", "type", "value", "scopeid"],
            true,
            true,
        ),
    };

    match x {
        y => { /*Block with comment. Preserve me.*/ }
        z => {
            stmt();
        }
    }
}

fn matches() {
    match 1 {
        -1 => 10,
        1 => 1, // foo
        2 => 2,
        // bar
        3 => 3,
        _ => 0, // baz
    }
}

fn match_skip() {
    let _ = match Some(1) {
        #[rustfmt_skip]
        Some( n ) => n,
        None => 1,
    };
}

fn issue339() {
    match a {
        b => {}
        c => {}
        d => {}
        e => {}
        // collapsing here is safe
        ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff => {}
        // collapsing here exceeds line length
        ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffg => {
        }
        h => {
            // comment above block
        }
        i => {} // comment below block
        j => {
            // comment inside block
        }
        j2 => {
            // comments inside...
        } // ... and after
        // TODO uncomment when vertical whitespace is handled better
        // k => {
        //
        //     // comment with WS above
        // }
        // l => {
        //     // comment with ws below
        //
        // }
        m => {}
        n => {}
        o => {}
        p => {
            // Dont collapse me
        }
        q => {}
        r => {}
        s => 0, // s comment
        // t comment
        t => 1,
        u => 2,
        v => {} /* funky block
                 * comment */
                /* final comment */
    }
}

fn issue355() {
    match mac {
        a => println!("a", b),
        b => vec![1, 2],
        c => vec![3; 4],
        d => println!("a", b),
        e => vec![1, 2],
        f => vec![3; 4],
        h => println!("a", b), // h comment
        i => vec![1, 2],       // i comment
        j => vec![3; 4],       // j comment
        // k comment
        k => println!("a", b),
        // l comment
        l => vec![1, 2],
        // m comment
        m => vec![3; 4],
        // Rewrite splits macro
        nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn => {
            println!("a", b)
        }
        // Rewrite splits macro
        oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo => {
            vec![1, 2]
        }
        // Macro support fails to recognise this macro as splittable
        // We push the whole expr to a new line, TODO split this macro as well
        pppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp => {
            vec![3; 4]
        }
        // q, r and s: Rewrite splits match arm
        qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq => {
            println!("a", b)
        }
        rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr => {
            vec![1, 2]
        }
        ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss => {
            vec![3; 4]
        }
        // Funky bracketing styles
        t => println!{"a", b},
        u => vec![1, 2],
        v => vec![3; 4],
        w => println!["a", b],
        x => vec![1, 2],
        y => vec![3; 4],
        // Brackets with comments
        tc => println!{"a", b}, // comment
        uc => vec![1, 2],       // comment
        vc => vec![3; 4],       // comment
        wc => println!["a", b], // comment
        xc => vec![1, 2],       // comment
        yc => vec![3; 4],       // comment
        yd => looooooooooooooooooooooooooooooooooooooooooooooooooooooooong_func(
            aaaaaaaaaa,
            bbbbbbbbbb,
            cccccccccc,
            dddddddddd,
        ),
    }
}

fn issue280() {
    {
        match x {
            CompressionMode::DiscardNewline | CompressionMode::CompressWhitespaceNewline => {
                ch == '\n'
            }
            ast::ItemConst(ref typ, ref expr) => {
                self.process_static_or_const_item(item, &typ, &expr)
            }
        }
    }
}

fn issue383() {
    match resolution.last_private {
        LastImport { .. } => false,
        _ => true,
    };
}

fn issue507() {
    match 1 {
        1 => unsafe { std::intrinsics::abort() },
        _ => (),
    }
}

fn issue508() {
    match s.type_id() {
        Some(
            NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLCanvasElement)),
        ) => true,
        Some(
            NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLObjectElement)),
        ) => s.has_object_data(),
        Some(NodeTypeId::Element(_)) => false,
    }
}

fn issue496() {
    {
        {
            {
                match def {
                    def::DefConst(def_id) | def::DefAssociatedConst(def_id) => {
                        match const_eval::lookup_const_by_id(cx.tcx, def_id, Some(self.pat.id)) {
                            Some(const_expr) => x,
                        }
                    }
                }
            }
        }
    }
}

fn issue494() {
    {
        match stmt.node {
            hir::StmtExpr(ref expr, id) | hir::StmtSemi(ref expr, id) => {
                result.push(StmtRef::Mirror(Box::new(Stmt {
                    span: stmt.span,
                    kind: StmtKind::Expr {
                        scope: cx.tcx.region_maps.node_extent(id),
                        expr: expr.to_ref(),
                    },
                })))
            }
        }
    }
}

fn issue386() {
    match foo {
        BiEq | BiLt | BiLe | BiNe | BiGt | BiGe => true,
        BiAnd | BiOr | BiAdd | BiSub | BiMul | BiDiv | BiRem | BiBitXor | BiBitAnd | BiBitOr
        | BiShl | BiShr => false,
    }
}

fn guards() {
    match foo {
        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
            if foooooooooooooo && barrrrrrrrrrrr => {}
        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
        | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
            if foooooooooooooo && barrrrrrrrrrrr => {}
        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
            if fooooooooooooooooooooo
                && (bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
                    || cccccccccccccccccccccccccccccccccccccccc) => {}
    }
}

fn issue1371() {
    Some(match type_ {
        sfEvtClosed => Closed,
        sfEvtResized => {
            let e = unsafe { *event.size.as_ref() };

            Resized {
                width: e.width,
                height: e.height,
            }
        }
        sfEvtLostFocus => LostFocus,
        sfEvtGainedFocus => GainedFocus,
        sfEvtTextEntered => TextEntered {
            unicode: unsafe {
                ::std::char::from_u32((*event.text.as_ref()).unicode)
                    .expect("Invalid unicode encountered on TextEntered event")
            },
        },
        sfEvtKeyPressed => {
            let e = unsafe { event.key.as_ref() };

            KeyPressed {
                code: unsafe { ::std::mem::transmute(e.code) },
                alt: e.alt.to_bool(),
                ctrl: e.control.to_bool(),
                shift: e.shift.to_bool(),
                system: e.system.to_bool(),
            }
        }
        sfEvtKeyReleased => {
            let e = unsafe { event.key.as_ref() };

            KeyReleased {
                code: unsafe { ::std::mem::transmute(e.code) },
                alt: e.alt.to_bool(),
                ctrl: e.control.to_bool(),
                shift: e.shift.to_bool(),
                system: e.system.to_bool(),
            }
        }
    })
}

fn issue1395() {
    let bar = Some(true);
    let foo = Some(true);
    let mut x = false;
    bar.and_then(|_| match foo {
        None => None,
        Some(b) => {
            x = true;
            Some(b)
        }
    });
}

fn issue1456() {
    Ok(Recording {
        artists: match reader.evaluate(".//mb:recording/mb:artist-credit/mb:name-credit")? {
            Nodeset(nodeset) => {
                let res: Result<Vec<ArtistRef>, ReadError> = nodeset
                    .iter()
                    .map(|node| {
                        XPathNodeReader::new(node, &context).and_then(|r| ArtistRef::from_xml(&r))
                    })
                    .collect();
                res?
            }
            _ => Vec::new(),
        },
    })
}

fn issue1460() {
    let _ = match foo {
        REORDER_BUFFER_CHANGE_INTERNAL_SPEC_INSERT => {
            "internal_spec_insert_internal_spec_insert_internal_spec_insert"
        }
        _ => "reorder_something",
    };
}

fn issue525() {
    foobar(
        f,
        "{}",
        match *self {
            TaskState::Started => "started",
            TaskState::Success => "success",
            TaskState::Failed => "failed",
        },
    );
}

// #1838, #1839
fn match_with_near_max_width() {
    let (this_line_uses_99_characters_and_is_formatted_properly, x012345) = match some_expression {
        _ => unimplemented!(),
    };

    let (should_be_formatted_like_the_line_above_using_100_characters, x0) = match some_expression {
        _ => unimplemented!(),
    };

    let (should_put_the_brace_on_the_next_line_using_101_characters, x0000) = match some_expression
    {
        _ => unimplemented!(),
    };
    match m {
        Variant::Tag
        | Variant::Tag2
        | Variant::Tag3
        | Variant::Tag4
        | Variant::Tag5
        | Variant::Tag6 => {}
    }
}

fn match_with_trailing_spaces() {
    match x {
        #![allow(simple_match)]
        Some(..) => 0,
        None => 1,
    }
}

fn issue_2099() {
    let a = match x {};
    let b = match x {};

    match x {}
}

// #2021
impl<'tcx> Const<'tcx> {
    pub fn from_constval<'a>() -> Const<'tcx> {
        let val = match *cv {
            ConstVal::Variant(_) | ConstVal::Aggregate(..) | ConstVal::Unevaluated(..) => bug!(
                "MIR must not use `{:?}` (aggregates are expanded to MIR rvalues)",
                cv
            ),
        };
    }
}

// #2151
fn issue_2151() {
    match either {
        x => {}
        y => (),
    }
}

// #2152
fn issue_2152() {
    match m {
        "aaaaaaaaaaaaa" | "bbbbbbbbbbbbb" | "cccccccccccccccccccccccccccccccccccccccccccc"
            if true => {}
        "bind" | "writev" | "readv" | "sendmsg" | "recvmsg" if android && (aarch64 || x86_64) => {
            true
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Data structures for commands of virtio video devices.

use std::io;

use data_model::{Le32, Le64};

use crate::virtio::video::command::QueueType;
use crate::virtio::video::control::*;
use crate::virtio::video::error::VideoError;
use crate::virtio::video::format::*;
use crate::virtio::video::params::Params;
use crate::virtio::video::protocol::*;
use crate::virtio::Writer;

pub trait Response {
    /// Writes an object to virtqueue.
    fn write(&self, w: &mut Writer) -> Result<(), io::Error>;
}

#[derive(Debug)]
pub enum CmdError {
    InvalidResourceId,
    InvalidStreamId,
    InvalidParameter,
    InvalidOperation,
}

/// A response to a `VideoCmd`. These correspond to `VIRTIO_VIDEO_RESP_*`.
#[derive(Debug)]
pub enum CmdResponse {
    NoData,
    QueryCapability(Vec<FormatDesc>),
    ResourceQueue {
        timestamp: u64,
        flags: u32,
        size: u32,
    },
    GetParams {
        queue_type: QueueType,
        params: Params,
    },
    QueryControl(QueryCtrlResponse),
    GetControl(CtrlVal),
    Error(CmdError),
}

impl From<VideoError> for CmdResponse {
    fn from(error: VideoError) -> Self {
        let cmd_error = match error {
            VideoError::InvalidResourceId { .. } => CmdError::InvalidResourceId,
            VideoError::InvalidStreamId(_) => CmdError::InvalidStreamId,
            VideoError::InvalidParameter => CmdError::InvalidParameter,
            _ => CmdError::InvalidOperation,
        };
        CmdResponse::Error(cmd_error)
    }
}

impl Response for CmdResponse {
    /// Writes a response to virtqueue.
    fn write(&self, w: &mut Writer) -> Result<(), io::Error> {
        use CmdResponse::*;

        let type_ = Le32::from(match self {
            NoData => VIRTIO_VIDEO_RESP_OK_NODATA,
            QueryCapability(_) => VIRTIO_VIDEO_RESP_OK_QUERY_CAPABILITY,
            ResourceQueue { .. } => VIRTIO_VIDEO_RESP_OK_RESOURCE_QUEUE,
            GetParams { .. } => VIRTIO_VIDEO_RESP_OK_GET_PARAMS,
            QueryControl(_) => VIRTIO_VIDEO_RESP_OK_QUERY_CONTROL,
            GetControl(_) => VIRTIO_VIDEO_RESP_OK_GET_CONTROL,
            Error(e) => {
                match e {
                    // TODO(b/1518105): Add more detailed error code when a new protocol supports
                    // them.
                    CmdError::InvalidResourceId => VIRTIO_VIDEO_RESP_ERR_INVALID_RESOURCE_ID,
                    CmdError::InvalidStreamId => VIRTIO_VIDEO_RESP_ERR_INVALID_STREAM_ID,
                    CmdError::InvalidParameter => VIRTIO_VIDEO_RESP_ERR_INVALID_PARAMETER,
                    CmdError::InvalidOperation => VIRTIO_VIDEO_RESP_ERR_INVALID_OPERATION,
                }
            }
        });

        let hdr = virtio_video_cmd_hdr {
            type_,
            ..Default::default()
        };

        match self {
            NoData | Error(_) => w.write_obj(hdr),
            QueryCapability(descs) => {
                w.write_obj(virtio_video_query_capability_resp {
                    hdr,
                    num_descs: Le32::from(descs.len() as u32),
                    ..Default::default()
                })?;
                descs.iter().map(|d| d.write(w)).collect()
            }
            ResourceQueue {
                timestamp,
                flags,
                size,
            } => w.write_obj(virtio_video_resource_queue_resp {
                hdr,
                timestamp: Le64::from(*timestamp),
                flags: Le32::from(*flags),
                size: Le32::from(*size),
            }),
            GetParams { queue_type, params } => {
                let params = params.to_virtio_video_params(*queue_type);
                w.write_obj(virtio_video_get_params_resp { hdr, params })
            }
            QueryControl(r) => {
                w.write_obj(virtio_video_query_control_resp { hdr })?;
                r.write(w)
            }
            GetControl(val) => {
                w.write_obj(virtio_video_get_control_resp { hdr })?;
                val.write(w)
            }
        }
    }
}
<commit_msg>devices: virtio: video: Add SetControl response enum<commit_after>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Data structures for commands of virtio video devices.

use std::io;

use data_model::{Le32, Le64};

use crate::virtio::video::command::QueueType;
use crate::virtio::video::control::*;
use crate::virtio::video::error::VideoError;
use crate::virtio::video::format::*;
use crate::virtio::video::params::Params;
use crate::virtio::video::protocol::*;
use crate::virtio::Writer;

pub trait Response {
    /// Writes an object to virtqueue.
    fn write(&self, w: &mut Writer) -> Result<(), io::Error>;
}

#[derive(Debug)]
pub enum CmdError {
    InvalidResourceId,
    InvalidStreamId,
    InvalidParameter,
    InvalidOperation,
}

/// A response to a `VideoCmd`. These correspond to `VIRTIO_VIDEO_RESP_*`.
#[derive(Debug)]
pub enum CmdResponse {
    NoData,
    QueryCapability(Vec<FormatDesc>),
    ResourceQueue {
        timestamp: u64,
        flags: u32,
        size: u32,
    },
    GetParams {
        queue_type: QueueType,
        params: Params,
    },
    QueryControl(QueryCtrlResponse),
    GetControl(CtrlVal),
    SetControl,
    Error(CmdError),
}

impl From<VideoError> for CmdResponse {
    fn from(error: VideoError) -> Self {
        let cmd_error = match error {
            VideoError::InvalidResourceId { .. } => CmdError::InvalidResourceId,
            VideoError::InvalidStreamId(_) => CmdError::InvalidStreamId,
            VideoError::InvalidParameter => CmdError::InvalidParameter,
            _ => CmdError::InvalidOperation,
        };
        CmdResponse::Error(cmd_error)
    }
}

impl Response for CmdResponse {
    /// Writes a response to virtqueue.
    fn write(&self, w: &mut Writer) -> Result<(), io::Error> {
        use CmdResponse::*;

        let type_ = Le32::from(match self {
            NoData => VIRTIO_VIDEO_RESP_OK_NODATA,
            QueryCapability(_) => VIRTIO_VIDEO_RESP_OK_QUERY_CAPABILITY,
            ResourceQueue { .. } => VIRTIO_VIDEO_RESP_OK_RESOURCE_QUEUE,
            GetParams { .. } => VIRTIO_VIDEO_RESP_OK_GET_PARAMS,
            QueryControl(_) => VIRTIO_VIDEO_RESP_OK_QUERY_CONTROL,
            GetControl(_) => VIRTIO_VIDEO_RESP_OK_GET_CONTROL,
            SetControl => VIRTIO_VIDEO_RESP_OK_NODATA,
            Error(e) => {
                match e {
                    // TODO(b/1518105): Add more detailed error code when a new protocol supports
                    // them.
                    CmdError::InvalidResourceId => VIRTIO_VIDEO_RESP_ERR_INVALID_RESOURCE_ID,
                    CmdError::InvalidStreamId => VIRTIO_VIDEO_RESP_ERR_INVALID_STREAM_ID,
                    CmdError::InvalidParameter => VIRTIO_VIDEO_RESP_ERR_INVALID_PARAMETER,
                    CmdError::InvalidOperation => VIRTIO_VIDEO_RESP_ERR_INVALID_OPERATION,
                }
            }
        });

        let hdr = virtio_video_cmd_hdr {
            type_,
            ..Default::default()
        };

        match self {
            NoData | Error(_) => w.write_obj(hdr),
            QueryCapability(descs) => {
                w.write_obj(virtio_video_query_capability_resp {
                    hdr,
                    num_descs: Le32::from(descs.len() as u32),
                    ..Default::default()
                })?;
                descs.iter().map(|d| d.write(w)).collect()
            }
            ResourceQueue {
                timestamp,
                flags,
                size,
            } => w.write_obj(virtio_video_resource_queue_resp {
                hdr,
                timestamp: Le64::from(*timestamp),
                flags: Le32::from(*flags),
                size: Le32::from(*size),
            }),
            GetParams { queue_type, params } => {
                let params = params.to_virtio_video_params(*queue_type);
                w.write_obj(virtio_video_get_params_resp { hdr, params })
            }
            QueryControl(r) => {
                w.write_obj(virtio_video_query_control_resp { hdr })?;
                r.write(w)
            }
            GetControl(val) => {
                w.write_obj(virtio_video_get_control_resp { hdr })?;
                val.write(w)
            }
            SetControl => w.write_obj(virtio_video_set_control_resp { hdr }),
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

use appkit::NSRect;

use libc::{c_double, c_long};
use libc;

pub type Class = libc::intptr_t;
pub type IMP = extern "C" fn(id, SEL) -> id;
pub type Ivar = libc::intptr_t;
pub type SEL = libc::intptr_t;
pub type id = libc::intptr_t;

pub static nil: id = 0 as id;

extern {
    pub fn class_addMethod(cls: Class, name: SEL, imp: IMP, types: *libc::c_char) -> bool;
    pub fn class_addIvar(cls: Class,
                         name: *libc::c_char,
                         size: libc::size_t,
                         alignment: u8,
		                 types: *libc::c_char)
                         -> bool;
    pub fn object_setInstanceVariable(obj: id, name: *libc::c_char, value: *libc::c_void);
    pub fn object_getInstanceVariable(obj: id, name: *libc::c_char, outValue: **libc::c_void);
    pub fn objc_allocateClassPair(superclass: Class, name: *libc::c_char, extraBytes: libc::size_t)
                                  -> Class;
    pub fn objc_getClass(name: *libc::c_char) -> id;
    pub fn objc_msgSend(theReceiver: id, theSelector: SEL) -> id;
    pub fn objc_registerClassPair(cls: Class);
    pub fn sel_registerName(name: *libc::c_char) -> SEL;
}

/// A convenience method to convert the name of a class to the class object itself.
#[inline]
pub fn class(name: &str) -> id {
    unsafe {
        name.to_c_str().with_ref(|c_string| objc_getClass(c_string))
    }
}

/// A convenience method to convert the name of a selector to the selector object.
#[inline]
pub fn selector(name: &str) -> SEL {
    unsafe {
        name.to_c_str().with_ref(|c_string| sel_registerName(c_string))
    }
}

/// A trait that allows syntax like:
///
///     let string = "NSString".send("alloc").send("initWithCString:", "Hello world!");
pub trait ObjCMethodCall {
    unsafe fn send<S:ObjCSelector,A:ObjCMethodArgs>(self, selector: S, args: A) -> id;
    unsafe fn send_double<S:ObjCSelector,A:ObjCMethodDoubleArgs>(self, selector: S, args: A)
                          -> c_double;
    unsafe fn send_long<S:ObjCSelector,A:ObjCMethodLongArgs>(self, selector: S, args: A) -> c_long;
    unsafe fn send_void<S:ObjCSelector,A:ObjCMethodVoidArgs>(self, selector: S, args: A);
}

impl ObjCMethodCall for id {
    unsafe fn send<S:ObjCSelector,A:ObjCMethodArgs>(self, selector: S, args: A) -> id {
        args.send_args(self, selector.as_selector())
    }
    unsafe fn send_double<S:ObjCSelector,A:ObjCMethodDoubleArgs>(self, selector: S, args: A)
                          -> c_double {
        args.send_double_args(self, selector.as_selector())
    }
    unsafe fn send_long<S:ObjCSelector,A:ObjCMethodLongArgs>(self, selector: S, args: A)
                        -> c_long {
        args.send_long_args(self, selector.as_selector())
    }
    unsafe fn send_void<S:ObjCSelector,A:ObjCMethodVoidArgs>(self, selector: S, args: A) {
        args.send_void_args(self, selector.as_selector())
    }
}

/// A convenience implementation that allows methods on class names to be called directly, as in:
///
///     "NSString".send("alloc")
impl<'a> ObjCMethodCall for &'a str {
    unsafe fn send<S:ObjCSelector,A:ObjCMethodArgs>(self, selector: S, args: A) -> id {
        args.send_args(class(self), selector.as_selector())
    }
    unsafe fn send_double<S:ObjCSelector,A:ObjCMethodDoubleArgs>(self, selector: S, args: A)
                          -> c_double {
        args.send_double_args(class(self), selector.as_selector())
    }
    unsafe fn send_long<S:ObjCSelector,A:ObjCMethodLongArgs>(self, selector: S, args: A)
                        -> c_long {
        args.send_long_args(class(self), selector.as_selector())
    }
    unsafe fn send_void<S:ObjCSelector,A:ObjCMethodVoidArgs>(self, selector: S, args: A) {
        args.send_void_args(class(self), selector.as_selector())
    }
}

/// A trait that allows C strings to be used as selectors without having to convert them first.
pub trait ObjCSelector {
    fn as_selector(self) -> SEL;
}

impl<'a> ObjCSelector for &'a str {
    #[inline]
    fn as_selector(self) -> SEL {
        // TODO(pcwalton): Cache somehow.
        unsafe {
            self.to_c_str().with_ref(|c_string| sel_registerName(c_string))
        }
    }
}

impl ObjCSelector for SEL {
    #[inline]
    fn as_selector(self) -> SEL {
        self
    }
}

/// Traits that simulate variadic parameters for convenience when sending messages.
trait ObjCMethodArgs {
    unsafe fn send_args(self, receiver: id, selector: SEL) -> id;
}
trait ObjCMethodDoubleArgs {
    unsafe fn send_double_args(self, receiver: id, selector: SEL) -> c_double;
}
trait ObjCMethodLongArgs {
    unsafe fn send_long_args(self, receiver: id, selector: SEL) -> c_long;
}
trait ObjCMethodVoidArgs {
    unsafe fn send_void_args(self, receiver: id, selector: SEL);
}

impl ObjCMethodArgs for () {
    #[inline]
    unsafe fn send_args(self, receiver: id, selector: SEL) -> id {
        invoke_msg_id(receiver, selector)
    }
}

impl ObjCMethodArgs for (id, id, id, id, id) {
    #[inline]
    unsafe fn send_args(self, receiver: id, selector: SEL) -> id {
        let (first, second, third, fourth, fifth) = self;
        invoke_msg_id_id_id_id_id_id(receiver, selector, first, second, third, fourth, fifth)
    }
}

impl ObjCMethodArgs for NSRect {
    #[inline]
    unsafe fn send_args(self, receiver: id, selector: SEL) -> id {
        invoke_msg_id_NSRect(receiver, selector, &self)
    }
}

impl ObjCMethodDoubleArgs for () {
    #[inline]
    unsafe fn send_double_args(self, receiver: id, selector: SEL) -> f64 {
        invoke_msg_double(receiver, selector)
    }
}

impl ObjCMethodLongArgs for () {
    #[inline]
    unsafe fn send_long_args(self, receiver: id, selector: SEL) -> c_long {
        invoke_msg_long(receiver, selector)
    }
}

impl ObjCMethodVoidArgs for () {
    #[inline]
    unsafe fn send_void_args(self, receiver: id, selector: SEL) {
        invoke_msg_void(receiver, selector)
    }
}

impl ObjCMethodVoidArgs for bool {
    #[inline]
    unsafe fn send_void_args(self, receiver: id, selector: SEL) {
        invoke_msg_void_bool(receiver, selector, self)
    }
}

impl ObjCMethodVoidArgs for id {
    #[inline]
    unsafe fn send_void_args(self, receiver: id, selector: SEL) {
        invoke_msg_void_id(receiver, selector, self)
    }
}

/// A trait that simulates variadic parameters for method calls.

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

    #[test]
    pub fn test_nsapp() {
        unsafe {
            let _nsApp = "NSApplication".send("sharedApplication", ());
        }
    }

    #[test]
    pub fn test_custom_obj() {
        extern fn MyObject_doSomething(this: id, _: SEL) -> id {
            println!("doSomething");
            return this;
        }

        let NSObject = class("NSObject");
        let MyObject = "MyObject".to_c_str().with_ref(|s| {
            unsafe {
                objc_allocateClassPair(NSObject, s, 0 as libc::size_t)
            }
        });
        unsafe {
            let doSomething = selector("doSomething");
            let _ = "@@:".to_c_str().with_ref(|types| {
                class_addMethod(MyObject, doSomething, MyObject_doSomething, types)
            });

            objc_registerClassPair(MyObject);

            let mut obj: id = MyObject.send("alloc", ());
            obj = obj.send("init", ());
            obj.send_void("doSomething", ());
        }
    }
}

#[link(name = "msgsend")]
extern {
    fn invoke_msg_double(theReceiver: id, theSelector: SEL) -> f64;
    fn invoke_msg_id(theReceiver: id, theSelector: SEL) -> id;
    fn invoke_msg_id_id_id_id_id_id(theReceiver: id,
                                    theSelector: SEL,
                                    a: id,
                                    b: id,
                                    c: id,
                                    d: id,
                                    e: id)
                                    -> id;
    fn invoke_msg_id_NSRect(theReceiver: id, theSelector: SEL, a: &NSRect) -> id;
    fn invoke_msg_long(theReceiver: id, theSelector: SEL) -> c_long;
    fn invoke_msg_void(theReceiver: id, theSelector: SEL);
    fn invoke_msg_void_bool(theReceiver: id, theSelector: SEL, a: bool);
    fn invoke_msg_void_id(theReceiver: id, theSelector: SEL, a: id);
}

<commit_msg>Fix tests for rust upgrade<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

use appkit::NSRect;

use libc::{c_double, c_long};
use libc;

pub type Class = libc::intptr_t;
pub type IMP = extern "C" fn(id, SEL) -> id;
pub type Ivar = libc::intptr_t;
pub type SEL = libc::intptr_t;
pub type id = libc::intptr_t;

pub static nil: id = 0 as id;

extern {
    pub fn class_addMethod(cls: Class, name: SEL, imp: IMP, types: *libc::c_char) -> bool;
    pub fn class_addIvar(cls: Class,
                         name: *libc::c_char,
                         size: libc::size_t,
                         alignment: u8,
		                 types: *libc::c_char)
                         -> bool;
    pub fn object_setInstanceVariable(obj: id, name: *libc::c_char, value: *libc::c_void);
    pub fn object_getInstanceVariable(obj: id, name: *libc::c_char, outValue: **libc::c_void);
    pub fn objc_allocateClassPair(superclass: Class, name: *libc::c_char, extraBytes: libc::size_t)
                                  -> Class;
    pub fn objc_getClass(name: *libc::c_char) -> id;
    pub fn objc_msgSend(theReceiver: id, theSelector: SEL) -> id;
    pub fn objc_registerClassPair(cls: Class);
    pub fn sel_registerName(name: *libc::c_char) -> SEL;
}

/// A convenience method to convert the name of a class to the class object itself.
#[inline]
pub fn class(name: &str) -> id {
    unsafe {
        name.to_c_str().with_ref(|c_string| objc_getClass(c_string))
    }
}

/// A convenience method to convert the name of a selector to the selector object.
#[inline]
pub fn selector(name: &str) -> SEL {
    unsafe {
        name.to_c_str().with_ref(|c_string| sel_registerName(c_string))
    }
}

/// A trait that allows syntax like:
///
///     let string = "NSString".send("alloc").send("initWithCString:", "Hello world!");
pub trait ObjCMethodCall {
    unsafe fn send<S:ObjCSelector,A:ObjCMethodArgs>(self, selector: S, args: A) -> id;
    unsafe fn send_double<S:ObjCSelector,A:ObjCMethodDoubleArgs>(self, selector: S, args: A)
                          -> c_double;
    unsafe fn send_long<S:ObjCSelector,A:ObjCMethodLongArgs>(self, selector: S, args: A) -> c_long;
    unsafe fn send_void<S:ObjCSelector,A:ObjCMethodVoidArgs>(self, selector: S, args: A);
}

impl ObjCMethodCall for id {
    unsafe fn send<S:ObjCSelector,A:ObjCMethodArgs>(self, selector: S, args: A) -> id {
        args.send_args(self, selector.as_selector())
    }
    unsafe fn send_double<S:ObjCSelector,A:ObjCMethodDoubleArgs>(self, selector: S, args: A)
                          -> c_double {
        args.send_double_args(self, selector.as_selector())
    }
    unsafe fn send_long<S:ObjCSelector,A:ObjCMethodLongArgs>(self, selector: S, args: A)
                        -> c_long {
        args.send_long_args(self, selector.as_selector())
    }
    unsafe fn send_void<S:ObjCSelector,A:ObjCMethodVoidArgs>(self, selector: S, args: A) {
        args.send_void_args(self, selector.as_selector())
    }
}

/// A convenience implementation that allows methods on class names to be called directly, as in:
///
///     "NSString".send("alloc")
impl<'a> ObjCMethodCall for &'a str {
    unsafe fn send<S:ObjCSelector,A:ObjCMethodArgs>(self, selector: S, args: A) -> id {
        args.send_args(class(self), selector.as_selector())
    }
    unsafe fn send_double<S:ObjCSelector,A:ObjCMethodDoubleArgs>(self, selector: S, args: A)
                          -> c_double {
        args.send_double_args(class(self), selector.as_selector())
    }
    unsafe fn send_long<S:ObjCSelector,A:ObjCMethodLongArgs>(self, selector: S, args: A)
                        -> c_long {
        args.send_long_args(class(self), selector.as_selector())
    }
    unsafe fn send_void<S:ObjCSelector,A:ObjCMethodVoidArgs>(self, selector: S, args: A) {
        args.send_void_args(class(self), selector.as_selector())
    }
}

/// A trait that allows C strings to be used as selectors without having to convert them first.
pub trait ObjCSelector {
    fn as_selector(self) -> SEL;
}

impl<'a> ObjCSelector for &'a str {
    #[inline]
    fn as_selector(self) -> SEL {
        // TODO(pcwalton): Cache somehow.
        unsafe {
            self.to_c_str().with_ref(|c_string| sel_registerName(c_string))
        }
    }
}

impl ObjCSelector for SEL {
    #[inline]
    fn as_selector(self) -> SEL {
        self
    }
}

/// Traits that simulate variadic parameters for convenience when sending messages.
trait ObjCMethodArgs {
    unsafe fn send_args(self, receiver: id, selector: SEL) -> id;
}
trait ObjCMethodDoubleArgs {
    unsafe fn send_double_args(self, receiver: id, selector: SEL) -> c_double;
}
trait ObjCMethodLongArgs {
    unsafe fn send_long_args(self, receiver: id, selector: SEL) -> c_long;
}
trait ObjCMethodVoidArgs {
    unsafe fn send_void_args(self, receiver: id, selector: SEL);
}

impl ObjCMethodArgs for () {
    #[inline]
    unsafe fn send_args(self, receiver: id, selector: SEL) -> id {
        invoke_msg_id(receiver, selector)
    }
}

impl ObjCMethodArgs for (id, id, id, id, id) {
    #[inline]
    unsafe fn send_args(self, receiver: id, selector: SEL) -> id {
        let (first, second, third, fourth, fifth) = self;
        invoke_msg_id_id_id_id_id_id(receiver, selector, first, second, third, fourth, fifth)
    }
}

impl ObjCMethodArgs for NSRect {
    #[inline]
    unsafe fn send_args(self, receiver: id, selector: SEL) -> id {
        invoke_msg_id_NSRect(receiver, selector, &self)
    }
}

impl ObjCMethodDoubleArgs for () {
    #[inline]
    unsafe fn send_double_args(self, receiver: id, selector: SEL) -> f64 {
        invoke_msg_double(receiver, selector)
    }
}

impl ObjCMethodLongArgs for () {
    #[inline]
    unsafe fn send_long_args(self, receiver: id, selector: SEL) -> c_long {
        invoke_msg_long(receiver, selector)
    }
}

impl ObjCMethodVoidArgs for () {
    #[inline]
    unsafe fn send_void_args(self, receiver: id, selector: SEL) {
        invoke_msg_void(receiver, selector)
    }
}

impl ObjCMethodVoidArgs for bool {
    #[inline]
    unsafe fn send_void_args(self, receiver: id, selector: SEL) {
        invoke_msg_void_bool(receiver, selector, self)
    }
}

impl ObjCMethodVoidArgs for id {
    #[inline]
    unsafe fn send_void_args(self, receiver: id, selector: SEL) {
        invoke_msg_void_id(receiver, selector, self)
    }
}

/// A trait that simulates variadic parameters for method calls.

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

    #[test]
    pub fn test_nsapp() {
        unsafe {
            let _nsApp = "NSApplication".send("sharedApplication", ());
        }
    }

    #[test]
    pub fn test_custom_obj() {
        extern fn MyObject_doSomething(this: id, _: SEL) -> id {
            println!("doSomething");
            return this;
        }

        let NSObject = class("NSObject");
        let MyObject = "MyObject".to_c_str().with_ref(|s| {
            unsafe {
                objc_allocateClassPair(NSObject, s, 0 as libc::size_t)
            }
        });
        unsafe {
            let doSomething = selector("doSomething");
            let _ = "@@:".to_c_str().with_ref(|types| {
                class_addMethod(MyObject, doSomething, MyObject_doSomething, types)
            });

            objc_registerClassPair(MyObject);

            let mut obj: id = MyObject.send("alloc", ());
            obj = obj.send("init", ());
            obj.send_void("doSomething", ());
        }
    }
}

#[link(name = "msgsend")]
extern {
    fn invoke_msg_double(theReceiver: id, theSelector: SEL) -> f64;
    fn invoke_msg_id(theReceiver: id, theSelector: SEL) -> id;
    fn invoke_msg_id_id_id_id_id_id(theReceiver: id,
                                    theSelector: SEL,
                                    a: id,
                                    b: id,
                                    c: id,
                                    d: id,
                                    e: id)
                                    -> id;
    fn invoke_msg_id_NSRect(theReceiver: id, theSelector: SEL, a: &NSRect) -> id;
    fn invoke_msg_long(theReceiver: id, theSelector: SEL) -> c_long;
    fn invoke_msg_void(theReceiver: id, theSelector: SEL);
    fn invoke_msg_void_bool(theReceiver: id, theSelector: SEL, a: bool);
    fn invoke_msg_void_id(theReceiver: id, theSelector: SEL, a: id);
}

<|endoftext|>


<commit_before>use crate::{logging, projects, pubsub::publish, telemetry, utils::schemas};
use defaults::Defaults;
use eyre::{bail, Result};
use once_cell::sync::Lazy;
use schemars::{gen::SchemaGenerator, schema::Schema, JsonSchema};
use serde::{Deserialize, Serialize};
use std::{env, fs, io::Write, path::PathBuf};
use tokio::sync::Mutex;
use validator::Validate;

/// Get the directory where configuration data is stored
pub fn dir(ensure: bool) -> Result<PathBuf> {
    let config_base = dirs_next::config_dir().unwrap_or_else(|| env::current_dir().unwrap());
    let dir = match env::consts::OS {
        "macos" => config_base.join("Stencila"),
        "windows" => config_base.join("Stencila").join("Config"),
        _ => config_base.join("stencila"),
    };
    if ensure {
        fs::create_dir_all(&dir)?;
    }
    Ok(dir)
}

#[derive(Debug, JsonSchema, Serialize)]
#[serde(rename_all = "lowercase")]
enum ConfigEventType {
    Set,
    Reset,
}

/// An event associated with changes to the configuration
#[derive(Debug, JsonSchema, Serialize)]
#[schemars(deny_unknown_fields)]
struct ConfigEvent {
    /// The type of event
    #[serde(rename = "type")]
    type_: ConfigEventType,

    /// The configuration at the time of the event
    #[schemars(schema_with = "ConfigEvent::schema_config")]
    config: Config,
}

impl ConfigEvent {
    /// Generate the JSON Schema for the `config` property to avoid nesting
    fn schema_config(_generator: &mut SchemaGenerator) -> Schema {
        schemas::typescript("Config", true)
    }

    /// Publish an event.
    pub fn publish(type_: ConfigEventType, config: &Config) {
        let event = ConfigEvent {
            type_,
            config: config.clone(),
        };
        publish("config", &event)
    }
}

#[derive(Debug, Default, PartialEq, Clone, JsonSchema, Deserialize, Serialize, Validate)]
#[serde(default)]
#[schemars(deny_unknown_fields)]
pub struct Config {
    #[validate]
    pub projects: projects::config::ProjectsConfig,

    #[validate]
    pub logging: logging::config::LoggingConfig,

    #[validate]
    pub telemetry: telemetry::config::TelemetryConfig,

    #[cfg(feature = "serve")]
    #[validate]
    pub serve: crate::serve::config::ServeConfig,

    #[cfg(feature = "plugins")]
    #[validate]
    pub plugins: crate::plugins::config::PluginsConfig,

    #[cfg(feature = "binaries")]
    #[validate]
    pub binaries: crate::binaries::config::BinariesConfig,

    pub editors: EditorsConfig,

    #[cfg(feature = "upgrade")]
    #[validate]
    pub upgrade: crate::upgrade::config::UpgradeConfig,
}

/// Editors
///
/// Configuration settings for document editors.
#[derive(Debug, Defaults, PartialEq, Clone, JsonSchema, Deserialize, Serialize)]
#[serde(default, rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct EditorsConfig {
    /// Default format for new documents
    #[def = "\"md\".to_string()"]
    pub default_format: String,

    /// Show line numbers
    #[def = "false"]
    pub line_numbers: bool,

    /// Enable wrapping of lines
    #[def = "true"]
    pub line_wrapping: bool,
}

impl Config {
    const CONFIG_FILE: &'static str = "config.toml";

    /// Get the path of the configuration file
    #[tracing::instrument]
    fn path() -> Result<PathBuf> {
        #[cfg(not(test))]
        return Ok(dir(true)?.join(Config::CONFIG_FILE));

        // When running tests, avoid messing with users existing config
        #[cfg(test)]
        {
            let path = std::env::temp_dir()
                .join("stencila")
                .join("test")
                .join(Config::CONFIG_FILE);
            fs::create_dir_all(path.parent().unwrap())?;
            Ok(path)
        }
    }

    /// Ensure that a string is a valid JSON pointer
    ///
    /// Replaces dots (`.`) with slashes (`/`) and ensures a
    /// leading slash.
    #[tracing::instrument]
    pub fn json_pointer(pointer: &str) -> String {
        let pointer = pointer.replace(".", "/");
        if pointer.starts_with('/') {
            pointer
        } else {
            format!("/{}", pointer)
        }
    }

    /// Read a config from the configuration file
    #[tracing::instrument]
    pub fn load() -> Result<Config> {
        let config_file = Config::path()?;

        let content = if config_file.exists() {
            match fs::read_to_string(config_file.clone()) {
                Ok(content) => content,
                // If there was a problem reading the config file warn the user
                // but return an empty string.
                Err(error) => {
                    tracing::warn!("Error while reading config file: {}", error.to_string());
                    String::new()
                }
            }
        } else {
            // If there is no config file just return an empty string
            String::new()
        };

        let config = match toml::from_str(content.as_str()) {
            Ok(config) => config,
            // If there was a problem reading the config file. e.g syntax error, a change
            // in the enum variants for an option, then warn the user and return the
            // defaults instead. This avoids a "corrupt" config file from preventing the
            // user from doing anything.
            Err(error) => {
                tracing::warn!(
                "Error while parsing config file; use `stencila config reset all` or edit {} to fix; defaults will be used: {}",
                config_file.display(),
                error.to_string()
            );
                Config {
                    ..Default::default()
                }
            }
        };

        if let Err(errors) = config.validate() {
            tracing::error!(
                "Invalid config file; use `stencila config set`, `stencila config reset` or edit {} to fix.\n\n{}",
                config_file.display(),
                serde_json::to_string_pretty(&errors)?
            )
        }

        Ok(config)
    }

    /// Write a config to the configuration file
    #[tracing::instrument]
    pub fn write(&self) -> Result<()> {
        self.validate()?;

        let config_file = Config::path()?;
        let mut file = fs::File::create(config_file)?;
        file.write_all(toml::to_string(&self)?.as_bytes())?;
        Ok(())
    }

    /// Get a config property
    #[tracing::instrument]
    pub fn get(&self, pointer: Option<String>) -> Result<serde_json::Value> {
        match pointer {
            None => Ok(serde_json::to_value(self)?),
            Some(pointer) => {
                let config = serde_json::to_value(self)?;
                if let Some(part) = config.pointer(Config::json_pointer(&pointer).as_str()) {
                    let json = serde_json::to_string(part)?;
                    let part: toml::Value = serde_json::from_str(&json)?;
                    Ok(serde_json::to_value(part)?)
                } else {
                    bail!("No configuration value at pointer: {}", pointer)
                }
            }
        }
    }

    /// Set a property and write to disk
    #[tracing::instrument]
    pub fn set(&mut self, pointer: &str, value: &str) -> Result<()> {
        // Serialize self to a JSON value and set property
        let mut config = serde_json::to_value(&self)?;
        if let Some(property) = config.pointer_mut(Config::json_pointer(pointer).as_str()) {
            let value = match serde_json::from_str(value) {
                Ok(value) => value,
                Err(_) => serde_json::Value::String(value.into()),
            };
            *property = value;
        } else {
            bail!("No configuration value at pointer: {}", pointer)
        };

        // Now deserialize self from the JSON value
        *self = serde_json::from_value(config)?;

        ConfigEvent::publish(ConfigEventType::Set, self);
        self.write()
    }

    /// Reset one, or all, properties and write to disk
    #[tracing::instrument]
    pub fn reset(&mut self, property: &str) -> Result<()> {
        match property {
            "all" => *self = Config::default(),

            "logging" => self.logging = crate::logging::config::LoggingConfig::default(),

            #[cfg(feature = "plugins")]
            "plugins" => self.plugins = crate::plugins::config::PluginsConfig::default(),

            #[cfg(feature = "serve")]
            "serve" => self.serve = crate::serve::config::ServeConfig::default(),

            #[cfg(feature = "upgrade")]
            "upgrade" => self.upgrade = crate::upgrade::config::UpgradeConfig::default(),

            _ => bail!("No top level configuration property named: {}", property),
        }

        ConfigEvent::publish(ConfigEventType::Reset, self);
        self.write()
    }
}

/// A global config store
///
/// Previously, we loaded config on startup and then passed them to various
/// functions in other modules.
/// However, this proved complicated for things like `Project` and `Document`
/// file watching threads when they need access to the current config.
pub static CONFIG: Lazy<Mutex<Config>> =
    Lazy::new(|| Mutex::new(Config::load().expect("Unable to read config")));

/// Get the JSON Schema for the configuration
pub fn schemas() -> Result<serde_json::Value> {
    let schemas = serde_json::Value::Array(vec![
        schemas::generate::<Config>()?,
        schemas::generate::<ConfigEvent>()?,
    ]);
    Ok(schemas)
}

/// CLI options for the `config` command
#[cfg(feature = "cli")]
pub mod cli {
    use super::*;
    use crate::cli::display;
    use structopt::StructOpt;

    #[derive(Debug, StructOpt)]
    #[structopt(
        about = "Manage configuration settings",
        setting = structopt::clap::AppSettings::ColoredHelp,
        setting = structopt::clap::AppSettings::VersionlessSubcommands
    )]
    pub struct Command {
        #[structopt(subcommand)]
        pub action: Action,
    }

    #[derive(Debug, StructOpt)]
    #[structopt(
        setting = structopt::clap::AppSettings::DeriveDisplayOrder
    )]
    pub enum Action {
        Get(Get),
        Set(Set),
        Reset(Reset),

        #[structopt(
            about = "Get the directories used for config, cache etc",
            setting = structopt::clap::AppSettings::ColoredHelp
        )]
        Dirs,

        #[structopt(
            about = "Get JSON Schemas for configuration and associated types",
            setting = structopt::clap::AppSettings::ColoredHelp
        )]
        Schemas,
    }

    #[derive(Debug, StructOpt)]
    #[structopt(
        about = "Get configuration properties",
        setting = structopt::clap::AppSettings::ColoredHelp
    )]
    pub struct Get {
        /// A pointer to a config property e.g. `upgrade.auto`
        pub pointer: Option<String>,
    }

    #[derive(Debug, StructOpt)]
    #[structopt(
        about = "Set configuration properties",
        setting = structopt::clap::AppSettings::ColoredHelp
    )]
    pub struct Set {
        /// A pointer to a config property e.g. `upgrade.auto`
        pub pointer: String,

        /// The value to set the property to
        pub value: String,
    }

    #[derive(Debug, StructOpt)]
    #[structopt(
        about = "Reset configuration properties to their defaults",
        setting = structopt::clap::AppSettings::ColoredHelp
    )]
    pub struct Reset {
        /// The config property to reset. Use 'all' to reset the entire config.
        pub property: String,
    }

    pub async fn run(args: Command) -> display::Result {
        let Command { action } = args;

        let config = &mut *CONFIG.lock().await;

        match action {
            Action::Get(action) => {
                let Get { pointer } = action;
                let value = config.get(pointer)?;
                display::value(value)
            }
            Action::Set(action) => {
                let Set { pointer, value } = action;
                config.set(&pointer, &value)?;
                display::nothing()
            }
            Action::Reset(action) => {
                let Reset { property } = action;
                config.reset(&property)?;
                display::nothing()
            }
            Action::Dirs => {
                let config_dir = dir(false)?.display().to_string();
                let logs_dir = crate::logging::config::dir(false)?.display().to_string();
                let plugins_dir = crate::plugins::plugins_dir(false)?.display().to_string();
                let binaries_dir = crate::binaries::binaries_dir().display().to_string();
                let value = serde_json::json!({
                    "config": config_dir,
                    "logs": logs_dir,
                    "plugins": plugins_dir,
                    "binaries": binaries_dir
                });
                display::value(value)
            }
            Action::Schemas => {
                let value = schemas()?;
                display::value(value)
            }
        }
    }
}

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

    #[test]
    fn test_path() -> Result<()> {
        let path = Config::path()?;
        assert!(path.starts_with(std::env::temp_dir()));
        Ok(())
    }

    #[test]
    fn test_json_pointer() {
        assert_eq!(Config::json_pointer("a"), "/a");
        assert_eq!(Config::json_pointer("a/b"), "/a/b");
        assert_eq!(Config::json_pointer("/a.b"), "/a/b");
        assert_eq!(Config::json_pointer("a.b.c"), "/a/b/c");
    }

    #[test]
    fn test_display() -> Result<()> {
        let config = Config {
            ..Default::default()
        };

        serde_json::from_value::<Config>(config.get(None)?)?;

        assert_eq!(
            config
                .get(Some("foo.bar".to_string()))
                .unwrap_err()
                .to_string(),
            "No configuration value at pointer: foo.bar"
        );

        Ok(())
    }

    #[cfg(feature = "upgrade")]
    #[test]
    fn test_set() -> Result<()> {
        let mut config = Config {
            ..Default::default()
        };

        config.set("upgrade.auto", "off")?;
        assert_eq!(config.upgrade.auto, "off");

        config.set("upgrade.verbose", "true")?;
        assert_eq!(config.upgrade.verbose, true);

        assert_eq!(
            config.set("foo.bar", "baz").unwrap_err().to_string(),
            "No configuration value at pointer: foo.bar"
        );

        Ok(())
    }

    #[cfg(feature = "upgrade")]
    #[test]
    fn test_reset() -> Result<()> {
        let mut config: Config = serde_json::from_value(serde_json::json!({
            "upgrade": {
                "auto": "off",
                "verbose": true,
                "confirm": true,
            }
        }))?;

        let default = Config {
            ..Default::default()
        };

        config.reset("upgrade")?;
        assert_eq!(config.upgrade.auto, default.upgrade.auto);
        assert_eq!(config.upgrade.verbose, default.upgrade.verbose);

        config.reset("all")?;
        assert_eq!(config, default);

        assert_eq!(
            config.reset("foo").unwrap_err().to_string(),
            "No top level configuration property named: foo"
        );

        Ok(())
    }

    #[cfg(feature = "cli")]
    #[tokio::test]
    async fn test_cli() -> Result<()> {
        use super::cli::*;

        run(Command {
            action: Action::Get(Get { pointer: None }),
        })
        .await?;

        run(Command {
            action: Action::Set(Set {
                pointer: "upgrade.confirm".to_string(),
                value: "true".to_string(),
            }),
        })
        .await?;

        run(Command {
            action: Action::Reset(Reset {
                property: "upgrade".to_string(),
            }),
        })
        .await?;

        run(Command {
            action: Action::Dirs,
        })
        .await?;

        Ok(())
    }
}
<commit_msg>fix(Config): Remove unecessary validate attributes<commit_after>use crate::{logging, projects, pubsub::publish, telemetry, utils::schemas};
use defaults::Defaults;
use eyre::{bail, Result};
use once_cell::sync::Lazy;
use schemars::{gen::SchemaGenerator, schema::Schema, JsonSchema};
use serde::{Deserialize, Serialize};
use std::{env, fs, io::Write, path::PathBuf};
use tokio::sync::Mutex;
use validator::Validate;

/// Get the directory where configuration data is stored
pub fn dir(ensure: bool) -> Result<PathBuf> {
    let config_base = dirs_next::config_dir().unwrap_or_else(|| env::current_dir().unwrap());
    let dir = match env::consts::OS {
        "macos" => config_base.join("Stencila"),
        "windows" => config_base.join("Stencila").join("Config"),
        _ => config_base.join("stencila"),
    };
    if ensure {
        fs::create_dir_all(&dir)?;
    }
    Ok(dir)
}

#[derive(Debug, JsonSchema, Serialize)]
#[serde(rename_all = "lowercase")]
enum ConfigEventType {
    Set,
    Reset,
}

/// An event associated with changes to the configuration
#[derive(Debug, JsonSchema, Serialize)]
#[schemars(deny_unknown_fields)]
struct ConfigEvent {
    /// The type of event
    #[serde(rename = "type")]
    type_: ConfigEventType,

    /// The configuration at the time of the event
    #[schemars(schema_with = "ConfigEvent::schema_config")]
    config: Config,
}

impl ConfigEvent {
    /// Generate the JSON Schema for the `config` property to avoid nesting
    fn schema_config(_generator: &mut SchemaGenerator) -> Schema {
        schemas::typescript("Config", true)
    }

    /// Publish an event.
    pub fn publish(type_: ConfigEventType, config: &Config) {
        let event = ConfigEvent {
            type_,
            config: config.clone(),
        };
        publish("config", &event)
    }
}

#[derive(Debug, Default, PartialEq, Clone, JsonSchema, Deserialize, Serialize, Validate)]
#[serde(default)]
#[schemars(deny_unknown_fields)]
pub struct Config {
    pub projects: projects::config::ProjectsConfig,

    pub logging: logging::config::LoggingConfig,

    pub telemetry: telemetry::config::TelemetryConfig,

    #[cfg(feature = "serve")]
    pub serve: crate::serve::config::ServeConfig,

    #[cfg(feature = "plugins")]
    pub plugins: crate::plugins::config::PluginsConfig,

    #[cfg(feature = "binaries")]
    pub binaries: crate::binaries::config::BinariesConfig,

    pub editors: EditorsConfig,

    #[cfg(feature = "upgrade")]
    pub upgrade: crate::upgrade::config::UpgradeConfig,
}

/// Editors
///
/// Configuration settings for document editors.
#[derive(Debug, Defaults, PartialEq, Clone, JsonSchema, Deserialize, Serialize)]
#[serde(default, rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct EditorsConfig {
    /// Default format for new documents
    #[def = "\"md\".to_string()"]
    pub default_format: String,

    /// Show line numbers
    #[def = "false"]
    pub line_numbers: bool,

    /// Enable wrapping of lines
    #[def = "true"]
    pub line_wrapping: bool,
}

impl Config {
    const CONFIG_FILE: &'static str = "config.toml";

    /// Get the path of the configuration file
    #[tracing::instrument]
    fn path() -> Result<PathBuf> {
        #[cfg(not(test))]
        return Ok(dir(true)?.join(Config::CONFIG_FILE));

        // When running tests, avoid messing with users existing config
        #[cfg(test)]
        {
            let path = std::env::temp_dir()
                .join("stencila")
                .join("test")
                .join(Config::CONFIG_FILE);
            fs::create_dir_all(path.parent().unwrap())?;
            Ok(path)
        }
    }

    /// Ensure that a string is a valid JSON pointer
    ///
    /// Replaces dots (`.`) with slashes (`/`) and ensures a
    /// leading slash.
    #[tracing::instrument]
    pub fn json_pointer(pointer: &str) -> String {
        let pointer = pointer.replace(".", "/");
        if pointer.starts_with('/') {
            pointer
        } else {
            format!("/{}", pointer)
        }
    }

    /// Read a config from the configuration file
    #[tracing::instrument]
    pub fn load() -> Result<Config> {
        let config_file = Config::path()?;

        let content = if config_file.exists() {
            match fs::read_to_string(config_file.clone()) {
                Ok(content) => content,
                // If there was a problem reading the config file warn the user
                // but return an empty string.
                Err(error) => {
                    tracing::warn!("Error while reading config file: {}", error.to_string());
                    String::new()
                }
            }
        } else {
            // If there is no config file just return an empty string
            String::new()
        };

        let config = match toml::from_str(content.as_str()) {
            Ok(config) => config,
            // If there was a problem reading the config file. e.g syntax error, a change
            // in the enum variants for an option, then warn the user and return the
            // defaults instead. This avoids a "corrupt" config file from preventing the
            // user from doing anything.
            Err(error) => {
                tracing::warn!(
                "Error while parsing config file; use `stencila config reset all` or edit {} to fix; defaults will be used: {}",
                config_file.display(),
                error.to_string()
            );
                Config {
                    ..Default::default()
                }
            }
        };

        if let Err(errors) = config.validate() {
            tracing::error!(
                "Invalid config file; use `stencila config set`, `stencila config reset` or edit {} to fix.\n\n{}",
                config_file.display(),
                serde_json::to_string_pretty(&errors)?
            )
        }

        Ok(config)
    }

    /// Write a config to the configuration file
    #[tracing::instrument]
    pub fn write(&self) -> Result<()> {
        self.validate()?;

        let config_file = Config::path()?;
        let mut file = fs::File::create(config_file)?;
        file.write_all(toml::to_string(&self)?.as_bytes())?;
        Ok(())
    }

    /// Get a config property
    #[tracing::instrument]
    pub fn get(&self, pointer: Option<String>) -> Result<serde_json::Value> {
        match pointer {
            None => Ok(serde_json::to_value(self)?),
            Some(pointer) => {
                let config = serde_json::to_value(self)?;
                if let Some(part) = config.pointer(Config::json_pointer(&pointer).as_str()) {
                    let json = serde_json::to_string(part)?;
                    let part: toml::Value = serde_json::from_str(&json)?;
                    Ok(serde_json::to_value(part)?)
                } else {
                    bail!("No configuration value at pointer: {}", pointer)
                }
            }
        }
    }

    /// Set a property and write to disk
    #[tracing::instrument]
    pub fn set(&mut self, pointer: &str, value: &str) -> Result<()> {
        // Serialize self to a JSON value and set property
        let mut config = serde_json::to_value(&self)?;
        if let Some(property) = config.pointer_mut(Config::json_pointer(pointer).as_str()) {
            let value = match serde_json::from_str(value) {
                Ok(value) => value,
                Err(_) => serde_json::Value::String(value.into()),
            };
            *property = value;
        } else {
            bail!("No configuration value at pointer: {}", pointer)
        };

        // Now deserialize self from the JSON value
        *self = serde_json::from_value(config)?;

        ConfigEvent::publish(ConfigEventType::Set, self);
        self.write()
    }

    /// Reset one, or all, properties and write to disk
    #[tracing::instrument]
    pub fn reset(&mut self, property: &str) -> Result<()> {
        match property {
            "all" => *self = Config::default(),

            "logging" => self.logging = crate::logging::config::LoggingConfig::default(),

            #[cfg(feature = "plugins")]
            "plugins" => self.plugins = crate::plugins::config::PluginsConfig::default(),

            #[cfg(feature = "serve")]
            "serve" => self.serve = crate::serve::config::ServeConfig::default(),

            #[cfg(feature = "upgrade")]
            "upgrade" => self.upgrade = crate::upgrade::config::UpgradeConfig::default(),

            _ => bail!("No top level configuration property named: {}", property),
        }

        ConfigEvent::publish(ConfigEventType::Reset, self);
        self.write()
    }
}

/// A global config store
///
/// Previously, we loaded config on startup and then passed them to various
/// functions in other modules.
/// However, this proved complicated for things like `Project` and `Document`
/// file watching threads when they need access to the current config.
pub static CONFIG: Lazy<Mutex<Config>> =
    Lazy::new(|| Mutex::new(Config::load().expect("Unable to read config")));

/// Get the JSON Schema for the configuration
pub fn schemas() -> Result<serde_json::Value> {
    let schemas = serde_json::Value::Array(vec![
        schemas::generate::<Config>()?,
        schemas::generate::<ConfigEvent>()?,
    ]);
    Ok(schemas)
}

/// CLI options for the `config` command
#[cfg(feature = "cli")]
pub mod cli {
    use super::*;
    use crate::cli::display;
    use structopt::StructOpt;

    #[derive(Debug, StructOpt)]
    #[structopt(
        about = "Manage configuration settings",
        setting = structopt::clap::AppSettings::ColoredHelp,
        setting = structopt::clap::AppSettings::VersionlessSubcommands
    )]
    pub struct Command {
        #[structopt(subcommand)]
        pub action: Action,
    }

    #[derive(Debug, StructOpt)]
    #[structopt(
        setting = structopt::clap::AppSettings::DeriveDisplayOrder
    )]
    pub enum Action {
        Get(Get),
        Set(Set),
        Reset(Reset),

        #[structopt(
            about = "Get the directories used for config, cache etc",
            setting = structopt::clap::AppSettings::ColoredHelp
        )]
        Dirs,

        #[structopt(
            about = "Get JSON Schemas for configuration and associated types",
            setting = structopt::clap::AppSettings::ColoredHelp
        )]
        Schemas,
    }

    #[derive(Debug, StructOpt)]
    #[structopt(
        about = "Get configuration properties",
        setting = structopt::clap::AppSettings::ColoredHelp
    )]
    pub struct Get {
        /// A pointer to a config property e.g. `upgrade.auto`
        pub pointer: Option<String>,
    }

    #[derive(Debug, StructOpt)]
    #[structopt(
        about = "Set configuration properties",
        setting = structopt::clap::AppSettings::ColoredHelp
    )]
    pub struct Set {
        /// A pointer to a config property e.g. `upgrade.auto`
        pub pointer: String,

        /// The value to set the property to
        pub value: String,
    }

    #[derive(Debug, StructOpt)]
    #[structopt(
        about = "Reset configuration properties to their defaults",
        setting = structopt::clap::AppSettings::ColoredHelp
    )]
    pub struct Reset {
        /// The config property to reset. Use 'all' to reset the entire config.
        pub property: String,
    }

    pub async fn run(args: Command) -> display::Result {
        let Command { action } = args;

        let config = &mut *CONFIG.lock().await;

        match action {
            Action::Get(action) => {
                let Get { pointer } = action;
                let value = config.get(pointer)?;
                display::value(value)
            }
            Action::Set(action) => {
                let Set { pointer, value } = action;
                config.set(&pointer, &value)?;
                display::nothing()
            }
            Action::Reset(action) => {
                let Reset { property } = action;
                config.reset(&property)?;
                display::nothing()
            }
            Action::Dirs => {
                let config_dir = dir(false)?.display().to_string();
                let logs_dir = crate::logging::config::dir(false)?.display().to_string();
                let plugins_dir = crate::plugins::plugins_dir(false)?.display().to_string();
                let binaries_dir = crate::binaries::binaries_dir().display().to_string();
                let value = serde_json::json!({
                    "config": config_dir,
                    "logs": logs_dir,
                    "plugins": plugins_dir,
                    "binaries": binaries_dir
                });
                display::value(value)
            }
            Action::Schemas => {
                let value = schemas()?;
                display::value(value)
            }
        }
    }
}

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

    #[test]
    fn test_path() -> Result<()> {
        let path = Config::path()?;
        assert!(path.starts_with(std::env::temp_dir()));
        Ok(())
    }

    #[test]
    fn test_json_pointer() {
        assert_eq!(Config::json_pointer("a"), "/a");
        assert_eq!(Config::json_pointer("a/b"), "/a/b");
        assert_eq!(Config::json_pointer("/a.b"), "/a/b");
        assert_eq!(Config::json_pointer("a.b.c"), "/a/b/c");
    }

    #[test]
    fn test_display() -> Result<()> {
        let config = Config {
            ..Default::default()
        };

        serde_json::from_value::<Config>(config.get(None)?)?;

        assert_eq!(
            config
                .get(Some("foo.bar".to_string()))
                .unwrap_err()
                .to_string(),
            "No configuration value at pointer: foo.bar"
        );

        Ok(())
    }

    #[cfg(feature = "upgrade")]
    #[test]
    fn test_set() -> Result<()> {
        let mut config = Config {
            ..Default::default()
        };

        config.set("upgrade.auto", "off")?;
        assert_eq!(config.upgrade.auto, "off");

        config.set("upgrade.verbose", "true")?;
        assert_eq!(config.upgrade.verbose, true);

        assert_eq!(
            config.set("foo.bar", "baz").unwrap_err().to_string(),
            "No configuration value at pointer: foo.bar"
        );

        Ok(())
    }

    #[cfg(feature = "upgrade")]
    #[test]
    fn test_reset() -> Result<()> {
        let mut config: Config = serde_json::from_value(serde_json::json!({
            "upgrade": {
                "auto": "off",
                "verbose": true,
                "confirm": true,
            }
        }))?;

        let default = Config {
            ..Default::default()
        };

        config.reset("upgrade")?;
        assert_eq!(config.upgrade.auto, default.upgrade.auto);
        assert_eq!(config.upgrade.verbose, default.upgrade.verbose);

        config.reset("all")?;
        assert_eq!(config, default);

        assert_eq!(
            config.reset("foo").unwrap_err().to_string(),
            "No top level configuration property named: foo"
        );

        Ok(())
    }

    #[cfg(feature = "cli")]
    #[tokio::test]
    async fn test_cli() -> Result<()> {
        use super::cli::*;

        run(Command {
            action: Action::Get(Get { pointer: None }),
        })
        .await?;

        run(Command {
            action: Action::Set(Set {
                pointer: "upgrade.confirm".to_string(),
                value: "true".to_string(),
            }),
        })
        .await?;

        run(Command {
            action: Action::Reset(Reset {
                property: "upgrade".to_string(),
            }),
        })
        .await?;

        run(Command {
            action: Action::Dirs,
        })
        .await?;

        Ok(())
    }
}
<|endoftext|>


<commit_before>use stack::Stack;

/// Represents a builtin function
#[derive(Debug, Clone, PartialEq)]
pub enum Builtin {
    Dot,
    Plus,
    Minus,
    Star,
    Slash,
    Abs,
    And,
    Or,
    Xor,
    Equals,
    LessThan,
    GreaterThan,
    LessEqual,
    GreaterEqual,
    Emit,
    Dup,
    Swap,
    Over,
    Rot,
    Tuck,
    Drop,
}

impl Builtin {
    pub fn call(&self, stack: &mut Stack) {
        /// Allows defining Builtin using closure-like syntax
        macro_rules! stackexpr {
            ( | $($aname:ident : $atype:ty),+ | $value:expr ) => {
                {
                    $(
                        let $aname: $atype = stack.pop();
                    )+
                    stack.push($value)
                }
            }
        }

        use self::Builtin::*;
        match *self {
            Dot => print!("{}", stack.pop::<i32>()),
            Plus => stackexpr!(|n2: i32, n1: i32| n1 + n2),
            Minus => stackexpr!(|n2: i32, n1: i32| n1 - n2),
            Star => stackexpr!(|n2: i32, n1: i32| n1 * n2),
            Slash => stackexpr!(|n2: i32, n1: i32| n1 / n2),
            Abs => stackexpr!(|n: i32| n.abs()),
            And => stackexpr!(|n2: i32, n1: i32| n1 & n2),
            Or => stackexpr!(|n2: i32, n1: i32| n1 | n2),
            Xor => stackexpr!(|n2: i32, n1: i32| n1 ^ n2),
            Equals => stackexpr!(|n2: i32, n1: i32| n1 == n2),
            LessThan => stackexpr!(|n2: i32, n1: i32| n1 < n2),
            GreaterThan => stackexpr!(|n2: i32, n1: i32| n1 > n2),
            LessEqual => stackexpr!(|n2: i32, n1: i32| n1 <= n2),
            GreaterEqual => stackexpr!(|n2: i32, n1: i32| n1 >= n2),
            Emit => print!("{}", stack.pop::<char>()),
            Dup => {
                let n: i32 = stack.peak();
                stack.push(n);
            }
            Swap => {
                let n2: i32 = stack.pop();
                let n1: i32 = stack.pop();
                stack.push(n2);
                stack.push(n1);
            }
            Over => {
                let n2: i32 = stack.pop();
                let n1: i32 = stack.pop();
                stack.push(n1);
                stack.push(n2);
                stack.push(n1);
            }
            Rot => {
                let n3: i32 = stack.pop();
                let n2: i32 = stack.pop();
                let n1: i32 = stack.pop();
                stack.push(n1);
                stack.push(n3);
                stack.push(n2);
            }
            Tuck => {
                let n2: i32 = stack.pop();
                let n1: i32 = stack.pop();
                stack.push(n2);
                stack.push(n1);
                stack.push(n2);
            }
            Drop => {
                stack.pop::<i32>();
            }
        }
    }
}
<commit_msg>Update comment<commit_after>use stack::Stack;

/// Represents a builtin function
#[derive(Debug, Clone, PartialEq)]
pub enum Builtin {
    Dot,
    Plus,
    Minus,
    Star,
    Slash,
    Abs,
    And,
    Or,
    Xor,
    Equals,
    LessThan,
    GreaterThan,
    LessEqual,
    GreaterEqual,
    Emit,
    Dup,
    Swap,
    Over,
    Rot,
    Tuck,
    Drop,
}

impl Builtin {
    pub fn call(&self, stack: &mut Stack) {
        /// Allows defining a builtin using closure-like syntax. Note that the
        /// arguments are in reverse order, as that is how the stack is laid out.
        macro_rules! stackexpr {
            ( | $($aname:ident : $atype:ty),+ | $value:expr ) => {
                {
                    $(
                        let $aname: $atype = stack.pop();
                    )+
                    stack.push($value)
                }
            }
        }

        use self::Builtin::*;
        match *self {
            Dot => print!("{}", stack.pop::<i32>()),
            Plus => stackexpr!(|n2: i32, n1: i32| n1 + n2),
            Minus => stackexpr!(|n2: i32, n1: i32| n1 - n2),
            Star => stackexpr!(|n2: i32, n1: i32| n1 * n2),
            Slash => stackexpr!(|n2: i32, n1: i32| n1 / n2),
            Abs => stackexpr!(|n: i32| n.abs()),
            And => stackexpr!(|n2: i32, n1: i32| n1 & n2),
            Or => stackexpr!(|n2: i32, n1: i32| n1 | n2),
            Xor => stackexpr!(|n2: i32, n1: i32| n1 ^ n2),
            Equals => stackexpr!(|n2: i32, n1: i32| n1 == n2),
            LessThan => stackexpr!(|n2: i32, n1: i32| n1 < n2),
            GreaterThan => stackexpr!(|n2: i32, n1: i32| n1 > n2),
            LessEqual => stackexpr!(|n2: i32, n1: i32| n1 <= n2),
            GreaterEqual => stackexpr!(|n2: i32, n1: i32| n1 >= n2),
            Emit => print!("{}", stack.pop::<char>()),
            Dup => {
                let n: i32 = stack.peak();
                stack.push(n);
            }
            Swap => {
                let n2: i32 = stack.pop();
                let n1: i32 = stack.pop();
                stack.push(n2);
                stack.push(n1);
            }
            Over => {
                let n2: i32 = stack.pop();
                let n1: i32 = stack.pop();
                stack.push(n1);
                stack.push(n2);
                stack.push(n1);
            }
            Rot => {
                let n3: i32 = stack.pop();
                let n2: i32 = stack.pop();
                let n1: i32 = stack.pop();
                stack.push(n1);
                stack.push(n3);
                stack.push(n2);
            }
            Tuck => {
                let n2: i32 = stack.pop();
                let n1: i32 = stack.pop();
                stack.push(n2);
                stack.push(n1);
                stack.push(n2);
            }
            Drop => {
                stack.pop::<i32>();
            }
        }
    }
}
<|endoftext|>