<commit_before>use crate::attr;
use crate::ast;
use crate::parse::{SeqSep, PResult};
use crate::parse::token::{self, Nonterminal, DelimToken};
use crate::parse::parser::{Parser, TokenType, PathStyle};
use crate::tokenstream::{TokenStream, TokenTree};
use crate::source_map::Span;

use log::debug;
use smallvec::smallvec;

#[derive(Debug)]
enum InnerAttributeParsePolicy<'a> {
    Permitted,
    NotPermitted { reason: &'a str, prev_attr_sp: Option<Span> },
}

const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \
                                                     permitted in this context";

impl<'a> Parser<'a> {
    crate fn parse_arg_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
        let attrs = self.parse_outer_attributes()?;
        attrs.iter().for_each(|a|
            self.sess.param_attr_spans.borrow_mut().push(a.span)
        );
        Ok(attrs)
    }

    /// Parse attributes that appear before an item
    crate fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
        let mut attrs: Vec<ast::Attribute> = Vec::new();
        let mut just_parsed_doc_comment = false;
        loop {
            debug!("parse_outer_attributes: self.token={:?}", self.token);
            match self.token.kind {
                token::Pound => {
                    let inner_error_reason = if just_parsed_doc_comment {
                        "an inner attribute is not permitted following an outer doc comment"
                    } else if !attrs.is_empty() {
                        "an inner attribute is not permitted following an outer attribute"
                    } else {
                        DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
                    };
                    let inner_parse_policy =
                        InnerAttributeParsePolicy::NotPermitted { reason: inner_error_reason,
                            prev_attr_sp: attrs.last().and_then(|a| Some(a.span)) };
                    let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?;
                    attrs.push(attr);
                    just_parsed_doc_comment = false;
                }
                token::DocComment(s) => {
                    let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, self.token.span);
                    if attr.style != ast::AttrStyle::Outer {
                        let mut err = self.fatal("expected outer doc comment");
                        err.note("inner doc comments like this (starting with \
                                  `//!` or `/*!`) can only appear before items");
                        return Err(err);
                    }
                    attrs.push(attr);
                    self.bump();
                    just_parsed_doc_comment = true;
                }
                _ => break,
            }
        }
        Ok(attrs)
    }

    /// Matches `attribute = # ! [ meta_item ]`
    ///
    /// If permit_inner is true, then a leading `!` indicates an inner
    /// attribute
    pub fn parse_attribute(&mut self, permit_inner: bool) -> PResult<'a, ast::Attribute> {
        debug!("parse_attribute: permit_inner={:?} self.token={:?}",
               permit_inner,
               self.token);
        let inner_parse_policy = if permit_inner {
            InnerAttributeParsePolicy::Permitted
        } else {
            InnerAttributeParsePolicy::NotPermitted
                { reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG, prev_attr_sp: None }
        };
        self.parse_attribute_with_inner_parse_policy(inner_parse_policy)
    }

    /// The same as `parse_attribute`, except it takes in an `InnerAttributeParsePolicy`
    /// that prescribes how to handle inner attributes.
    fn parse_attribute_with_inner_parse_policy(&mut self,
                                               inner_parse_policy: InnerAttributeParsePolicy<'_>)
                                               -> PResult<'a, ast::Attribute> {
        debug!("parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}",
               inner_parse_policy,
               self.token);
        let (span, path, tokens, style) = match self.token.kind {
            token::Pound => {
                let lo = self.token.span;
                self.bump();

                if let InnerAttributeParsePolicy::Permitted = inner_parse_policy {
                    self.expected_tokens.push(TokenType::Token(token::Not));
                }

                let style = if self.token == token::Not {
                    self.bump();
                    ast::AttrStyle::Inner
                } else {
                    ast::AttrStyle::Outer
                };

                self.expect(&token::OpenDelim(token::Bracket))?;
                let (path, tokens) = self.parse_meta_item_unrestricted()?;
                self.expect(&token::CloseDelim(token::Bracket))?;
                let hi = self.prev_span;

                let attr_sp = lo.to(hi);

                // Emit error if inner attribute is encountered and not permitted
                if style == ast::AttrStyle::Inner {
                    if let InnerAttributeParsePolicy::NotPermitted { reason, prev_attr_sp }
                            = inner_parse_policy {
                        let mut diagnostic = self
                            .diagnostic()
                            .struct_span_err(attr_sp, reason);

                        if let Some(prev_attr_sp) = prev_attr_sp {
                            diagnostic
                                .span_label(attr_sp, "not permitted following an outer attibute")
                                .span_label(prev_attr_sp, "previous outer attribute");
                        }

                        diagnostic
                            .note("inner attributes, like `#![no_std]`, annotate the item \
                                   enclosing them, and are usually found at the beginning of \
                                   source files. Outer attributes, like `#[test]`, annotate the \
                                   item following them.")
                            .emit()
                    }
                }

                (attr_sp, path, tokens, style)
            }
            _ => {
                let token_str = self.this_token_to_string();
                return Err(self.fatal(&format!("expected `#`, found `{}`", token_str)));
            }
        };

        Ok(ast::Attribute {
            id: attr::mk_attr_id(),
            style,
            path,
            tokens,
            is_sugared_doc: false,
            span,
        })
    }

    /// Parse an inner part of attribute - path and following tokens.
    /// The tokens must be either a delimited token stream, or empty token stream,
    /// or the "legacy" key-value form.
    /// PATH `(` TOKEN_STREAM `)`
    /// PATH `[` TOKEN_STREAM `]`
    /// PATH `{` TOKEN_STREAM `}`
    /// PATH
    /// PATH `=` TOKEN_TREE
    /// The delimiters or `=` are still put into the resulting token stream.
    crate fn parse_meta_item_unrestricted(&mut self) -> PResult<'a, (ast::Path, TokenStream)> {
        let meta = match self.token.kind {
            token::Interpolated(ref nt) => match **nt {
                Nonterminal::NtMeta(ref meta) => Some(meta.clone()),
                _ => None,
            },
            _ => None,
        };
        Ok(if let Some(meta) = meta {
            self.bump();
            (meta.path, meta.node.tokens(meta.span))
        } else {
            let path = self.parse_path(PathStyle::Mod)?;
            let tokens = if self.check(&token::OpenDelim(DelimToken::Paren)) ||
               self.check(&token::OpenDelim(DelimToken::Bracket)) ||
               self.check(&token::OpenDelim(DelimToken::Brace)) {
                   self.parse_token_tree().into()
            } else if self.eat(&token::Eq) {
                let eq = TokenTree::token(token::Eq, self.prev_span);
                let mut is_interpolated_expr = false;
                if let token::Interpolated(nt) = &self.token.kind {
                    if let token::NtExpr(..) = **nt {
                        is_interpolated_expr = true;
                    }
                }
                let tokens = if is_interpolated_expr {
                    // We need to accept arbitrary interpolated expressions to continue
                    // supporting things like `doc = $expr` that work on stable.
                    // Non-literal interpolated expressions are rejected after expansion.
                    self.parse_token_tree().into()
                } else {
                    self.parse_unsuffixed_lit()?.tokens()
                };
                TokenStream::from_streams(smallvec![eq.into(), tokens])
            } else {
                TokenStream::empty()
            };
            (path, tokens)
        })
    }

    /// Parse attributes that appear after the opening of an item. These should
    /// be preceded by an exclamation mark, but we accept and warn about one
    /// terminated by a semicolon.

    /// matches inner_attrs*
    crate fn parse_inner_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
        let mut attrs: Vec<ast::Attribute> = vec![];
        loop {
            match self.token.kind {
                token::Pound => {
                    // Don't even try to parse if it's not an inner attribute.
                    if !self.look_ahead(1, |t| t == &token::Not) {
                        break;
                    }

                    let attr = self.parse_attribute(true)?;
                    assert_eq!(attr.style, ast::AttrStyle::Inner);
                    attrs.push(attr);
                }
                token::DocComment(s) => {
                    // we need to get the position of this token before we bump.
                    let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, self.token.span);
                    if attr.style == ast::AttrStyle::Inner {
                        attrs.push(attr);
                        self.bump();
                    } else {
                        break;
                    }
                }
                _ => break,
            }
        }
        Ok(attrs)
    }

    fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> {
        let lit = self.parse_lit()?;
        debug!("checking if {:?} is unusuffixed", lit);

        if !lit.node.is_unsuffixed() {
            let msg = "suffixed literals are not allowed in attributes";
            self.diagnostic().struct_span_err(lit.span, msg)
                             .help("instead of using a suffixed literal \
                                    (1u8, 1.0f32, etc.), use an unsuffixed version \
                                    (1, 1.0, etc.).")
                             .emit()
        }

        Ok(lit)
    }

    /// Per RFC#1559, matches the following grammar:
    ///
    /// meta_item : IDENT ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
    /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ;
    pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
        let nt_meta = match self.token.kind {
            token::Interpolated(ref nt) => match **nt {
                token::NtMeta(ref e) => Some(e.clone()),
                _ => None,
            },
            _ => None,
        };

        if let Some(meta) = nt_meta {
            self.bump();
            return Ok(meta);
        }

        let lo = self.token.span;
        let path = self.parse_path(PathStyle::Mod)?;
        let node = self.parse_meta_item_kind()?;
        let span = lo.to(self.prev_span);
        Ok(ast::MetaItem { path, node, span })
    }

    crate fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> {
        Ok(if self.eat(&token::Eq) {
            ast::MetaItemKind::NameValue(self.parse_unsuffixed_lit()?)
        } else if self.eat(&token::OpenDelim(token::Paren)) {
            ast::MetaItemKind::List(self.parse_meta_seq()?)
        } else {
            ast::MetaItemKind::Word
        })
    }

    /// matches meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;
    fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
        match self.parse_unsuffixed_lit() {
            Ok(lit) => {
                return Ok(ast::NestedMetaItem::Literal(lit))
            }
            Err(ref mut err) => self.diagnostic().cancel(err)
        }

        match self.parse_meta_item() {
            Ok(mi) => {
                return Ok(ast::NestedMetaItem::MetaItem(mi))
            }
            Err(ref mut err) => self.diagnostic().cancel(err)
        }

        let found = self.this_token_to_string();
        let msg = format!("expected unsuffixed literal or identifier, found `{}`", found);
        Err(self.diagnostic().struct_span_err(self.token.span, &msg))
    }

    /// matches meta_seq = ( COMMASEP(meta_item_inner) )
    fn parse_meta_seq(&mut self) -> PResult<'a, Vec<ast::NestedMetaItem>> {
        self.parse_seq_to_end(&token::CloseDelim(token::Paren),
                              SeqSep::trailing_allowed(token::Comma),
                              |p: &mut Parser<'a>| p.parse_meta_item_inner())
    }
}
<commit_msg>Treat doc comments separately<commit_after>use crate::attr;
use crate::ast;
use crate::parse::{SeqSep, PResult};
use crate::parse::token::{self, Nonterminal, DelimToken};
use crate::parse::parser::{Parser, TokenType, PathStyle};
use crate::tokenstream::{TokenStream, TokenTree};
use crate::source_map::Span;

use log::debug;
use smallvec::smallvec;

#[derive(Debug)]
enum InnerAttributeParsePolicy<'a> {
    Permitted,
    NotPermitted { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option<Span> },
}

const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \
                                                     permitted in this context";

impl<'a> Parser<'a> {
    crate fn parse_arg_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
        let attrs = self.parse_outer_attributes()?;
        attrs.iter().for_each(|a|
            self.sess.param_attr_spans.borrow_mut().push(a.span)
        );
        Ok(attrs)
    }

    /// Parse attributes that appear before an item
    crate fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
        let mut attrs: Vec<ast::Attribute> = Vec::new();
        let mut just_parsed_doc_comment = false;
        loop {
            debug!("parse_outer_attributes: self.token={:?}", self.token);
            match self.token.kind {
                token::Pound => {
                    let inner_error_reason = if just_parsed_doc_comment {
                        "an inner attribute is not permitted following an outer doc comment"
                    } else if !attrs.is_empty() {
                        "an inner attribute is not permitted following an outer attribute"
                    } else {
                        DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
                    };
                    let inner_parse_policy =
                        InnerAttributeParsePolicy::NotPermitted {
                            reason: inner_error_reason,
                            saw_doc_comment: just_parsed_doc_comment,
                            prev_attr_sp: attrs.last().and_then(|a| Some(a.span))
                        };
                    let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?;
                    attrs.push(attr);
                    just_parsed_doc_comment = false;
                }
                token::DocComment(s) => {
                    let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, self.token.span);
                    if attr.style != ast::AttrStyle::Outer {
                        let mut err = self.fatal("expected outer doc comment");
                        err.note("inner doc comments like this (starting with \
                                  `//!` or `/*!`) can only appear before items");
                        return Err(err);
                    }
                    attrs.push(attr);
                    self.bump();
                    just_parsed_doc_comment = true;
                }
                _ => break,
            }
        }
        Ok(attrs)
    }

    /// Matches `attribute = # ! [ meta_item ]`
    ///
    /// If permit_inner is true, then a leading `!` indicates an inner
    /// attribute
    pub fn parse_attribute(&mut self, permit_inner: bool) -> PResult<'a, ast::Attribute> {
        debug!("parse_attribute: permit_inner={:?} self.token={:?}",
               permit_inner,
               self.token);
        let inner_parse_policy = if permit_inner {
            InnerAttributeParsePolicy::Permitted
        } else {
            InnerAttributeParsePolicy::NotPermitted {
                reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG,
                saw_doc_comment: false,
                prev_attr_sp: None
            }
        };
        self.parse_attribute_with_inner_parse_policy(inner_parse_policy)
    }

    /// The same as `parse_attribute`, except it takes in an `InnerAttributeParsePolicy`
    /// that prescribes how to handle inner attributes.
    fn parse_attribute_with_inner_parse_policy(&mut self,
                                               inner_parse_policy: InnerAttributeParsePolicy<'_>)
                                               -> PResult<'a, ast::Attribute> {
        debug!("parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}",
               inner_parse_policy,
               self.token);
        let (span, path, tokens, style) = match self.token.kind {
            token::Pound => {
                let lo = self.token.span;
                self.bump();

                if let InnerAttributeParsePolicy::Permitted = inner_parse_policy {
                    self.expected_tokens.push(TokenType::Token(token::Not));
                }

                let style = if self.token == token::Not {
                    self.bump();
                    ast::AttrStyle::Inner
                } else {
                    ast::AttrStyle::Outer
                };

                self.expect(&token::OpenDelim(token::Bracket))?;
                let (path, tokens) = self.parse_meta_item_unrestricted()?;
                self.expect(&token::CloseDelim(token::Bracket))?;
                let hi = self.prev_span;

                let attr_sp = lo.to(hi);

                // Emit error if inner attribute is encountered and not permitted
                if style == ast::AttrStyle::Inner {
                    if let InnerAttributeParsePolicy::NotPermitted { reason,
                        saw_doc_comment, prev_attr_sp } = inner_parse_policy {
                        let prev_attr_note = if saw_doc_comment {
                            "previous doc comment"
                        } else {
                            "previous outer attribute"
                        };

                        let mut diagnostic = self
                            .diagnostic()
                            .struct_span_err(attr_sp, reason);

                        if let Some(prev_attr_sp) = prev_attr_sp {
                            diagnostic
                                .span_label(attr_sp, "not permitted following an outer attibute")
                                .span_label(prev_attr_sp, prev_attr_note);
                        }

                        diagnostic
                            .note("inner attributes, like `#![no_std]`, annotate the item \
                                   enclosing them, and are usually found at the beginning of \
                                   source files. Outer attributes, like `#[test]`, annotate the \
                                   item following them.")
                            .emit()
                    }
                }

                (attr_sp, path, tokens, style)
            }
            _ => {
                let token_str = self.this_token_to_string();
                return Err(self.fatal(&format!("expected `#`, found `{}`", token_str)));
            }
        };

        Ok(ast::Attribute {
            id: attr::mk_attr_id(),
            style,
            path,
            tokens,
            is_sugared_doc: false,
            span,
        })
    }

    /// Parse an inner part of attribute - path and following tokens.
    /// The tokens must be either a delimited token stream, or empty token stream,
    /// or the "legacy" key-value form.
    /// PATH `(` TOKEN_STREAM `)`
    /// PATH `[` TOKEN_STREAM `]`
    /// PATH `{` TOKEN_STREAM `}`
    /// PATH
    /// PATH `=` TOKEN_TREE
    /// The delimiters or `=` are still put into the resulting token stream.
    crate fn parse_meta_item_unrestricted(&mut self) -> PResult<'a, (ast::Path, TokenStream)> {
        let meta = match self.token.kind {
            token::Interpolated(ref nt) => match **nt {
                Nonterminal::NtMeta(ref meta) => Some(meta.clone()),
                _ => None,
            },
            _ => None,
        };
        Ok(if let Some(meta) = meta {
            self.bump();
            (meta.path, meta.node.tokens(meta.span))
        } else {
            let path = self.parse_path(PathStyle::Mod)?;
            let tokens = if self.check(&token::OpenDelim(DelimToken::Paren)) ||
               self.check(&token::OpenDelim(DelimToken::Bracket)) ||
               self.check(&token::OpenDelim(DelimToken::Brace)) {
                   self.parse_token_tree().into()
            } else if self.eat(&token::Eq) {
                let eq = TokenTree::token(token::Eq, self.prev_span);
                let mut is_interpolated_expr = false;
                if let token::Interpolated(nt) = &self.token.kind {
                    if let token::NtExpr(..) = **nt {
                        is_interpolated_expr = true;
                    }
                }
                let tokens = if is_interpolated_expr {
                    // We need to accept arbitrary interpolated expressions to continue
                    // supporting things like `doc = $expr` that work on stable.
                    // Non-literal interpolated expressions are rejected after expansion.
                    self.parse_token_tree().into()
                } else {
                    self.parse_unsuffixed_lit()?.tokens()
                };
                TokenStream::from_streams(smallvec![eq.into(), tokens])
            } else {
                TokenStream::empty()
            };
            (path, tokens)
        })
    }

    /// Parse attributes that appear after the opening of an item. These should
    /// be preceded by an exclamation mark, but we accept and warn about one
    /// terminated by a semicolon.

    /// matches inner_attrs*
    crate fn parse_inner_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
        let mut attrs: Vec<ast::Attribute> = vec![];
        loop {
            match self.token.kind {
                token::Pound => {
                    // Don't even try to parse if it's not an inner attribute.
                    if !self.look_ahead(1, |t| t == &token::Not) {
                        break;
                    }

                    let attr = self.parse_attribute(true)?;
                    assert_eq!(attr.style, ast::AttrStyle::Inner);
                    attrs.push(attr);
                }
                token::DocComment(s) => {
                    // we need to get the position of this token before we bump.
                    let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, self.token.span);
                    if attr.style == ast::AttrStyle::Inner {
                        attrs.push(attr);
                        self.bump();
                    } else {
                        break;
                    }
                }
                _ => break,
            }
        }
        Ok(attrs)
    }

    fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> {
        let lit = self.parse_lit()?;
        debug!("checking if {:?} is unusuffixed", lit);

        if !lit.node.is_unsuffixed() {
            let msg = "suffixed literals are not allowed in attributes";
            self.diagnostic().struct_span_err(lit.span, msg)
                             .help("instead of using a suffixed literal \
                                    (1u8, 1.0f32, etc.), use an unsuffixed version \
                                    (1, 1.0, etc.).")
                             .emit()
        }

        Ok(lit)
    }

    /// Per RFC#1559, matches the following grammar:
    ///
    /// meta_item : IDENT ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
    /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ;
    pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
        let nt_meta = match self.token.kind {
            token::Interpolated(ref nt) => match **nt {
                token::NtMeta(ref e) => Some(e.clone()),
                _ => None,
            },
            _ => None,
        };

        if let Some(meta) = nt_meta {
            self.bump();
            return Ok(meta);
        }

        let lo = self.token.span;
        let path = self.parse_path(PathStyle::Mod)?;
        let node = self.parse_meta_item_kind()?;
        let span = lo.to(self.prev_span);
        Ok(ast::MetaItem { path, node, span })
    }

    crate fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> {
        Ok(if self.eat(&token::Eq) {
            ast::MetaItemKind::NameValue(self.parse_unsuffixed_lit()?)
        } else if self.eat(&token::OpenDelim(token::Paren)) {
            ast::MetaItemKind::List(self.parse_meta_seq()?)
        } else {
            ast::MetaItemKind::Word
        })
    }

    /// matches meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;
    fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
        match self.parse_unsuffixed_lit() {
            Ok(lit) => {
                return Ok(ast::NestedMetaItem::Literal(lit))
            }
            Err(ref mut err) => self.diagnostic().cancel(err)
        }

        match self.parse_meta_item() {
            Ok(mi) => {
                return Ok(ast::NestedMetaItem::MetaItem(mi))
            }
            Err(ref mut err) => self.diagnostic().cancel(err)
        }

        let found = self.this_token_to_string();
        let msg = format!("expected unsuffixed literal or identifier, found `{}`", found);
        Err(self.diagnostic().struct_span_err(self.token.span, &msg))
    }

    /// matches meta_seq = ( COMMASEP(meta_item_inner) )
    fn parse_meta_seq(&mut self) -> PResult<'a, Vec<ast::NestedMetaItem>> {
        self.parse_seq_to_end(&token::CloseDelim(token::Paren),
                              SeqSep::trailing_allowed(token::Comma),
                              |p: &mut Parser<'a>| p.parse_meta_item_inner())
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! network deals abstracts away the manipulation of network device and
//! interface unit files. All that is left is to write the resulting string to
//! the necessary unit.

use std::net::IpAddr;

pub struct IpNetwork {
    addr: IpAddr,
    prefix: u8,
}

pub struct NetworkRoute {
    destination: IpNetwork,
    gateway: IpAddr,
}

pub struct MacAddr(pub u8, pub u8, pub u8,pub u8, pub u8, pub u8, pub u8, pub u8);

pub struct Interface {
    name: String,
    mac_address: MacAddr,
    priority: u32,
    nameservers: Vec<IpAddr>,
    ip_addresses: Vec<IpNetwork>,
    routes: Vec<NetworkRoute>,
    bond: String
}

pub struct Section {
    name: String,
    attributes: Vec<(String, String)>,
}

pub struct Device {
    name: String,
    kind: String,
    mac_address: MacAddr,
    priority: u32,
    sections: Vec

}

impl Interface {
    pub fn unit_name(&self) -> String {
        String::new()
    }
    pub fn config(&self) -> String {
        String::new()
    }
}

impl Device {
    pub fn unit_name(&self) -> String {
        String::new()
    }
    pub fn config(&self) -> String {
        String::new()
    }
}
<commit_msg>network: write network interface/device units<commit_after>// Copyright 2017 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! network deals abstracts away the manipulation of network device and
//! interface unit files. All that is left is to write the resulting string to
//! the necessary unit.

use std::net::IpAddr;
use std::fmt;
use std::string::String;
use std::string::ToString;

#[derive(Clone, Copy, Debug)]
pub struct IpNetwork {
    addr: IpAddr,
    prefix: u8,
}

impl fmt::Display for IpNetwork {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}/{}", self.addr, self.prefix)
    }
}

#[derive(Clone, Copy, Debug)]
pub struct NetworkRoute {
    destination: IpNetwork,
    gateway: IpAddr,
}

#[derive(Clone, Copy, Debug)]
pub struct MacAddr(pub u8, pub u8, pub u8,pub u8, pub u8, pub u8, pub u8, pub u8);

impl fmt::Display for MacAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}", self.0, self.1, self.2, self.3, self.4, self.5, self.6, self.7)
    }
}

/// for naming purposes an interface needs either a name or an address.
/// it can have both. but it can't have neither.
/// there isn't really a way to express this in the type system
/// so we just panic! if it's not what we expected.
/// I guess that there aren't really type systems with inclusive disjunction
/// so it's not really that big of a deal.
#[derive(Clone, Debug)]
pub struct Interface {
    name: Option<String>,
    mac_address: Option<MacAddr>,
    priority: Option<u32>,
    nameservers: Vec<IpAddr>,
    ip_addresses: Vec<IpNetwork>,
    routes: Vec<NetworkRoute>,
    bond: Option<String>,
}

#[derive(Clone, Debug)]
pub struct Section {
    name: String,
    attributes: Vec<(String, String)>,
}

#[derive(Clone, Debug)]
pub struct Device {
    name: String,
    kind: String,
    mac_address: MacAddr,
    priority: Option<u32>,
    sections: Vec

}

impl Interface {
    pub fn unit_name(&self) -> String {
        format!("{:02}-{}.network",
                self.priority.unwrap_or(10),
                self.name.clone().unwrap_or(
                    self.mac_address.unwrap_or_else(
                        // needs to be a lambda or we panic immediately
                        // yay, manual thunking!
                        ||panic!("interface needs either name or mac address (or both)")
                    ).to_string()
                ))
    }
    pub fn config(&self) -> String {
        let mut config = String::new();

        // [Match] section
        config.push_str("[Match]\n");
        self.name.clone().map(|name| config.push_str(&format!("Name={}\n", name)));
        self.mac_address.map(|mac| config.push_str(&format!("MACAddress={}\n", mac)));

        // [Network] section
        config.push_str("\n[Network]\n");
        for ns in &self.nameservers {
            config.push_str(&format!("DNS={}\n", ns))
        }
        self.bond.clone().map(|bond| config.push_str(&format!("Bond={}\n", bond)));

        // [Address] sections
        for addr in &self.ip_addresses {
            config.push_str(&format!("\n[Address]\nAddress={}\n", addr));
        }

        // [Route] sections
        for route in &self.routes {
            config.push_str(&format!("\n[Route]\nDestination={}\nGateway={}\n", route.destination, route.gateway));
        }

        config
    }
}

impl Device {
    pub fn unit_name(&self) -> String {
        format!("{:02}-{}.netdev", self.priority.unwrap_or(10), self.name)
    }
    pub fn config(&self) -> String {
        let mut config = String::new();

        // [NetDev] section
        config.push_str("[NetDev]\n");
        config.push_str(&format!("Name={}\n", self.name));
        config.push_str(&format!("Kind={}\n", self.kind));
        config.push_str(&format!("MACAddress={}\n", self.mac_address));

        // custom sections
        for section in &self.sections {
            config.push_str(&format!("\n[{}]\n", section.name));
            for attr in &section.attributes {
                config.push_str(&format!("{}={}\n", attr.0, attr.1));
            }
        }

        config
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 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.

//! The `Clone` trait for types that cannot be 'implicitly copied'
//!
//! In Rust, some simple types are "implicitly copyable" and when you
//! assign them or pass them as arguments, the receiver will get a copy,
//! leaving the original value in place. These types do not require
//! allocation to copy and do not have finalizers (i.e. they do not
//! contain owned boxes or implement `Drop`), so the compiler considers
//! them cheap and safe to copy. For other types copies must be made
//! explicitly, by convention implementing the `Clone` trait and calling
//! the `clone` method.

#![stable(feature = "rust1", since = "1.0.0")]

use marker::Sized;

/// A common trait for cloning an object.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Clone : Sized {
    /// Returns a copy of the value.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn clone(&self) -> Self;

    /// Perform copy-assignment from `source`.
    ///
    /// `a.clone_from(&b)` is equivalent to `a = b.clone()` in functionality,
    /// but can be overridden to reuse the resources of `a` to avoid unnecessary
    /// allocations.
    #[inline(always)]
    #[unstable(feature = "core",
               reason = "this function is rarely used")]
    fn clone_from(&mut self, source: &Self) {
        *self = source.clone()
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized> Clone for &'a T {
    /// Return a shallow copy of the reference.
    #[inline]
    fn clone(&self) -> &'a T { *self }
}

macro_rules! clone_impl {
    ($t:ty) => {
        #[stable(feature = "rust1", since = "1.0.0")]
        impl Clone for $t {
            /// Return a deep copy of the value.
            #[inline]
            fn clone(&self) -> $t { *self }
        }
    }
}

clone_impl! { isize }
clone_impl! { i8 }
clone_impl! { i16 }
clone_impl! { i32 }
clone_impl! { i64 }

clone_impl! { usize }
clone_impl! { u8 }
clone_impl! { u16 }
clone_impl! { u32 }
clone_impl! { u64 }

clone_impl! { f32 }
clone_impl! { f64 }

clone_impl! { () }
clone_impl! { bool }
clone_impl! { char }

macro_rules! extern_fn_clone {
    ($($A:ident),*) => (
        #[unstable(feature = "core",
                   reason = "this may not be sufficient for fns with region parameters")]
        impl<$($A,)* ReturnType> Clone for extern "Rust" fn($($A),*) -> ReturnType {
            /// Return a copy of a function pointer
            #[inline]
            fn clone(&self) -> extern "Rust" fn($($A),*) -> ReturnType { *self }
        }
    )
}

extern_fn_clone! {}
extern_fn_clone! { A }
extern_fn_clone! { A, B }
extern_fn_clone! { A, B, C }
extern_fn_clone! { A, B, C, D }
extern_fn_clone! { A, B, C, D, E }
extern_fn_clone! { A, B, C, D, E, F }
extern_fn_clone! { A, B, C, D, E, F, G }
extern_fn_clone! { A, B, C, D, E, F, G, H }
<commit_msg>rollup merge of #23671: steveklabnik/doc_std_clone<commit_after>// Copyright 2012-2013 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.

//! The `Clone` trait for types that cannot be 'implicitly copied'
//!
//! In Rust, some simple types are "implicitly copyable" and when you
//! assign them or pass them as arguments, the receiver will get a copy,
//! leaving the original value in place. These types do not require
//! allocation to copy and do not have finalizers (i.e. they do not
//! contain owned boxes or implement `Drop`), so the compiler considers
//! them cheap and safe to copy. For other types copies must be made
//! explicitly, by convention implementing the `Clone` trait and calling
//! the `clone` method.

#![stable(feature = "rust1", since = "1.0.0")]

use marker::Sized;

/// A common trait for cloning an object.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Clone : Sized {
    /// Returns a copy of the value.
    ///
    /// # Examples
    ///
    /// ```
    /// let hello = "Hello"; // &str implements Clone
    ///
    /// assert_eq!("Hello", hello.clone());
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    fn clone(&self) -> Self;

    /// Perform copy-assignment from `source`.
    ///
    /// `a.clone_from(&b)` is equivalent to `a = b.clone()` in functionality,
    /// but can be overridden to reuse the resources of `a` to avoid unnecessary
    /// allocations.
    #[inline(always)]
    #[unstable(feature = "core",
               reason = "this function is rarely used")]
    fn clone_from(&mut self, source: &Self) {
        *self = source.clone()
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized> Clone for &'a T {
    /// Return a shallow copy of the reference.
    #[inline]
    fn clone(&self) -> &'a T { *self }
}

macro_rules! clone_impl {
    ($t:ty) => {
        #[stable(feature = "rust1", since = "1.0.0")]
        impl Clone for $t {
            /// Return a deep copy of the value.
            #[inline]
            fn clone(&self) -> $t { *self }
        }
    }
}

clone_impl! { isize }
clone_impl! { i8 }
clone_impl! { i16 }
clone_impl! { i32 }
clone_impl! { i64 }

clone_impl! { usize }
clone_impl! { u8 }
clone_impl! { u16 }
clone_impl! { u32 }
clone_impl! { u64 }

clone_impl! { f32 }
clone_impl! { f64 }

clone_impl! { () }
clone_impl! { bool }
clone_impl! { char }

macro_rules! extern_fn_clone {
    ($($A:ident),*) => (
        #[unstable(feature = "core",
                   reason = "this may not be sufficient for fns with region parameters")]
        impl<$($A,)* ReturnType> Clone for extern "Rust" fn($($A),*) -> ReturnType {
            /// Return a copy of a function pointer
            #[inline]
            fn clone(&self) -> extern "Rust" fn($($A),*) -> ReturnType { *self }
        }
    )
}

extern_fn_clone! {}
extern_fn_clone! { A }
extern_fn_clone! { A, B }
extern_fn_clone! { A, B, C }
extern_fn_clone! { A, B, C, D }
extern_fn_clone! { A, B, C, D, E }
extern_fn_clone! { A, B, C, D, E, F }
extern_fn_clone! { A, B, C, D, E, F, G }
extern_fn_clone! { A, B, C, D, E, F, G, H }
<|endoftext|>


<commit_before>use std::collections::HashSet;

use protobuf::descriptor::*;

use crate::customize::ctx::CustomizeElemCtx;
use crate::customize::rustproto_proto::customize_from_rustproto_for_enum;
use crate::gen::code_writer::*;
use crate::gen::file_index::FileIndex;
use crate::gen::inside::protobuf_crate_path;
use crate::gen::protoc_insertion_point::write_protoc_insertion_point_for_enum;
use crate::gen::protoc_insertion_point::write_protoc_insertion_point_for_enum_value;
use crate::gen::rust::EXPR_NONE;
use crate::gen::rust_name::RustIdent;
use crate::gen::rust_name::RustIdentWithPath;
use crate::gen::scope::EnumValueWithContext;
use crate::gen::scope::EnumWithScope;
use crate::gen::scope::RootScope;
use crate::gen::scope::WithScope;

#[derive(Clone)]
pub(crate) struct EnumValueGen<'a> {
    value: EnumValueWithContext<'a>,
    enum_rust_name: RustIdentWithPath,
}

impl<'a> EnumValueGen<'a> {
    fn parse(
        value: EnumValueWithContext<'a>,
        enum_rust_name: &RustIdentWithPath,
    ) -> EnumValueGen<'a> {
        EnumValueGen {
            value: value.clone(),
            enum_rust_name: enum_rust_name.clone(),
        }
    }

    // enum value
    fn number(&self) -> i32 {
        self.value.proto.proto().number()
    }

    // name of enum variant in generated rust code
    pub fn rust_name_inner(&self) -> RustIdent {
        self.value.rust_name()
    }

    pub fn rust_name_outer(&self) -> RustIdentWithPath {
        self.enum_rust_name
            .to_path()
            .with_ident(self.rust_name_inner())
    }
}

// Codegen for enum definition
pub(crate) struct EnumGen<'a> {
    enum_with_scope: &'a EnumWithScope<'a>,
    file_index: &'a FileIndex,
    type_name: RustIdentWithPath,
    lite_runtime: bool,
    customize: CustomizeElemCtx<'a>,
    path: &'a [i32],
    info: Option<&'a SourceCodeInfo>,
}

impl<'a> EnumGen<'a> {
    pub fn new(
        enum_with_scope: &'a EnumWithScope<'a>,
        file_index: &'a FileIndex,
        customize: &CustomizeElemCtx<'a>,
        _root_scope: &RootScope,
        path: &'a [i32],
        info: Option<&'a SourceCodeInfo>,
    ) -> EnumGen<'a> {
        let customize = customize.child(
            &customize_from_rustproto_for_enum(enum_with_scope.en.proto().options.get_or_default()),
            &enum_with_scope.en,
        );
        let lite_runtime = customize.for_elem.lite_runtime.unwrap_or_else(|| {
            enum_with_scope
                .scope()
                .file_descriptor()
                .options
                .get_or_default()
                .optimize_for()
                == file_options::OptimizeMode::LITE_RUNTIME
        });

        EnumGen {
            enum_with_scope,
            type_name: enum_with_scope.rust_name().to_path(),
            lite_runtime,
            customize,
            path,
            info,
            file_index,
        }
    }

    fn index_in_file(&self) -> u32 {
        self.file_index.enum_to_index[&self.enum_with_scope.protobuf_name_to_package()]
    }

    fn allow_alias(&self) -> bool {
        self.enum_with_scope
            .en
            .proto()
            .options
            .get_or_default()
            .allow_alias()
    }

    fn values_all(&self) -> Vec<EnumValueGen> {
        let mut r = Vec::new();
        for p in self.enum_with_scope.values() {
            r.push(EnumValueGen::parse(p, &self.type_name));
        }
        r
    }

    fn values_unique(&self) -> Vec<EnumValueGen> {
        let mut used = HashSet::new();
        let mut r = Vec::new();
        for p in self.enum_with_scope.values() {
            if !used.insert(p.proto.proto().number()) {
                continue;
            }
            r.push(EnumValueGen::parse(p, &self.type_name));
        }
        r
    }

    pub fn write(&self, w: &mut CodeWriter) {
        self.write_enum(w);
        if self.allow_alias() {
            w.write_line("");
            self.write_impl_eq(w);
            w.write_line("");
            self.write_impl_hash(w);
        }
        w.write_line("");
        self.write_impl_enum(w);
        if !self.lite_runtime {
            w.write_line("");
            self.write_impl_enum_full(w);
        }
        w.write_line("");
        self.write_impl_default(w);
        w.write_line("");
        self.write_impl_self(w);
    }

    fn write_impl_self(&self, w: &mut CodeWriter) {
        if !self.lite_runtime {
            w.impl_self_block(&format!("{}", self.type_name), |w| {
                self.write_generated_enum_descriptor_data(w);
            });
        }
    }

    fn write_enum(&self, w: &mut CodeWriter) {
        w.all_documentation(self.info, self.path);

        let mut derive = Vec::new();
        derive.push("Clone");
        derive.push("Copy");
        if !self.allow_alias() {
            derive.push("PartialEq");
        }
        derive.push("Eq");
        derive.push("Debug");
        if !self.allow_alias() {
            derive.push("Hash");
        } else {
            w.comment("Note: you cannot use pattern matching for enums with allow_alias option");
        }
        w.derive(&derive);
        let ref type_name = self.type_name;
        write_protoc_insertion_point_for_enum(
            w,
            &self.customize.for_elem,
            &self.enum_with_scope.en,
        );
        w.expr_block(&format!("pub enum {}", type_name), |w| {
            for value in self.values_all() {
                write_protoc_insertion_point_for_enum_value(
                    w,
                    &self.customize.for_children,
                    &value.value.proto,
                );
                if self.allow_alias() {
                    w.write_line(&format!(
                        "{}, // {}",
                        value.rust_name_inner(),
                        value.number()
                    ));
                } else {
                    w.write_line(&format!(
                        "{} = {},",
                        value.rust_name_inner(),
                        value.number()
                    ));
                }
            }
        });
    }

    fn write_fn_value(&self, w: &mut CodeWriter) {
        w.def_fn("value(&self) -> i32", |w| {
            if self.allow_alias() {
                w.match_expr("*self", |w| {
                    for value in self.values_all() {
                        w.case_expr(
                            &format!("{}", value.rust_name_outer()),
                            &format!("{}", value.number()),
                        );
                    }
                });
            } else {
                w.write_line("*self as i32")
            }
        });
    }

    fn write_impl_enum(&self, w: &mut CodeWriter) {
        let ref type_name = self.type_name;
        w.impl_for_block(
            &format!("{}::Enum", protobuf_crate_path(&self.customize.for_elem)),
            &format!("{}", type_name),
            |w| {
                w.write_line(&format!(
                    "const NAME: &'static str = \"{}\";",
                    self.enum_with_scope.en.name()
                ));

                w.write_line("");
                self.write_fn_value(w);

                w.write_line("");
                let ref type_name = self.type_name;
                w.def_fn(
                    &format!(
                        "from_i32(value: i32) -> ::std::option::Option<{}>",
                        type_name
                    ),
                    |w| {
                        w.match_expr("value", |w| {
                            let values = self.values_unique();
                            for value in values {
                                w.write_line(&format!(
                                    "{} => ::std::option::Option::Some({}),",
                                    value.number(),
                                    value.rust_name_outer()
                                ));
                            }
                            w.write_line(&format!("_ => {}", EXPR_NONE));
                        });
                    },
                );

                w.write_line("");
                w.def_fn(&format!("values() -> &'static [Self]"), |w| {
                    w.write_line(&format!("static values: &'static [{}] = &[", type_name));
                    w.indented(|w| {
                        for value in self.values_all() {
                            w.write_line(&format!("{},", value.rust_name_outer()));
                        }
                    });
                    w.write_line("];");
                    w.write_line("values");
                });
            },
        );
    }

    fn write_impl_enum_full(&self, w: &mut CodeWriter) {
        let ref type_name = self.type_name;
        w.impl_for_block(
            &format!(
                "{}::EnumFull",
                protobuf_crate_path(&self.customize.for_elem)
            ),
            &format!("{}", type_name),
            |w| {
                self.write_enum_descriptor_static(w);
            },
        );
    }

    fn write_enum_descriptor_static(&self, w: &mut CodeWriter) {
        let sig = format!(
            "enum_descriptor_static() -> {}::reflect::EnumDescriptor",
            protobuf_crate_path(&self.customize.for_elem)
        );
        w.def_fn(&sig, |w| {
            w.write_line(&format!(
                "{}::reflect::EnumDescriptor::new_generated_2({}(), {})",
                protobuf_crate_path(&self.customize.for_elem),
                self.enum_with_scope
                    .scope()
                    .rust_path_to_file()
                    .to_reverse()
                    .append_ident("file_descriptor".into()),
                self.index_in_file(),
            ));
        });
    }

    fn write_generated_enum_descriptor_data(&self, w: &mut CodeWriter) {
        let sig = format!(
            "generated_enum_descriptor_data() -> {}::reflect::GeneratedEnumDescriptorData",
            protobuf_crate_path(&self.customize.for_elem)
        );
        w.fn_block(
            Visibility::Path(
                self.enum_with_scope
                    .scope()
                    .rust_path_to_file()
                    .to_reverse(),
            ),
            &sig,
            |w| {
                w.write_line(&format!(
                    "{}::reflect::GeneratedEnumDescriptorData::new_2::<{}>(\"{}\", {})",
                    protobuf_crate_path(&self.customize.for_elem),
                    self.type_name,
                    self.enum_with_scope.name_to_package(),
                    self.index_in_file(),
                ));
            },
        );
    }

    fn write_impl_eq(&self, w: &mut CodeWriter) {
        assert!(self.allow_alias());
        w.impl_for_block(
            "::std::cmp::PartialEq",
            &format!("{}", self.type_name),
            |w| {
                w.def_fn("eq(&self, other: &Self) -> bool", |w| {
                    w.write_line(&format!(
                        "{}::Enum::value(self) == {}::Enum::value(other)",
                        protobuf_crate_path(&self.customize.for_elem),
                        protobuf_crate_path(&self.customize.for_elem)
                    ));
                });
            },
        );
    }

    fn write_impl_hash(&self, w: &mut CodeWriter) {
        assert!(self.allow_alias());
        w.impl_for_block("::std::hash::Hash", &format!("{}", self.type_name), |w| {
            w.def_fn("hash<H : ::std::hash::Hasher>(&self, state: &mut H)", |w| {
                w.write_line(&format!(
                    "state.write_i32({}::Enum::value(self))",
                    protobuf_crate_path(&self.customize.for_elem)
                ));
            });
        });
    }

    fn write_impl_default(&self, w: &mut CodeWriter) {
        let first_value = &self.enum_with_scope.values()[0];
        if first_value.proto.proto().number() != 0 {
            // This warning is emitted only for proto2
            // (because in proto3 first enum variant number is always 0).
            // `Default` implemented unconditionally to simplify certain
            // generic operations, e. g. reading a map.
            // Also, note that even in proto2 some operations fallback to
            // first enum value, e. g. `get_xxx` for unset field,
            // so this implementation is not completely unreasonable.
            w.comment("Note, `Default` is implemented although default value is not 0");
        }
        w.impl_for_block(
            "::std::default::Default",
            &format!("{}", self.type_name),
            |w| {
                w.def_fn("default() -> Self", |w| {
                    w.write_line(&format!(
                        "{}::{}",
                        &self.type_name,
                        &first_value.rust_name()
                    ))
                });
            },
        );
    }
}
<commit_msg>Enum codegen minor refactoring<commit_after>use std::collections::HashSet;

use protobuf::descriptor::*;

use crate::customize::ctx::CustomizeElemCtx;
use crate::customize::rustproto_proto::customize_from_rustproto_for_enum;
use crate::gen::code_writer::*;
use crate::gen::file_index::FileIndex;
use crate::gen::inside::protobuf_crate_path;
use crate::gen::protoc_insertion_point::write_protoc_insertion_point_for_enum;
use crate::gen::protoc_insertion_point::write_protoc_insertion_point_for_enum_value;
use crate::gen::rust::EXPR_NONE;
use crate::gen::rust_name::RustIdent;
use crate::gen::rust_name::RustIdentWithPath;
use crate::gen::scope::EnumValueWithContext;
use crate::gen::scope::EnumWithScope;
use crate::gen::scope::RootScope;
use crate::gen::scope::WithScope;

#[derive(Clone)]
pub(crate) struct EnumValueGen<'a> {
    value: EnumValueWithContext<'a>,
    enum_rust_name: RustIdentWithPath,
}

impl<'a> EnumValueGen<'a> {
    fn parse(
        value: EnumValueWithContext<'a>,
        enum_rust_name: &RustIdentWithPath,
    ) -> EnumValueGen<'a> {
        EnumValueGen {
            value: value.clone(),
            enum_rust_name: enum_rust_name.clone(),
        }
    }

    // enum value
    fn number(&self) -> i32 {
        self.value.proto.proto().number()
    }

    // name of enum variant in generated rust code
    pub fn rust_name_inner(&self) -> RustIdent {
        self.value.rust_name()
    }

    pub fn rust_name_outer(&self) -> RustIdentWithPath {
        self.enum_rust_name
            .to_path()
            .with_ident(self.rust_name_inner())
    }
}

// Codegen for enum definition
pub(crate) struct EnumGen<'a> {
    enum_with_scope: &'a EnumWithScope<'a>,
    file_index: &'a FileIndex,
    type_name: RustIdentWithPath,
    lite_runtime: bool,
    customize: CustomizeElemCtx<'a>,
    path: &'a [i32],
    info: Option<&'a SourceCodeInfo>,
}

impl<'a> EnumGen<'a> {
    pub fn new(
        enum_with_scope: &'a EnumWithScope<'a>,
        file_index: &'a FileIndex,
        customize: &CustomizeElemCtx<'a>,
        _root_scope: &RootScope,
        path: &'a [i32],
        info: Option<&'a SourceCodeInfo>,
    ) -> EnumGen<'a> {
        let customize = customize.child(
            &customize_from_rustproto_for_enum(enum_with_scope.en.proto().options.get_or_default()),
            &enum_with_scope.en,
        );
        let lite_runtime = customize.for_elem.lite_runtime.unwrap_or_else(|| {
            enum_with_scope
                .scope()
                .file_descriptor()
                .options
                .get_or_default()
                .optimize_for()
                == file_options::OptimizeMode::LITE_RUNTIME
        });

        EnumGen {
            enum_with_scope,
            type_name: enum_with_scope.rust_name().to_path(),
            lite_runtime,
            customize,
            path,
            info,
            file_index,
        }
    }

    fn index_in_file(&self) -> u32 {
        self.file_index.enum_to_index[&self.enum_with_scope.protobuf_name_to_package()]
    }

    fn allow_alias(&self) -> bool {
        self.enum_with_scope
            .en
            .proto()
            .options
            .get_or_default()
            .allow_alias()
    }

    fn values_all(&self) -> Vec<EnumValueGen> {
        let mut r = Vec::new();
        for p in self.enum_with_scope.values() {
            r.push(EnumValueGen::parse(p, &self.type_name));
        }
        r
    }

    fn values_unique(&self) -> Vec<EnumValueGen> {
        let mut used = HashSet::new();
        let mut r = Vec::new();
        for p in self.enum_with_scope.values() {
            if !used.insert(p.proto.proto().number()) {
                continue;
            }
            r.push(EnumValueGen::parse(p, &self.type_name));
        }
        r
    }

    pub fn write(&self, w: &mut CodeWriter) {
        self.write_enum(w);
        if self.allow_alias() {
            w.write_line("");
            self.write_impl_eq(w);
            w.write_line("");
            self.write_impl_hash(w);
        }
        w.write_line("");
        self.write_impl_enum(w);
        if !self.lite_runtime {
            w.write_line("");
            self.write_impl_enum_full(w);
        }
        w.write_line("");
        self.write_impl_default(w);
        w.write_line("");
        self.write_impl_self(w);
    }

    fn write_impl_self(&self, w: &mut CodeWriter) {
        if !self.lite_runtime {
            w.impl_self_block(&format!("{}", self.type_name), |w| {
                self.write_generated_enum_descriptor_data(w);
            });
        }
    }

    fn write_enum(&self, w: &mut CodeWriter) {
        w.all_documentation(self.info, self.path);

        let mut derive = Vec::new();
        derive.push("Clone");
        derive.push("Copy");
        if !self.allow_alias() {
            derive.push("PartialEq");
        }
        derive.push("Eq");
        derive.push("Debug");
        if !self.allow_alias() {
            derive.push("Hash");
        } else {
            w.comment("Note: you cannot use pattern matching for enums with allow_alias option");
        }
        w.derive(&derive);
        let ref type_name = self.type_name;
        write_protoc_insertion_point_for_enum(
            w,
            &self.customize.for_elem,
            &self.enum_with_scope.en,
        );
        w.expr_block(&format!("pub enum {}", type_name), |w| {
            for value in self.values_all() {
                write_protoc_insertion_point_for_enum_value(
                    w,
                    &self.customize.for_children,
                    &value.value.proto,
                );
                if self.allow_alias() {
                    w.write_line(&format!(
                        "{}, // {}",
                        value.rust_name_inner(),
                        value.number()
                    ));
                } else {
                    w.write_line(&format!(
                        "{} = {},",
                        value.rust_name_inner(),
                        value.number()
                    ));
                }
            }
        });
    }

    fn write_impl_enum_fn_value(&self, w: &mut CodeWriter) {
        w.def_fn("value(&self) -> i32", |w| {
            if self.allow_alias() {
                w.match_expr("*self", |w| {
                    for value in self.values_all() {
                        w.case_expr(
                            &format!("{}", value.rust_name_outer()),
                            &format!("{}", value.number()),
                        );
                    }
                });
            } else {
                w.write_line("*self as i32")
            }
        });
    }

    fn write_impl_enum_const_name(&self, w: &mut CodeWriter) {
        w.write_line(&format!(
            "const NAME: &'static str = \"{}\";",
            self.enum_with_scope.en.name()
        ));
    }

    fn write_impl_enum_fn_from_i32(&self, w: &mut CodeWriter) {
        w.def_fn(
            &format!(
                "from_i32(value: i32) -> ::std::option::Option<{}>",
                self.type_name
            ),
            |w| {
                w.match_expr("value", |w| {
                    let values = self.values_unique();
                    for value in values {
                        w.write_line(&format!(
                            "{} => ::std::option::Option::Some({}),",
                            value.number(),
                            value.rust_name_outer()
                        ));
                    }
                    w.write_line(&format!("_ => {}", EXPR_NONE));
                });
            },
        );
    }

    fn write_impl_enum_fn_values(&self, w: &mut CodeWriter) {
        w.def_fn(&format!("values() -> &'static [Self]"), |w| {
            w.write_line(&format!(
                "static values: &'static [{}] = &[",
                self.type_name
            ));
            w.indented(|w| {
                for value in self.values_all() {
                    w.write_line(&format!("{},", value.rust_name_outer()));
                }
            });
            w.write_line("];");
            w.write_line("values");
        });
    }

    fn write_impl_enum(&self, w: &mut CodeWriter) {
        w.impl_for_block(
            &format!("{}::Enum", protobuf_crate_path(&self.customize.for_elem)),
            &format!("{}", self.type_name),
            |w| {
                self.write_impl_enum_const_name(w);
                w.write_line("");
                self.write_impl_enum_fn_value(w);
                w.write_line("");
                self.write_impl_enum_fn_from_i32(w);
                w.write_line("");
                self.write_impl_enum_fn_values(w);
            },
        );
    }

    fn write_impl_enum_full(&self, w: &mut CodeWriter) {
        let ref type_name = self.type_name;
        w.impl_for_block(
            &format!(
                "{}::EnumFull",
                protobuf_crate_path(&self.customize.for_elem)
            ),
            &format!("{}", type_name),
            |w| {
                self.write_enum_descriptor_static(w);
            },
        );
    }

    fn write_enum_descriptor_static(&self, w: &mut CodeWriter) {
        let sig = format!(
            "enum_descriptor_static() -> {}::reflect::EnumDescriptor",
            protobuf_crate_path(&self.customize.for_elem)
        );
        w.def_fn(&sig, |w| {
            w.write_line(&format!(
                "{}::reflect::EnumDescriptor::new_generated_2({}(), {})",
                protobuf_crate_path(&self.customize.for_elem),
                self.enum_with_scope
                    .scope()
                    .rust_path_to_file()
                    .to_reverse()
                    .append_ident("file_descriptor".into()),
                self.index_in_file(),
            ));
        });
    }

    fn write_generated_enum_descriptor_data(&self, w: &mut CodeWriter) {
        let sig = format!(
            "generated_enum_descriptor_data() -> {}::reflect::GeneratedEnumDescriptorData",
            protobuf_crate_path(&self.customize.for_elem)
        );
        w.fn_block(
            Visibility::Path(
                self.enum_with_scope
                    .scope()
                    .rust_path_to_file()
                    .to_reverse(),
            ),
            &sig,
            |w| {
                w.write_line(&format!(
                    "{}::reflect::GeneratedEnumDescriptorData::new_2::<{}>(\"{}\", {})",
                    protobuf_crate_path(&self.customize.for_elem),
                    self.type_name,
                    self.enum_with_scope.name_to_package(),
                    self.index_in_file(),
                ));
            },
        );
    }

    fn write_impl_eq(&self, w: &mut CodeWriter) {
        assert!(self.allow_alias());
        w.impl_for_block(
            "::std::cmp::PartialEq",
            &format!("{}", self.type_name),
            |w| {
                w.def_fn("eq(&self, other: &Self) -> bool", |w| {
                    w.write_line(&format!(
                        "{}::Enum::value(self) == {}::Enum::value(other)",
                        protobuf_crate_path(&self.customize.for_elem),
                        protobuf_crate_path(&self.customize.for_elem)
                    ));
                });
            },
        );
    }

    fn write_impl_hash(&self, w: &mut CodeWriter) {
        assert!(self.allow_alias());
        w.impl_for_block("::std::hash::Hash", &format!("{}", self.type_name), |w| {
            w.def_fn("hash<H : ::std::hash::Hasher>(&self, state: &mut H)", |w| {
                w.write_line(&format!(
                    "state.write_i32({}::Enum::value(self))",
                    protobuf_crate_path(&self.customize.for_elem)
                ));
            });
        });
    }

    fn write_impl_default(&self, w: &mut CodeWriter) {
        let first_value = &self.enum_with_scope.values()[0];
        if first_value.proto.proto().number() != 0 {
            // This warning is emitted only for proto2
            // (because in proto3 first enum variant number is always 0).
            // `Default` implemented unconditionally to simplify certain
            // generic operations, e. g. reading a map.
            // Also, note that even in proto2 some operations fallback to
            // first enum value, e. g. `get_xxx` for unset field,
            // so this implementation is not completely unreasonable.
            w.comment("Note, `Default` is implemented although default value is not 0");
        }
        w.impl_for_block(
            "::std::default::Default",
            &format!("{}", self.type_name),
            |w| {
                w.def_fn("default() -> Self", |w| {
                    w.write_line(&format!(
                        "{}::{}",
                        &self.type_name,
                        &first_value.rust_name()
                    ))
                });
            },
        );
    }
}
<|endoftext|>


<commit_before>use std::str;

use protobuf_support::lexer::int;
use protobuf_support::lexer::loc::Loc;
use protobuf_support::lexer::parser_language::ParserLanguage;
use protobuf_support::lexer::str_lit::StrLitDecodeError;
use protobuf_support::lexer::tokenizer::Tokenizer;
use protobuf_support::lexer::tokenizer::TokenizerError;

use crate::message_dyn::MessageDyn;
use crate::message_full::MessageFull;
use crate::reflect::EnumDescriptor;
use crate::reflect::EnumValueDescriptor;
use crate::reflect::MessageDescriptor;
use crate::reflect::ReflectValueBox;
use crate::reflect::RuntimeFieldType;
use crate::reflect::RuntimeTypeBox;

#[derive(Debug, thiserror::Error)]
pub enum ParseErrorWithoutLoc {
    #[error(transparent)]
    TokenizerError(#[from] TokenizerError),
    #[error(transparent)]
    StrLitDecodeError(#[from] StrLitDecodeError),
    #[error("Unknown field: `{}`", .0)]
    UnknownField(String),
    #[error("Unknown enum value: `{}`", .0)]
    UnknownEnumValue(String),
    #[error("Map field specified more than once: `{}`", .0)]
    MapFieldIsSpecifiedMoreThanOnce(String),
    #[error("Integer overflow")]
    IntegerOverflow,
    #[error("Expecting bool")]
    ExpectingBool,
    #[error("Message not initialized")]
    MessageNotInitialized,
}

impl From<int::Overflow> for ParseErrorWithoutLoc {
    fn from(_: int::Overflow) -> Self {
        ParseErrorWithoutLoc::IntegerOverflow
    }
}

/// Text format parse error.
#[derive(Debug, thiserror::Error)]
#[error("{}: {}", loc, error)]
pub struct ParseError {
    error: ParseErrorWithoutLoc,
    loc: Loc,
}

pub type ParseResult<A> = Result<A, ParseErrorWithoutLoc>;
pub type ParseWithLocResult<A> = Result<A, ParseError>;

#[derive(Clone)]
struct Parser<'a> {
    tokenizer: Tokenizer<'a>,
}

impl<'a> Parser<'a> {
    // Text format

    fn next_field_name(&mut self) -> ParseResult<String> {
        Ok(self.tokenizer.next_ident()?)
    }

    fn read_colon(&mut self, desc: &'static str) -> ParseResult<()> {
        Ok(self.tokenizer.next_symbol_expect_eq(':', desc)?)
    }

    fn read_enum<'e>(&mut self, e: &'e EnumDescriptor) -> ParseResult<EnumValueDescriptor> {
        self.read_colon("enum")?;

        // TODO: read integer?
        let ident = self.tokenizer.next_ident()?;
        let value = match e.value_by_name(&ident) {
            Some(value) => value,
            None => return Err(ParseErrorWithoutLoc::UnknownEnumValue(ident)),
        };
        Ok(value)
    }

    fn read_u64(&mut self) -> ParseResult<u64> {
        self.read_colon("u64")?;

        Ok(self.tokenizer.next_int_lit()?)
    }

    fn read_u32(&mut self) -> ParseResult<u32> {
        self.read_colon("int value")?;

        let int_lit = self.tokenizer.next_int_lit()?;
        let value_u32 = int_lit as u32;
        if value_u32 as u64 != int_lit {
            return Err(ParseErrorWithoutLoc::IntegerOverflow);
        }
        Ok(value_u32)
    }

    fn read_i64(&mut self) -> ParseResult<i64> {
        self.read_colon("int value")?;

        if self.tokenizer.next_symbol_if_eq('-')? {
            let int_lit = self.tokenizer.next_int_lit()?;
            Ok(int::neg(int_lit)?)
        } else {
            let int_lit = self.tokenizer.next_int_lit()?;
            if int_lit > i64::max_value() as u64 {
                return Err(ParseErrorWithoutLoc::IntegerOverflow);
            }
            Ok(int_lit as i64)
        }
    }

    fn read_i32(&mut self) -> ParseResult<i32> {
        let value = self.read_i64()?;
        if value < i32::min_value() as i64 || value > i32::max_value() as i64 {
            return Err(ParseErrorWithoutLoc::IntegerOverflow);
        }
        Ok(value as i32)
    }

    fn read_f64(&mut self) -> ParseResult<f64> {
        self.read_colon("float value")?;

        let minus = self.tokenizer.next_symbol_if_eq('-')?;

        let value = if let Ok(value) = self.tokenizer.next_int_lit() {
            value as f64
        } else {
            self.tokenizer.next_float_lit()?
        };

        Ok(if minus { -value } else { value })
    }

    fn read_f32(&mut self) -> ParseResult<f32> {
        Ok(self.read_f64()? as f32)
    }

    fn read_bool(&mut self) -> ParseResult<bool> {
        self.read_colon("bool value")?;

        if self.tokenizer.next_ident_if_eq("true")? {
            Ok(true)
        } else if self.tokenizer.next_ident_if_eq("false")? {
            Ok(false)
        } else {
            Err(ParseErrorWithoutLoc::ExpectingBool)
        }
    }

    fn read_string(&mut self) -> ParseResult<String> {
        self.read_colon("string value")?;

        Ok(self
            .tokenizer
            .next_str_lit()
            .and_then(|s| s.decode_utf8().map_err(From::from))?)
    }

    fn read_bytes(&mut self) -> ParseResult<Vec<u8>> {
        self.read_colon("bytes value")?;

        Ok(self
            .tokenizer
            .next_str_lit()
            .and_then(|s| s.decode_bytes().map_err(From::from))?)
    }

    fn read_message(&mut self, descriptor: &MessageDescriptor) -> ParseResult<Box<dyn MessageDyn>> {
        let mut message = descriptor.new_instance();

        let symbol = self.tokenizer.next_symbol_expect_eq_oneof(&['{', '<'])?;
        let terminator = if symbol == '{' { '}' } else { '>' };
        while !self.tokenizer.lookahead_is_symbol(terminator)? {
            self.merge_field(&mut *message, descriptor)?;
        }
        self.tokenizer
            .next_symbol_expect_eq(terminator, "message")?;
        Ok(message)
    }

    fn read_map_entry(
        &mut self,
        k: &RuntimeTypeBox,
        v: &RuntimeTypeBox,
    ) -> ParseResult<(ReflectValueBox, ReflectValueBox)> {
        let key_field_name: &str = "key";
        let value_field_name: &str = "value";

        let mut key = None;
        let mut value = None;
        self.tokenizer.next_symbol_expect_eq('{', "map entry")?;
        while !self.tokenizer.lookahead_is_symbol('}')? {
            let ident = self.next_field_name()?;
            let (field, field_type) = if ident == key_field_name {
                (&mut key, k)
            } else if ident == value_field_name {
                (&mut value, v)
            } else {
                return Err(ParseErrorWithoutLoc::UnknownField(ident));
            };

            if let Some(..) = *field {
                return Err(ParseErrorWithoutLoc::MapFieldIsSpecifiedMoreThanOnce(ident));
            }

            let field_value = self.read_value_of_type(field_type)?;

            *field = Some(field_value);
        }
        self.tokenizer.next_symbol_expect_eq('}', "map entry")?;
        let key = match key {
            Some(key) => key,
            None => k.default_value_ref().to_box(),
        };
        let value = match value {
            Some(value) => value,
            None => v.default_value_ref().to_box(),
        };
        Ok((key, value))
    }

    fn read_value_of_type(&mut self, t: &RuntimeTypeBox) -> ParseResult<ReflectValueBox> {
        Ok(match t {
            RuntimeTypeBox::Enum(d) => {
                let value = self.read_enum(&d)?.value();
                ReflectValueBox::Enum(d.clone(), value)
            }
            RuntimeTypeBox::U32 => ReflectValueBox::U32(self.read_u32()?),
            RuntimeTypeBox::U64 => ReflectValueBox::U64(self.read_u64()?),
            RuntimeTypeBox::I32 => ReflectValueBox::I32(self.read_i32()?),
            RuntimeTypeBox::I64 => ReflectValueBox::I64(self.read_i64()?),
            RuntimeTypeBox::F32 => ReflectValueBox::F32(self.read_f32()?),
            RuntimeTypeBox::F64 => ReflectValueBox::F64(self.read_f64()?),
            RuntimeTypeBox::Bool => ReflectValueBox::Bool(self.read_bool()?),
            RuntimeTypeBox::String => ReflectValueBox::String(self.read_string()?),
            RuntimeTypeBox::VecU8 => ReflectValueBox::Bytes(self.read_bytes()?),
            RuntimeTypeBox::Message(m) => ReflectValueBox::Message(self.read_message(&m)?),
        })
    }

    fn merge_field(
        &mut self,
        message: &mut dyn MessageDyn,
        descriptor: &MessageDescriptor,
    ) -> ParseResult<()> {
        let field_name = self.next_field_name()?;

        let field = match descriptor.field_by_name(&field_name) {
            Some(field) => field,
            None => {
                // TODO: shouldn't unknown fields be quietly skipped?
                return Err(ParseErrorWithoutLoc::UnknownField(field_name));
            }
        };

        match field.runtime_field_type() {
            RuntimeFieldType::Singular(t) => {
                let value = self.read_value_of_type(&t)?;
                field.set_singular_field(message, value);
            }
            RuntimeFieldType::Repeated(t) => {
                let value = self.read_value_of_type(&t)?;
                field.mut_repeated(message).push(value);
            }
            RuntimeFieldType::Map(k, v) => {
                let (k, v) = self.read_map_entry(&k, &v)?;
                field.mut_map(message).insert(k, v);
            }
        };

        Ok(())
    }

    fn merge_inner(&mut self, message: &mut dyn MessageDyn) -> ParseResult<()> {
        loop {
            if self.tokenizer.syntax_eof()? {
                break;
            }
            let descriptor = message.descriptor_dyn();
            self.merge_field(message, &descriptor)?;
        }
        Ok(())
    }

    fn merge(&mut self, message: &mut dyn MessageDyn) -> ParseWithLocResult<()> {
        match self.merge_inner(message) {
            Ok(()) => Ok(()),
            Err(error) => Err(ParseError {
                error,
                loc: self.tokenizer.loc(),
            }),
        }
    }
}

/// Parse text format message.
///
/// This function does not check if message required fields are set.
pub fn merge_from_str(message: &mut dyn MessageDyn, input: &str) -> ParseWithLocResult<()> {
    let mut parser = Parser {
        tokenizer: Tokenizer::new(input, ParserLanguage::TextFormat),
    };
    parser.merge(message)
}

/// Parse text format message.
pub fn parse_from_str<M: MessageFull>(input: &str) -> ParseWithLocResult<M> {
    let mut m = M::new();
    merge_from_str(&mut m, input)?;
    if let Err(_) = m.check_initialized() {
        return Err(ParseError {
            error: ParseErrorWithoutLoc::MessageNotInitialized,
            loc: Loc::start(),
        });
    }
    Ok(m)
}
<commit_msg>Use non-deprecated function<commit_after>use std::str;

use protobuf_support::lexer::int;
use protobuf_support::lexer::loc::Loc;
use protobuf_support::lexer::parser_language::ParserLanguage;
use protobuf_support::lexer::str_lit::StrLitDecodeError;
use protobuf_support::lexer::tokenizer::Tokenizer;
use protobuf_support::lexer::tokenizer::TokenizerError;

use crate::message_dyn::MessageDyn;
use crate::message_full::MessageFull;
use crate::reflect::EnumDescriptor;
use crate::reflect::EnumValueDescriptor;
use crate::reflect::MessageDescriptor;
use crate::reflect::ReflectValueBox;
use crate::reflect::RuntimeFieldType;
use crate::reflect::RuntimeTypeBox;

#[derive(Debug, thiserror::Error)]
pub enum ParseErrorWithoutLoc {
    #[error(transparent)]
    TokenizerError(#[from] TokenizerError),
    #[error(transparent)]
    StrLitDecodeError(#[from] StrLitDecodeError),
    #[error("Unknown field: `{}`", .0)]
    UnknownField(String),
    #[error("Unknown enum value: `{}`", .0)]
    UnknownEnumValue(String),
    #[error("Map field specified more than once: `{}`", .0)]
    MapFieldIsSpecifiedMoreThanOnce(String),
    #[error("Integer overflow")]
    IntegerOverflow,
    #[error("Expecting bool")]
    ExpectingBool,
    #[error("Message not initialized")]
    MessageNotInitialized,
}

impl From<int::Overflow> for ParseErrorWithoutLoc {
    fn from(_: int::Overflow) -> Self {
        ParseErrorWithoutLoc::IntegerOverflow
    }
}

/// Text format parse error.
#[derive(Debug, thiserror::Error)]
#[error("{}: {}", loc, error)]
pub struct ParseError {
    error: ParseErrorWithoutLoc,
    loc: Loc,
}

pub type ParseResult<A> = Result<A, ParseErrorWithoutLoc>;
pub type ParseWithLocResult<A> = Result<A, ParseError>;

#[derive(Clone)]
struct Parser<'a> {
    tokenizer: Tokenizer<'a>,
}

impl<'a> Parser<'a> {
    // Text format

    fn next_field_name(&mut self) -> ParseResult<String> {
        Ok(self.tokenizer.next_ident()?)
    }

    fn read_colon(&mut self, desc: &'static str) -> ParseResult<()> {
        Ok(self.tokenizer.next_symbol_expect_eq(':', desc)?)
    }

    fn read_enum<'e>(&mut self, e: &'e EnumDescriptor) -> ParseResult<EnumValueDescriptor> {
        self.read_colon("enum")?;

        // TODO: read integer?
        let ident = self.tokenizer.next_ident()?;
        let value = match e.value_by_name(&ident) {
            Some(value) => value,
            None => return Err(ParseErrorWithoutLoc::UnknownEnumValue(ident)),
        };
        Ok(value)
    }

    fn read_u64(&mut self) -> ParseResult<u64> {
        self.read_colon("u64")?;

        Ok(self.tokenizer.next_int_lit()?)
    }

    fn read_u32(&mut self) -> ParseResult<u32> {
        self.read_colon("int value")?;

        let int_lit = self.tokenizer.next_int_lit()?;
        let value_u32 = int_lit as u32;
        if value_u32 as u64 != int_lit {
            return Err(ParseErrorWithoutLoc::IntegerOverflow);
        }
        Ok(value_u32)
    }

    fn read_i64(&mut self) -> ParseResult<i64> {
        self.read_colon("int value")?;

        if self.tokenizer.next_symbol_if_eq('-')? {
            let int_lit = self.tokenizer.next_int_lit()?;
            Ok(int::neg(int_lit)?)
        } else {
            let int_lit = self.tokenizer.next_int_lit()?;
            if int_lit > i64::MAX as u64 {
                return Err(ParseErrorWithoutLoc::IntegerOverflow);
            }
            Ok(int_lit as i64)
        }
    }

    fn read_i32(&mut self) -> ParseResult<i32> {
        let value = self.read_i64()?;
        if value < i32::min_value() as i64 || value > i32::max_value() as i64 {
            return Err(ParseErrorWithoutLoc::IntegerOverflow);
        }
        Ok(value as i32)
    }

    fn read_f64(&mut self) -> ParseResult<f64> {
        self.read_colon("float value")?;

        let minus = self.tokenizer.next_symbol_if_eq('-')?;

        let value = if let Ok(value) = self.tokenizer.next_int_lit() {
            value as f64
        } else {
            self.tokenizer.next_float_lit()?
        };

        Ok(if minus { -value } else { value })
    }

    fn read_f32(&mut self) -> ParseResult<f32> {
        Ok(self.read_f64()? as f32)
    }

    fn read_bool(&mut self) -> ParseResult<bool> {
        self.read_colon("bool value")?;

        if self.tokenizer.next_ident_if_eq("true")? {
            Ok(true)
        } else if self.tokenizer.next_ident_if_eq("false")? {
            Ok(false)
        } else {
            Err(ParseErrorWithoutLoc::ExpectingBool)
        }
    }

    fn read_string(&mut self) -> ParseResult<String> {
        self.read_colon("string value")?;

        Ok(self
            .tokenizer
            .next_str_lit()
            .and_then(|s| s.decode_utf8().map_err(From::from))?)
    }

    fn read_bytes(&mut self) -> ParseResult<Vec<u8>> {
        self.read_colon("bytes value")?;

        Ok(self
            .tokenizer
            .next_str_lit()
            .and_then(|s| s.decode_bytes().map_err(From::from))?)
    }

    fn read_message(&mut self, descriptor: &MessageDescriptor) -> ParseResult<Box<dyn MessageDyn>> {
        let mut message = descriptor.new_instance();

        let symbol = self.tokenizer.next_symbol_expect_eq_oneof(&['{', '<'])?;
        let terminator = if symbol == '{' { '}' } else { '>' };
        while !self.tokenizer.lookahead_is_symbol(terminator)? {
            self.merge_field(&mut *message, descriptor)?;
        }
        self.tokenizer
            .next_symbol_expect_eq(terminator, "message")?;
        Ok(message)
    }

    fn read_map_entry(
        &mut self,
        k: &RuntimeTypeBox,
        v: &RuntimeTypeBox,
    ) -> ParseResult<(ReflectValueBox, ReflectValueBox)> {
        let key_field_name: &str = "key";
        let value_field_name: &str = "value";

        let mut key = None;
        let mut value = None;
        self.tokenizer.next_symbol_expect_eq('{', "map entry")?;
        while !self.tokenizer.lookahead_is_symbol('}')? {
            let ident = self.next_field_name()?;
            let (field, field_type) = if ident == key_field_name {
                (&mut key, k)
            } else if ident == value_field_name {
                (&mut value, v)
            } else {
                return Err(ParseErrorWithoutLoc::UnknownField(ident));
            };

            if let Some(..) = *field {
                return Err(ParseErrorWithoutLoc::MapFieldIsSpecifiedMoreThanOnce(ident));
            }

            let field_value = self.read_value_of_type(field_type)?;

            *field = Some(field_value);
        }
        self.tokenizer.next_symbol_expect_eq('}', "map entry")?;
        let key = match key {
            Some(key) => key,
            None => k.default_value_ref().to_box(),
        };
        let value = match value {
            Some(value) => value,
            None => v.default_value_ref().to_box(),
        };
        Ok((key, value))
    }

    fn read_value_of_type(&mut self, t: &RuntimeTypeBox) -> ParseResult<ReflectValueBox> {
        Ok(match t {
            RuntimeTypeBox::Enum(d) => {
                let value = self.read_enum(&d)?.value();
                ReflectValueBox::Enum(d.clone(), value)
            }
            RuntimeTypeBox::U32 => ReflectValueBox::U32(self.read_u32()?),
            RuntimeTypeBox::U64 => ReflectValueBox::U64(self.read_u64()?),
            RuntimeTypeBox::I32 => ReflectValueBox::I32(self.read_i32()?),
            RuntimeTypeBox::I64 => ReflectValueBox::I64(self.read_i64()?),
            RuntimeTypeBox::F32 => ReflectValueBox::F32(self.read_f32()?),
            RuntimeTypeBox::F64 => ReflectValueBox::F64(self.read_f64()?),
            RuntimeTypeBox::Bool => ReflectValueBox::Bool(self.read_bool()?),
            RuntimeTypeBox::String => ReflectValueBox::String(self.read_string()?),
            RuntimeTypeBox::VecU8 => ReflectValueBox::Bytes(self.read_bytes()?),
            RuntimeTypeBox::Message(m) => ReflectValueBox::Message(self.read_message(&m)?),
        })
    }

    fn merge_field(
        &mut self,
        message: &mut dyn MessageDyn,
        descriptor: &MessageDescriptor,
    ) -> ParseResult<()> {
        let field_name = self.next_field_name()?;

        let field = match descriptor.field_by_name(&field_name) {
            Some(field) => field,
            None => {
                // TODO: shouldn't unknown fields be quietly skipped?
                return Err(ParseErrorWithoutLoc::UnknownField(field_name));
            }
        };

        match field.runtime_field_type() {
            RuntimeFieldType::Singular(t) => {
                let value = self.read_value_of_type(&t)?;
                field.set_singular_field(message, value);
            }
            RuntimeFieldType::Repeated(t) => {
                let value = self.read_value_of_type(&t)?;
                field.mut_repeated(message).push(value);
            }
            RuntimeFieldType::Map(k, v) => {
                let (k, v) = self.read_map_entry(&k, &v)?;
                field.mut_map(message).insert(k, v);
            }
        };

        Ok(())
    }

    fn merge_inner(&mut self, message: &mut dyn MessageDyn) -> ParseResult<()> {
        loop {
            if self.tokenizer.syntax_eof()? {
                break;
            }
            let descriptor = message.descriptor_dyn();
            self.merge_field(message, &descriptor)?;
        }
        Ok(())
    }

    fn merge(&mut self, message: &mut dyn MessageDyn) -> ParseWithLocResult<()> {
        match self.merge_inner(message) {
            Ok(()) => Ok(()),
            Err(error) => Err(ParseError {
                error,
                loc: self.tokenizer.loc(),
            }),
        }
    }
}

/// Parse text format message.
///
/// This function does not check if message required fields are set.
pub fn merge_from_str(message: &mut dyn MessageDyn, input: &str) -> ParseWithLocResult<()> {
    let mut parser = Parser {
        tokenizer: Tokenizer::new(input, ParserLanguage::TextFormat),
    };
    parser.merge(message)
}

/// Parse text format message.
pub fn parse_from_str<M: MessageFull>(input: &str) -> ParseWithLocResult<M> {
    let mut m = M::new();
    merge_from_str(&mut m, input)?;
    if let Err(_) = m.check_initialized() {
        return Err(ParseError {
            error: ParseErrorWithoutLoc::MessageNotInitialized,
            loc: Loc::start(),
        });
    }
    Ok(m)
}
<|endoftext|>