<commit_before>use std::io::Write;
use std::any::Any;

use hyper::status::StatusCode;
use hyper::header::{Header, HeaderFormat, HeaderFormatter};
use hyper::header::{ContentLength, TransferEncoding, Encoding};

use super::{Response, ResponseImpl};

quick_error! {
    #[derive(Debug)]
    pub enum HeaderError {
        DuplicateContentLength {
            description("Content-Length is added twice")
        }
        DuplicateTransferEncoding {
            description("Transfer-Encoding is added twice")
        }
        TransferEncodingAfterContentLength {
            description("Transfer encoding added when Content-Length is \
                already specified")
        }
        ContentLengthAfterTransferEncoding {
            description("Content-Length added after Transfer-Encoding")
        }
        UnknownTransferEncoding {
            description("Unknown Transfer-Encoding, only chunked is supported")
        }
        CantDetermineBodySize {
            description("Neither Content-Length nor TransferEncoding \
                is present in the headers")
        }
    }
}

/// This response is returned when Response is dropping without writing
/// anything to the buffer. In any real scenario this page must never appear.
/// If it is, this probably means there is a bug somewhere. For example,
/// emit_error_page has returned without creating a real error response.
pub const NOT_IMPLEMENTED_HEAD: &'static str = concat!(
    "HTTP/1.0 501 Not Implemented\r\n",
    "Content-Type: text/plain\r\n",
    "Content-Length: 22\r\n",
    "\r\n",
    "501 Not Implemented\r\n",
    );
pub const NOT_IMPLEMENTED: &'static str = concat!(
    "HTTP/1.0 501 Not Implemented\r\n",
    "Content-Type: text/plain\r\n",
    "Content-Length: 22\r\n",
    "\r\n",
    );

impl<'a> Response<'a> {
    /// Write status line
    ///
    /// This puts status line into a buffer immediately. If you don't
    /// continue with request it will be sent to the network shortly.
    ///
    /// # Panics
    ///
    /// When status line is already written. It's expected that your request
    /// handler state machine will never call the method twice.
    ///
    /// When status is 100x
    pub fn status(&mut self, code: StatusCode) {
        use hyper::status::StatusCode::*;
        use super::ResponseBody::*;
        use super::ResponseImpl::*;
        match self.1 {
            Start { version, mut body } => {
                // Note we don't expect code 100 and 102 here, but
                // we don't assert on that for now. The point is that
                // responses 100 and 102 are interim. 100 is generated by
                // rotor-http itself and 102 should probably too. Or we
                // will have a special method in request for it, because
                // request will contain another (real) response status here.
                //
                // TODO(tailhook) should we assert?
                //
                write!(self.0, "{:03} {} {}\r\n", code,
                    code.canonical_reason().unwrap_or("Unknown"),
                    version).unwrap();
                if matches!(code, SwitchingProtocols|NoContent) {
                    body = Denied;
                } else if body == Normal && code == NotModified {
                    body = Ignored;
                }
                self.1 = Headers { body: body,
                                   content_length: None, chunked: false };
            }
            ref state => {
                panic!("Called status() method on response in a state {:?}",
                       state)
            }
        }
    }
    // Add header to response
    //
    // Header is written into the output buffer immediately. And is sent
    // as soon as the next loop iteration
    //
    // Fails when invalid combination of headers is encountered. Note we
    // don't validate all the headers but only security-related ones like
    // double content-length and content-length with the combination of
    // transfer-encoding.
    //
    // We return Result here to make implementing proxies easier. In the
    // application handler it's okay to unwrap the result and to get
    // a meaningful panic (that is basically an assertion).
    //
    // # Panics
    //
    // * Panics when add_header is called in the wrong state.
    // * Panics on unsupported transfer encoding
    //
    pub fn add_header<H: Header+HeaderFormat>(&mut self, header: H)
        -> Result<(), HeaderError>
    {
        use super::ResponseImpl::*;
        use self::HeaderError::*;
        match self.1 {
            Headers { ref mut content_length, ref mut chunked, .. } => {
                match Any::downcast_ref::<ContentLength>(&header) {
                    Some(&ContentLength(ln)) => {
                        if *chunked {
                            return Err(ContentLengthAfterTransferEncoding);
                        }
                        if content_length.is_some() {
                            return Err(DuplicateContentLength);
                        }
                        *content_length = Some(ln);
                    }
                    None => {}
                }
                match Any::downcast_ref::<TransferEncoding>(&header) {
                    Some(te) if te[..] == [Encoding::Chunked] => {
                        if *chunked {
                            return Err(DuplicateTransferEncoding);
                        }
                        if content_length.is_some() {
                            return Err(TransferEncodingAfterContentLength);
                        }
                        *chunked = true;
                    }
                    Some(_) => {
                        return Err(UnknownTransferEncoding);
                    }
                    None => {}
                }
                write!(self.0, "{}", HeaderFormatter(&header)).unwrap();
                Ok(())
            }
            ref state => {
                panic!("Called add_header() method on response in a state {:?}",
                       state)
            }
        }
    }
    /// Returns true if at least `status()` method has been called
    ///
    /// This is mostly useful to find out whether we can build an error page
    /// or it's already too late.
    pub fn is_started(&self) -> bool {
        !matches!(self.1, ResponseImpl::Start { .. })
    }
    /// Checks the validity of headers. And returns `true` if entity
    /// body is expected.
    ///
    /// Specifically `false` is returned when status is 101, 204, 304 or the
    /// request is HEAD. Which means in both cases where response body is
    /// either ignored (304, HEAD) or is denied by specification. But not
    /// when response is zero-length.
    ///
    /// Similarly to `add_header()` it's fine to `unwrap()` here, unless you're
    /// doing some proxying.
    ///
    /// # Panics
    ///
    /// Panics when response is in a wrong state
    pub fn done_headers(&mut self) -> Result<bool, HeaderError> {
        use super::ResponseBody::*;
        use super::ResponseImpl::*;
        match self.1 {
            Start { .. } => {
                panic!("Trying to send headers, but no response status yet");
            }
            Headers { body: Ignored, .. } => {
                self.1 = IgnoredBody;
                Ok(false)
            }
            Headers { body: Denied, .. } => {
                self.1 = ZeroBodyResponse;
                Ok(false)
            }
            Headers { body: Normal, content_length: Some(cl), chunked: false }
            => {
                self.1 = FixedSizeBody(cl);
                Ok(true)
            }
            Headers { body: Normal, content_length: None, chunked: true } => {
                self.1 = ChunkedBody;
                Ok(true)
            }
            Headers { body: Normal, content_length: Some(_), chunked: true }
            => unreachable!(),
            Headers { body: Normal, content_length: None, chunked: false } => {
                Err(HeaderError::CantDetermineBodySize)
            }
            ref state => {
                panic!("Called done_headers() method on  in a state {:?}",
                       state)
            }
        }
    }
    /// Write a chunk of the body
    ///
    /// Works both for fixed-size body and chunked body.
    ///
    /// For the chunked body each chunk is put into the buffer immediately
    /// prefixed by chunk size.
    ///
    /// For both modes chunk is put into the buffer, but is only sent when
    /// rotor-stream state machine is reached. So you may put multiple chunks
    /// into the buffer quite efficiently.
    ///
    /// For Ignored body you can `write_body` any number of times, it's just
    /// ignored. But it's more efficient to check it with `needs_body()`
    ///
    /// # Panics
    ///
    /// When response is in wrong state. Or there is no headers which
    /// determine response body length (either Content-Length or
    /// Transfer-Encoding)
    pub fn write_body(&mut self, data: &[u8]) {
        use super::ResponseImpl::*;
        match self.1 {
            ZeroBodyResponse => {
                if data.len() != 0 {
                    panic!("Non-zero data length for the response where \
                            the response body is denied (101, 204)");
                }
            }
            FixedSizeBody(ref mut x) => {
                if data.len() as u64 > *x {
                    panic!("Fixed size response error. \
                        Bytes left {} but got additional {}", x, data.len());
                }
                self.0.write(data).unwrap();
                *x -= data.len() as u64;
            }
            ChunkedBody => {
                write!(self.0, "{:x}\r\n", data.len()).unwrap();
                self.0.write(data).unwrap();
            }
            ref state => {
                panic!("Called write_body() method on response \
                    in a state {:?}", state)
            }
        }
    }
    /// Returns true if `done()` method is already called and everything
    /// was okay.
    pub fn is_complete(&self) -> bool {
        matches!(self.1, ResponseImpl::Done)
    }
    /// Writes needed final finalization data into the buffer and asserts
    /// that response is in the appropriate state for that.
    ///
    /// The method may be called multiple times
    ///
    /// # Panics
    ///
    /// When the response is in the wrong state or when Content-Length bytes
    /// are not written yet
    pub fn done(&mut self) {
        use super::ResponseImpl::*;
        match self.1 {
            ChunkedBody => {
                self.0.write(b"0\r\n").unwrap();
                self.1 = Done;
            }
            FixedSizeBody(0) => {}
            ZeroBodyResponse => {}
            IgnoredBody => {}
            Done => {}  // multiple invocations are okay
            ref state => {
                panic!("Called done() method on response in a state {:?}",
                       state);
            }
        }
    }
}

<commit_msg>Finally got hello world working<commit_after>use std::io::Write;
use std::any::Any;

use hyper::status::StatusCode;
use hyper::header::{Header, HeaderFormat, HeaderFormatter};
use hyper::header::{ContentLength, TransferEncoding, Encoding};

use super::{Response, ResponseImpl};

quick_error! {
    #[derive(Debug)]
    pub enum HeaderError {
        DuplicateContentLength {
            description("Content-Length is added twice")
        }
        DuplicateTransferEncoding {
            description("Transfer-Encoding is added twice")
        }
        TransferEncodingAfterContentLength {
            description("Transfer encoding added when Content-Length is \
                already specified")
        }
        ContentLengthAfterTransferEncoding {
            description("Content-Length added after Transfer-Encoding")
        }
        UnknownTransferEncoding {
            description("Unknown Transfer-Encoding, only chunked is supported")
        }
        CantDetermineBodySize {
            description("Neither Content-Length nor TransferEncoding \
                is present in the headers")
        }
    }
}

/// This response is returned when Response is dropping without writing
/// anything to the buffer. In any real scenario this page must never appear.
/// If it is, this probably means there is a bug somewhere. For example,
/// emit_error_page has returned without creating a real error response.
pub const NOT_IMPLEMENTED_HEAD: &'static str = concat!(
    "HTTP/1.0 501 Not Implemented\r\n",
    "Content-Type: text/plain\r\n",
    "Content-Length: 22\r\n",
    "\r\n",
    "501 Not Implemented\r\n",
    );
pub const NOT_IMPLEMENTED: &'static str = concat!(
    "HTTP/1.0 501 Not Implemented\r\n",
    "Content-Type: text/plain\r\n",
    "Content-Length: 22\r\n",
    "\r\n",
    );

impl<'a> Response<'a> {
    /// Write status line
    ///
    /// This puts status line into a buffer immediately. If you don't
    /// continue with request it will be sent to the network shortly.
    ///
    /// # Panics
    ///
    /// When status line is already written. It's expected that your request
    /// handler state machine will never call the method twice.
    ///
    /// When status is 100x
    pub fn status(&mut self, code: StatusCode) {
        use hyper::status::StatusCode::*;
        use super::ResponseBody::*;
        use super::ResponseImpl::*;
        match self.1 {
            Start { version, mut body } => {
                // Note we don't expect code 100 and 102 here, but
                // we don't assert on that for now. The point is that
                // responses 100 and 102 are interim. 100 is generated by
                // rotor-http itself and 102 should probably too. Or we
                // will have a special method in request for it, because
                // request will contain another (real) response status here.
                //
                // TODO(tailhook) should we assert?
                //
                write!(self.0, "{} {}\r\n", version, code).unwrap();
                if matches!(code, SwitchingProtocols|NoContent) {
                    body = Denied;
                } else if body == Normal && code == NotModified {
                    body = Ignored;
                }
                self.1 = Headers { body: body,
                                   content_length: None, chunked: false };
            }
            ref state => {
                panic!("Called status() method on response in a state {:?}",
                       state)
            }
        }
    }
    // Add header to response
    //
    // Header is written into the output buffer immediately. And is sent
    // as soon as the next loop iteration
    //
    // Fails when invalid combination of headers is encountered. Note we
    // don't validate all the headers but only security-related ones like
    // double content-length and content-length with the combination of
    // transfer-encoding.
    //
    // We return Result here to make implementing proxies easier. In the
    // application handler it's okay to unwrap the result and to get
    // a meaningful panic (that is basically an assertion).
    //
    // # Panics
    //
    // * Panics when add_header is called in the wrong state.
    // * Panics on unsupported transfer encoding
    //
    pub fn add_header<H: Header+HeaderFormat>(&mut self, header: H)
        -> Result<(), HeaderError>
    {
        use super::ResponseImpl::*;
        use self::HeaderError::*;
        match self.1 {
            Headers { ref mut content_length, ref mut chunked, .. } => {
                match Any::downcast_ref::<ContentLength>(&header) {
                    Some(&ContentLength(ln)) => {
                        if *chunked {
                            return Err(ContentLengthAfterTransferEncoding);
                        }
                        if content_length.is_some() {
                            return Err(DuplicateContentLength);
                        }
                        *content_length = Some(ln);
                    }
                    None => {}
                }
                match Any::downcast_ref::<TransferEncoding>(&header) {
                    Some(te) if te[..] == [Encoding::Chunked] => {
                        if *chunked {
                            return Err(DuplicateTransferEncoding);
                        }
                        if content_length.is_some() {
                            return Err(TransferEncodingAfterContentLength);
                        }
                        *chunked = true;
                    }
                    Some(_) => {
                        return Err(UnknownTransferEncoding);
                    }
                    None => {}
                }
                write!(self.0, "{}: {}\r\n",
                    H::header_name(),
                    HeaderFormatter(&header)).unwrap();
                Ok(())
            }
            ref state => {
                panic!("Called add_header() method on response in a state {:?}",
                       state)
            }
        }
    }
    /// Returns true if at least `status()` method has been called
    ///
    /// This is mostly useful to find out whether we can build an error page
    /// or it's already too late.
    pub fn is_started(&self) -> bool {
        !matches!(self.1, ResponseImpl::Start { .. })
    }
    /// Checks the validity of headers. And returns `true` if entity
    /// body is expected.
    ///
    /// Specifically `false` is returned when status is 101, 204, 304 or the
    /// request is HEAD. Which means in both cases where response body is
    /// either ignored (304, HEAD) or is denied by specification. But not
    /// when response is zero-length.
    ///
    /// Similarly to `add_header()` it's fine to `unwrap()` here, unless you're
    /// doing some proxying.
    ///
    /// # Panics
    ///
    /// Panics when response is in a wrong state
    pub fn done_headers(&mut self) -> Result<bool, HeaderError> {
        use super::ResponseBody::*;
        use super::ResponseImpl::*;
        let result = match self.1 {
            Start { .. } => {
                panic!("Trying to send headers, but no response status yet");
            }
            Headers { body: Ignored, .. } => {
                self.1 = IgnoredBody;
                Ok(false)
            }
            Headers { body: Denied, .. } => {
                self.1 = ZeroBodyResponse;
                Ok(false)
            }
            Headers { body: Normal, content_length: Some(cl), chunked: false }
            => {
                self.1 = FixedSizeBody(cl);
                Ok(true)
            }
            Headers { body: Normal, content_length: None, chunked: true } => {
                self.1 = ChunkedBody;
                Ok(true)
            }
            Headers { body: Normal, content_length: Some(_), chunked: true }
            => unreachable!(),
            Headers { body: Normal, content_length: None, chunked: false } => {
                Err(HeaderError::CantDetermineBodySize)
            }
            ref state => {
                panic!("Called done_headers() method on  in a state {:?}",
                       state)
            }
        };
        self.0.write(b"\r\n").unwrap();
        result
    }
    /// Write a chunk of the body
    ///
    /// Works both for fixed-size body and chunked body.
    ///
    /// For the chunked body each chunk is put into the buffer immediately
    /// prefixed by chunk size.
    ///
    /// For both modes chunk is put into the buffer, but is only sent when
    /// rotor-stream state machine is reached. So you may put multiple chunks
    /// into the buffer quite efficiently.
    ///
    /// For Ignored body you can `write_body` any number of times, it's just
    /// ignored. But it's more efficient to check it with `needs_body()`
    ///
    /// # Panics
    ///
    /// When response is in wrong state. Or there is no headers which
    /// determine response body length (either Content-Length or
    /// Transfer-Encoding)
    pub fn write_body(&mut self, data: &[u8]) {
        use super::ResponseImpl::*;
        match self.1 {
            ZeroBodyResponse => {
                if data.len() != 0 {
                    panic!("Non-zero data length for the response where \
                            the response body is denied (101, 204)");
                }
            }
            FixedSizeBody(ref mut x) => {
                if data.len() as u64 > *x {
                    panic!("Fixed size response error. \
                        Bytes left {} but got additional {}", x, data.len());
                }
                self.0.write(data).unwrap();
                *x -= data.len() as u64;
            }
            ChunkedBody => {
                write!(self.0, "{:x}\r\n", data.len()).unwrap();
                self.0.write(data).unwrap();
            }
            ref state => {
                panic!("Called write_body() method on response \
                    in a state {:?}", state)
            }
        }
    }
    /// Returns true if `done()` method is already called and everything
    /// was okay.
    pub fn is_complete(&self) -> bool {
        matches!(self.1, ResponseImpl::Done)
    }
    /// Writes needed final finalization data into the buffer and asserts
    /// that response is in the appropriate state for that.
    ///
    /// The method may be called multiple times
    ///
    /// # Panics
    ///
    /// When the response is in the wrong state or when Content-Length bytes
    /// are not written yet
    pub fn done(&mut self) {
        use super::ResponseImpl::*;
        match self.1 {
            ChunkedBody => {
                self.0.write(b"0\r\n").unwrap();
                self.1 = Done;
            }
            FixedSizeBody(0) => {}
            ZeroBodyResponse => {}
            IgnoredBody => {}
            Done => {}  // multiple invocations are okay
            ref state => {
                panic!("Called done() method on response in a state {:?}",
                       state);
            }
        }
    }
}

<|endoftext|>


<commit_before>use super::*;

fn same(fmt: &'static str, p: &[Piece<'static>]) {
    let parser = Parser::new(fmt, None, vec![], false);
    assert!(parser.collect::<Vec<Piece<'static>>>() == p);
}

fn fmtdflt() -> FormatSpec<'static> {
    return FormatSpec {
        fill: None,
        align: AlignUnknown,
        flags: 0,
        precision: CountImplied,
        width: CountImplied,
        ty: "",
    };
}

fn musterr(s: &str) {
    let mut p = Parser::new(s, None, vec![], false);
    p.next();
    assert!(!p.errors.is_empty());
}

#[test]
fn simple() {
    same("asdf", &[String("asdf")]);
    same("a{{b", &[String("a"), String("{b")]);
    same("a}}b", &[String("a"), String("}b")]);
    same("a}}", &[String("a"), String("}")]);
    same("}}", &[String("}")]);
    same("\\}}", &[String("\\"), String("}")]);
}

#[test]
fn invalid01() {
    musterr("{")
}
#[test]
fn invalid02() {
    musterr("}")
}
#[test]
fn invalid04() {
    musterr("{3a}")
}
#[test]
fn invalid05() {
    musterr("{:|}")
}
#[test]
fn invalid06() {
    musterr("{:>>>}")
}

#[test]
fn format_nothing() {
    same("{}",
         &[NextArgument(Argument {
               position: ArgumentImplicitlyIs(0),
               format: fmtdflt(),
           })]);
}
#[test]
fn format_position() {
    same("{3}",
         &[NextArgument(Argument {
               position: ArgumentIs(3),
               format: fmtdflt(),
           })]);
}
#[test]
fn format_position_nothing_else() {
    same("{3:}",
         &[NextArgument(Argument {
               position: ArgumentIs(3),
               format: fmtdflt(),
           })]);
}
#[test]
fn format_type() {
    same("{3:a}",
         &[NextArgument(Argument {
               position: ArgumentIs(3),
               format: FormatSpec {
                   fill: None,
                   align: AlignUnknown,
                   flags: 0,
                   precision: CountImplied,
                   width: CountImplied,
                   ty: "a",
               },
           })]);
}
#[test]
fn format_align_fill() {
    same("{3:>}",
         &[NextArgument(Argument {
               position: ArgumentIs(3),
               format: FormatSpec {
                   fill: None,
                   align: AlignRight,
                   flags: 0,
                   precision: CountImplied,
                   width: CountImplied,
                   ty: "",
               },
           })]);
    same("{3:0<}",
         &[NextArgument(Argument {
               position: ArgumentIs(3),
               format: FormatSpec {
                   fill: Some('0'),
                   align: AlignLeft,
                   flags: 0,
                   precision: CountImplied,
                   width: CountImplied,
                   ty: "",
               },
           })]);
    same("{3:*<abcd}",
         &[NextArgument(Argument {
               position: ArgumentIs(3),
               format: FormatSpec {
                   fill: Some('*'),
                   align: AlignLeft,
                   flags: 0,
                   precision: CountImplied,
                   width: CountImplied,
                   ty: "abcd",
               },
           })]);
}
#[test]
fn format_counts() {
    use syntax_pos::{GLOBALS, Globals, edition};
    GLOBALS.set(&Globals::new(edition::DEFAULT_EDITION), || {
    same("{:10s}",
         &[NextArgument(Argument {
               position: ArgumentImplicitlyIs(0),
               format: FormatSpec {
                   fill: None,
                   align: AlignUnknown,
                   flags: 0,
                   precision: CountImplied,
                   width: CountIs(10),
                   ty: "s",
               },
           })]);
    same("{:10$.10s}",
         &[NextArgument(Argument {
               position: ArgumentImplicitlyIs(0),
               format: FormatSpec {
                   fill: None,
                   align: AlignUnknown,
                   flags: 0,
                   precision: CountIs(10),
                   width: CountIsParam(10),
                   ty: "s",
               },
           })]);
    same("{:.*s}",
         &[NextArgument(Argument {
               position: ArgumentImplicitlyIs(1),
               format: FormatSpec {
                   fill: None,
                   align: AlignUnknown,
                   flags: 0,
                   precision: CountIsParam(0),
                   width: CountImplied,
                   ty: "s",
               },
           })]);
    same("{:.10$s}",
         &[NextArgument(Argument {
               position: ArgumentImplicitlyIs(0),
               format: FormatSpec {
                   fill: None,
                   align: AlignUnknown,
                   flags: 0,
                   precision: CountIsParam(10),
                   width: CountImplied,
                   ty: "s",
               },
           })]);
    same("{:a$.b$s}",
         &[NextArgument(Argument {
               position: ArgumentImplicitlyIs(0),
               format: FormatSpec {
                   fill: None,
                   align: AlignUnknown,
                   flags: 0,
                   precision: CountIsName(Symbol::intern("b")),
                   width: CountIsName(Symbol::intern("a")),
                   ty: "s",
               },
           })]);
    });
}
#[test]
fn format_flags() {
    same("{:-}",
         &[NextArgument(Argument {
               position: ArgumentImplicitlyIs(0),
               format: FormatSpec {
                   fill: None,
                   align: AlignUnknown,
                   flags: (1 << FlagSignMinus as u32),
                   precision: CountImplied,
                   width: CountImplied,
                   ty: "",
               },
           })]);
    same("{:+#}",
         &[NextArgument(Argument {
               position: ArgumentImplicitlyIs(0),
               format: FormatSpec {
                   fill: None,
                   align: AlignUnknown,
                   flags: (1 << FlagSignPlus as u32) | (1 << FlagAlternate as u32),
                   precision: CountImplied,
                   width: CountImplied,
                   ty: "",
               },
           })]);
}
#[test]
fn format_mixture() {
    same("abcd {3:a} efg",
         &[String("abcd "),
           NextArgument(Argument {
               position: ArgumentIs(3),
               format: FormatSpec {
                   fill: None,
                   align: AlignUnknown,
                   flags: 0,
                   precision: CountImplied,
                   width: CountImplied,
                   ty: "a",
               },
           }),
           String(" efg")]);
}
<commit_msg>fix tests<commit_after>use super::*;

fn same(fmt: &'static str, p: &[Piece<'static>]) {
    let parser = Parser::new(fmt, None, vec![], false);
    assert!(parser.collect::<Vec<Piece<'static>>>() == p);
}

fn fmtdflt() -> FormatSpec<'static> {
    return FormatSpec {
        fill: None,
        align: AlignUnknown,
        flags: 0,
        precision: CountImplied,
        width: CountImplied,
        precision_span: None,
        width_span: None,
        ty: "",
    };
}

fn musterr(s: &str) {
    let mut p = Parser::new(s, None, vec![], false);
    p.next();
    assert!(!p.errors.is_empty());
}

#[test]
fn simple() {
    same("asdf", &[String("asdf")]);
    same("a{{b", &[String("a"), String("{b")]);
    same("a}}b", &[String("a"), String("}b")]);
    same("a}}", &[String("a"), String("}")]);
    same("}}", &[String("}")]);
    same("\\}}", &[String("\\"), String("}")]);
}

#[test]
fn invalid01() {
    musterr("{")
}
#[test]
fn invalid02() {
    musterr("}")
}
#[test]
fn invalid04() {
    musterr("{3a}")
}
#[test]
fn invalid05() {
    musterr("{:|}")
}
#[test]
fn invalid06() {
    musterr("{:>>>}")
}

#[test]
fn format_nothing() {
    same("{}",
         &[NextArgument(Argument {
               position: ArgumentImplicitlyIs(0),
               format: fmtdflt(),
           })]);
}
#[test]
fn format_position() {
    same("{3}",
         &[NextArgument(Argument {
               position: ArgumentIs(3),
               format: fmtdflt(),
           })]);
}
#[test]
fn format_position_nothing_else() {
    same("{3:}",
         &[NextArgument(Argument {
               position: ArgumentIs(3),
               format: fmtdflt(),
           })]);
}
#[test]
fn format_type() {
    same(
        "{3:a}",
        &[NextArgument(Argument {
            position: ArgumentIs(3),
            format: FormatSpec {
                fill: None,
                align: AlignUnknown,
                flags: 0,
                precision: CountImplied,
                width: CountImplied,
                precision_span: None,
                width_span: None,
                ty: "a",
            },
        })]);
}
#[test]
fn format_align_fill() {
    same(
        "{3:>}",
        &[NextArgument(Argument {
            position: ArgumentIs(3),
            format: FormatSpec {
                fill: None,
                align: AlignRight,
                flags: 0,
                precision: CountImplied,
                width: CountImplied,
                precision_span: None,
                width_span: None,
                ty: "",
            },
        })]);
    same(
        "{3:0<}",
        &[NextArgument(Argument {
            position: ArgumentIs(3),
            format: FormatSpec {
                fill: Some('0'),
                align: AlignLeft,
                flags: 0,
                precision: CountImplied,
                width: CountImplied,
                precision_span: None,
                width_span: None,
                ty: "",
            },
        })]);
    same(
        "{3:*<abcd}",
        &[NextArgument(Argument {
            position: ArgumentIs(3),
            format: FormatSpec {
                fill: Some('*'),
                align: AlignLeft,
                flags: 0,
                precision: CountImplied,
                width: CountImplied,
                precision_span: None,
                width_span: None,
                ty: "abcd",
            },
        })]);
}
#[test]
fn format_counts() {
    use syntax_pos::{GLOBALS, Globals, edition};
    GLOBALS.set(&Globals::new(edition::DEFAULT_EDITION), || {
    same(
        "{:10s}",
        &[NextArgument(Argument {
            position: ArgumentImplicitlyIs(0),
            format: FormatSpec {
                fill: None,
                align: AlignUnknown,
                flags: 0,
                precision: CountImplied,
                width: CountIs(10),
                precision_span: None,
                width_span: None,
                ty: "s",
            },
        })]);
    same(
        "{:10$.10s}",
        &[NextArgument(Argument {
            position: ArgumentImplicitlyIs(0),
            format: FormatSpec {
                fill: None,
                align: AlignUnknown,
                flags: 0,
                precision: CountIs(10),
                width: CountIsParam(10),
                precision_span: None,
                width_span: Some(InnerSpan::new(3, 6)),
                ty: "s",
            },
        })]);
    same(
        "{:.*s}",
        &[NextArgument(Argument {
            position: ArgumentImplicitlyIs(1),
            format: FormatSpec {
                fill: None,
                align: AlignUnknown,
                flags: 0,
                precision: CountIsParam(0),
                width: CountImplied,
                precision_span: Some(InnerSpan::new(3, 5)),
                width_span: None,
                ty: "s",
            },
        })]);
    same(
        "{:.10$s}",
        &[NextArgument(Argument {
            position: ArgumentImplicitlyIs(0),
            format: FormatSpec {
                fill: None,
                align: AlignUnknown,
                flags: 0,
                precision: CountIsParam(10),
                width: CountImplied,
                precision_span: Some(InnerSpan::new(3, 7)),
                width_span: None,
                ty: "s",
            },
        })]);
    same(
        "{:a$.b$s}",
        &[NextArgument(Argument {
            position: ArgumentImplicitlyIs(0),
            format: FormatSpec {
                fill: None,
                align: AlignUnknown,
                flags: 0,
                precision: CountIsName(Symbol::intern("b")),
                width: CountIsName(Symbol::intern("a")),
                precision_span: None,
                width_span: None,
                ty: "s",
            },
        })]);
    });
}
#[test]
fn format_flags() {
    same(
        "{:-}",
        &[NextArgument(Argument {
            position: ArgumentImplicitlyIs(0),
            format: FormatSpec {
                fill: None,
                align: AlignUnknown,
                flags: (1 << FlagSignMinus as u32),
                precision: CountImplied,
                width: CountImplied,
                precision_span: None,
                width_span: None,
                ty: "",
            },
        })]);
    same(
        "{:+#}",
        &[NextArgument(Argument {
            position: ArgumentImplicitlyIs(0),
            format: FormatSpec {
                fill: None,
                align: AlignUnknown,
                flags: (1 << FlagSignPlus as u32) | (1 << FlagAlternate as u32),
                precision: CountImplied,
                width: CountImplied,
                precision_span: None,
                width_span: None,
                ty: "",
            },
        })]);
}
#[test]
fn format_mixture() {
    same(
        "abcd {3:a} efg",
        &[
            String("abcd "),
            NextArgument(Argument {
                position: ArgumentIs(3),
                format: FormatSpec {
                    fill: None,
                    align: AlignUnknown,
                    flags: 0,
                    precision: CountImplied,
                    width: CountImplied,
                    precision_span: None,
                    width_span: None,
                    ty: "a",
                },
            }),
            String(" efg"),
        ],
    );
}
<|endoftext|>


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

use build::{Location, ScopeAuxiliaryVec, ScopeId};
use rustc::hir;
use rustc::mir::repr::*;
use rustc::mir::transform::MirSource;
use rustc::ty::{self, TyCtxt};
use rustc_data_structures::fnv::FnvHashMap;
use rustc_data_structures::indexed_vec::{Idx};
use std::fmt::Display;
use std::fs;
use std::io::{self, Write};
use syntax::ast::NodeId;

const INDENT: &'static str = "    ";
/// Alignment for lining up comments following MIR statements
const ALIGN: usize = 40;

/// If the session is properly configured, dumps a human-readable
/// representation of the mir into:
///
/// ```text
/// rustc.node<node_id>.<pass_name>.<disambiguator>
/// ```
///
/// Output from this function is controlled by passing `-Z dump-mir=<filter>`,
/// where `<filter>` takes the following forms:
///
/// - `all` -- dump MIR for all fns, all passes, all everything
/// - `substring1&substring2,...` -- `&`-separated list of substrings
///   that can appear in the pass-name or the `item_path_str` for the given
///   node-id. If any one of the substrings match, the data is dumped out.
pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                          pass_name: &str,
                          disambiguator: &Display,
                          src: MirSource,
                          mir: &Mir<'tcx>,
                          auxiliary: Option<&ScopeAuxiliaryVec>) {
    let filters = match tcx.sess.opts.debugging_opts.dump_mir {
        None => return,
        Some(ref filters) => filters,
    };
    let node_id = src.item_id();
    let node_path = tcx.item_path_str(tcx.map.local_def_id(node_id));
    let is_matched =
        filters.split("&")
               .any(|filter| {
                   filter == "all" ||
                       pass_name.contains(filter) ||
                       node_path.contains(filter)
               });
    if !is_matched {
        return;
    }

    let promotion_id = match src {
        MirSource::Promoted(_, id) => format!("-{:?}", id),
        _ => String::new()
    };

    let file_name = format!("rustc.node{}{}.{}.{}.mir",
                            node_id, promotion_id, pass_name, disambiguator);
    let _ = fs::File::create(&file_name).and_then(|mut file| {
        try!(writeln!(file, "// MIR for `{}`", node_path));
        try!(writeln!(file, "// node_id = {}", node_id));
        try!(writeln!(file, "// pass_name = {}", pass_name));
        try!(writeln!(file, "// disambiguator = {}", disambiguator));
        try!(writeln!(file, ""));
        try!(write_mir_fn(tcx, src, mir, &mut file, auxiliary));
        Ok(())
    });
}

/// Write out a human-readable textual representation for the given MIR.
pub fn write_mir_pretty<'a, 'b, 'tcx, I>(tcx: TyCtxt<'b, 'tcx, 'tcx>,
                                         iter: I,
                                         w: &mut Write)
                                         -> io::Result<()>
    where I: Iterator<Item=(&'a NodeId, &'a Mir<'tcx>)>, 'tcx: 'a
{
    let mut first = true;
    for (&id, mir) in iter {
        if first {
            first = false;
        } else {
            // Put empty lines between all items
            writeln!(w, "")?;
        }

        let src = MirSource::from_node(tcx, id);
        write_mir_fn(tcx, src, mir, w, None)?;

        for (i, mir) in mir.promoted.iter_enumerated() {
            writeln!(w, "")?;
            write_mir_fn(tcx, MirSource::Promoted(id, i), mir, w, None)?;
        }
    }
    Ok(())
}

enum Annotation {
    EnterScope(ScopeId),
    ExitScope(ScopeId),
}

fn scope_entry_exit_annotations(auxiliary: Option<&ScopeAuxiliaryVec>)
                                -> FnvHashMap<Location, Vec<Annotation>>
{
    // compute scope/entry exit annotations
    let mut annotations = FnvHashMap();
    if let Some(auxiliary) = auxiliary {
        for (scope_id, auxiliary) in auxiliary.iter_enumerated() {
            annotations.entry(auxiliary.dom)
                       .or_insert(vec![])
                       .push(Annotation::EnterScope(scope_id));

            for &loc in &auxiliary.postdoms {
                annotations.entry(loc)
                           .or_insert(vec![])
                           .push(Annotation::ExitScope(scope_id));
            }
        }
    }
    return annotations;
}

pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              src: MirSource,
                              mir: &Mir<'tcx>,
                              w: &mut Write,
                              auxiliary: Option<&ScopeAuxiliaryVec>)
                              -> io::Result<()> {
    let annotations = scope_entry_exit_annotations(auxiliary);
    write_mir_intro(tcx, src, mir, w)?;
    for block in mir.basic_blocks().indices() {
        write_basic_block(tcx, block, mir, w, &annotations)?;
        if block.index() + 1 != mir.basic_blocks().len() {
            writeln!(w, "")?;
        }
    }

    writeln!(w, "}}")?;
    Ok(())
}

/// Write out a human-readable textual representation for the given basic block.
fn write_basic_block(tcx: TyCtxt,
                     block: BasicBlock,
                     mir: &Mir,
                     w: &mut Write,
                     annotations: &FnvHashMap<Location, Vec<Annotation>>)
                     -> io::Result<()> {
    let data = &mir[block];

    // Basic block label at the top.
    writeln!(w, "{}{:?}: {{", INDENT, block)?;

    // List of statements in the middle.
    let mut current_location = Location { block: block, statement_index: 0 };
    for statement in &data.statements {
        if let Some(ref annotations) = annotations.get(&current_location) {
            for annotation in annotations.iter() {
                match *annotation {
                    Annotation::EnterScope(id) =>
                        writeln!(w, "{0}{0}// Enter Scope({1})",
                                 INDENT, id.index())?,
                    Annotation::ExitScope(id) =>
                        writeln!(w, "{0}{0}// Exit Scope({1})",
                                 INDENT, id.index())?,
                }
            }
        }

        let indented_mir = format!("{0}{0}{1:?};", INDENT, statement);
        writeln!(w, "{0:1$} // {2}",
                 indented_mir,
                 ALIGN,
                 comment(tcx, statement.source_info))?;

        current_location.statement_index += 1;
    }

    // Terminator at the bottom.
    let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind);
    writeln!(w, "{0:1$} // {2}",
             indented_terminator,
             ALIGN,
             comment(tcx, data.terminator().source_info))?;

    writeln!(w, "{}}}\n", INDENT)
}

fn comment(tcx: TyCtxt, SourceInfo { span, scope }: SourceInfo) -> String {
    format!("scope {} at {}", scope.index(), tcx.sess.codemap().span_to_string(span))
}

fn write_scope_tree(tcx: TyCtxt,
                    mir: &Mir,
                    scope_tree: &FnvHashMap<VisibilityScope, Vec<VisibilityScope>>,
                    w: &mut Write,
                    parent: VisibilityScope,
                    depth: usize)
                    -> io::Result<()> {
    let indent = depth * INDENT.len();

    let children = match scope_tree.get(&parent) {
        Some(childs) => childs,
        None => return Ok(()),
    };

    for &child in children {
        let data = &mir.visibility_scopes[child];
        assert_eq!(data.parent_scope, Some(parent));
        writeln!(w, "{0:1$}scope {2} {{", "", indent, child.index())?;

        // User variable types (including the user's name in a comment).
        for (id, var) in mir.var_decls.iter_enumerated() {
            // Skip if not declared in this scope.
            if var.source_info.scope != child {
                continue;
            }

            let mut_str = if var.mutability == Mutability::Mut {
                "mut "
            } else {
                ""
            };

            let indent = indent + INDENT.len();
            let indented_var = format!("{0:1$}let {2}{3:?}: {4};",
                                       INDENT,
                                       indent,
                                       mut_str,
                                       id,
                                       var.ty);
            writeln!(w, "{0:1$} // \"{2}\" in {3}",
                     indented_var,
                     ALIGN,
                     var.name,
                     comment(tcx, var.source_info))?;
        }

        write_scope_tree(tcx, mir, scope_tree, w, child, depth + 1)?;

        writeln!(w, "{0:1$}}}", "", depth * INDENT.len())?;
    }

    Ok(())
}

/// Write out a human-readable textual representation of the MIR's `fn` type and the types of its
/// local variables (both user-defined bindings and compiler temporaries).
fn write_mir_intro<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             src: MirSource,
                             mir: &Mir,
                             w: &mut Write)
                             -> io::Result<()> {
    write_mir_sig(tcx, src, mir, w)?;
    writeln!(w, " {{")?;

    // construct a scope tree and write it out
    let mut scope_tree: FnvHashMap<VisibilityScope, Vec<VisibilityScope>> = FnvHashMap();
    for (index, scope_data) in mir.visibility_scopes.iter().enumerate() {
        if let Some(parent) = scope_data.parent_scope {
            scope_tree.entry(parent)
                      .or_insert(vec![])
                      .push(VisibilityScope::new(index));
        } else {
            // Only the argument scope has no parent, because it's the root.
            assert_eq!(index, ARGUMENT_VISIBILITY_SCOPE.index());
        }
    }

    write_scope_tree(tcx, mir, &scope_tree, w, ARGUMENT_VISIBILITY_SCOPE, 1)?;

    write_mir_decls(mir, w)
}

fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write)
                 -> io::Result<()>
{
    match src {
        MirSource::Fn(_) => write!(w, "fn")?,
        MirSource::Const(_) => write!(w, "const")?,
        MirSource::Static(_, hir::MutImmutable) => write!(w, "static")?,
        MirSource::Static(_, hir::MutMutable) => write!(w, "static mut")?,
        MirSource::Promoted(_, i) => write!(w, "{:?} in", i)?
    }

    write!(w, " {}", tcx.node_path_str(src.item_id()))?;

    if let MirSource::Fn(_) = src {
        write!(w, "(")?;

        // fn argument types.
        for (i, arg) in mir.arg_decls.iter_enumerated() {
            if i.index() != 0 {
                write!(w, ", ")?;
            }
            write!(w, "{:?}: {}", Lvalue::Arg(i), arg.ty)?;
        }

        write!(w, ") -> ")?;

        // fn return type.
        match mir.return_ty {
            ty::FnOutput::FnConverging(ty) => write!(w, "{}", ty),
            ty::FnOutput::FnDiverging => write!(w, "!"),
        }
    } else {
        assert!(mir.arg_decls.is_empty());
        write!(w, ": {} =", mir.return_ty.unwrap())
    }
}

fn write_mir_decls(mir: &Mir, w: &mut Write) -> io::Result<()> {
    // Compiler-introduced temporary types.
    for (id, temp) in mir.temp_decls.iter_enumerated() {
        writeln!(w, "{}let mut {:?}: {};", INDENT, id, temp.ty)?;
    }

    // Wrote any declaration? Add an empty line before the first block is printed.
    if !mir.var_decls.is_empty() || !mir.temp_decls.is_empty() {
        writeln!(w, "")?;
    }

    Ok(())
}
<commit_msg>Rollup merge of #34807 - sanxiyn:dump-mir, r=nagisa<commit_after>// Copyright 2014 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.

use build::{Location, ScopeAuxiliaryVec, ScopeId};
use rustc::hir;
use rustc::mir::repr::*;
use rustc::mir::transform::MirSource;
use rustc::ty::{self, TyCtxt};
use rustc_data_structures::fnv::FnvHashMap;
use rustc_data_structures::indexed_vec::{Idx};
use std::fmt::Display;
use std::fs;
use std::io::{self, Write};
use syntax::ast::NodeId;

const INDENT: &'static str = "    ";
/// Alignment for lining up comments following MIR statements
const ALIGN: usize = 40;

/// If the session is properly configured, dumps a human-readable
/// representation of the mir into:
///
/// ```text
/// rustc.node<node_id>.<pass_name>.<disambiguator>
/// ```
///
/// Output from this function is controlled by passing `-Z dump-mir=<filter>`,
/// where `<filter>` takes the following forms:
///
/// - `all` -- dump MIR for all fns, all passes, all everything
/// - `substring1&substring2,...` -- `&`-separated list of substrings
///   that can appear in the pass-name or the `item_path_str` for the given
///   node-id. If any one of the substrings match, the data is dumped out.
pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                          pass_name: &str,
                          disambiguator: &Display,
                          src: MirSource,
                          mir: &Mir<'tcx>,
                          auxiliary: Option<&ScopeAuxiliaryVec>) {
    let filters = match tcx.sess.opts.debugging_opts.dump_mir {
        None => return,
        Some(ref filters) => filters,
    };
    let node_id = src.item_id();
    let node_path = tcx.item_path_str(tcx.map.local_def_id(node_id));
    let is_matched =
        filters.split("&")
               .any(|filter| {
                   filter == "all" ||
                       pass_name.contains(filter) ||
                       node_path.contains(filter)
               });
    if !is_matched {
        return;
    }

    let promotion_id = match src {
        MirSource::Promoted(_, id) => format!("-{:?}", id),
        _ => String::new()
    };

    let file_name = format!("rustc.node{}{}.{}.{}.mir",
                            node_id, promotion_id, pass_name, disambiguator);
    let _ = fs::File::create(&file_name).and_then(|mut file| {
        try!(writeln!(file, "// MIR for `{}`", node_path));
        try!(writeln!(file, "// node_id = {}", node_id));
        try!(writeln!(file, "// pass_name = {}", pass_name));
        try!(writeln!(file, "// disambiguator = {}", disambiguator));
        try!(writeln!(file, ""));
        try!(write_mir_fn(tcx, src, mir, &mut file, auxiliary));
        Ok(())
    });
}

/// Write out a human-readable textual representation for the given MIR.
pub fn write_mir_pretty<'a, 'b, 'tcx, I>(tcx: TyCtxt<'b, 'tcx, 'tcx>,
                                         iter: I,
                                         w: &mut Write)
                                         -> io::Result<()>
    where I: Iterator<Item=(&'a NodeId, &'a Mir<'tcx>)>, 'tcx: 'a
{
    let mut first = true;
    for (&id, mir) in iter {
        if first {
            first = false;
        } else {
            // Put empty lines between all items
            writeln!(w, "")?;
        }

        let src = MirSource::from_node(tcx, id);
        write_mir_fn(tcx, src, mir, w, None)?;

        for (i, mir) in mir.promoted.iter_enumerated() {
            writeln!(w, "")?;
            write_mir_fn(tcx, MirSource::Promoted(id, i), mir, w, None)?;
        }
    }
    Ok(())
}

enum Annotation {
    EnterScope(ScopeId),
    ExitScope(ScopeId),
}

fn scope_entry_exit_annotations(auxiliary: Option<&ScopeAuxiliaryVec>)
                                -> FnvHashMap<Location, Vec<Annotation>>
{
    // compute scope/entry exit annotations
    let mut annotations = FnvHashMap();
    if let Some(auxiliary) = auxiliary {
        for (scope_id, auxiliary) in auxiliary.iter_enumerated() {
            annotations.entry(auxiliary.dom)
                       .or_insert(vec![])
                       .push(Annotation::EnterScope(scope_id));

            for &loc in &auxiliary.postdoms {
                annotations.entry(loc)
                           .or_insert(vec![])
                           .push(Annotation::ExitScope(scope_id));
            }
        }
    }
    return annotations;
}

pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              src: MirSource,
                              mir: &Mir<'tcx>,
                              w: &mut Write,
                              auxiliary: Option<&ScopeAuxiliaryVec>)
                              -> io::Result<()> {
    let annotations = scope_entry_exit_annotations(auxiliary);
    write_mir_intro(tcx, src, mir, w)?;
    for block in mir.basic_blocks().indices() {
        write_basic_block(tcx, block, mir, w, &annotations)?;
        if block.index() + 1 != mir.basic_blocks().len() {
            writeln!(w, "")?;
        }
    }

    writeln!(w, "}}")?;
    Ok(())
}

/// Write out a human-readable textual representation for the given basic block.
fn write_basic_block(tcx: TyCtxt,
                     block: BasicBlock,
                     mir: &Mir,
                     w: &mut Write,
                     annotations: &FnvHashMap<Location, Vec<Annotation>>)
                     -> io::Result<()> {
    let data = &mir[block];

    // Basic block label at the top.
    writeln!(w, "{}{:?}: {{", INDENT, block)?;

    // List of statements in the middle.
    let mut current_location = Location { block: block, statement_index: 0 };
    for statement in &data.statements {
        if let Some(ref annotations) = annotations.get(&current_location) {
            for annotation in annotations.iter() {
                match *annotation {
                    Annotation::EnterScope(id) =>
                        writeln!(w, "{0}{0}// Enter Scope({1})",
                                 INDENT, id.index())?,
                    Annotation::ExitScope(id) =>
                        writeln!(w, "{0}{0}// Exit Scope({1})",
                                 INDENT, id.index())?,
                }
            }
        }

        let indented_mir = format!("{0}{0}{1:?};", INDENT, statement);
        writeln!(w, "{0:1$} // {2}",
                 indented_mir,
                 ALIGN,
                 comment(tcx, statement.source_info))?;

        current_location.statement_index += 1;
    }

    // Terminator at the bottom.
    let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind);
    writeln!(w, "{0:1$} // {2}",
             indented_terminator,
             ALIGN,
             comment(tcx, data.terminator().source_info))?;

    writeln!(w, "{}}}", INDENT)
}

fn comment(tcx: TyCtxt, SourceInfo { span, scope }: SourceInfo) -> String {
    format!("scope {} at {}", scope.index(), tcx.sess.codemap().span_to_string(span))
}

fn write_scope_tree(tcx: TyCtxt,
                    mir: &Mir,
                    scope_tree: &FnvHashMap<VisibilityScope, Vec<VisibilityScope>>,
                    w: &mut Write,
                    parent: VisibilityScope,
                    depth: usize)
                    -> io::Result<()> {
    let indent = depth * INDENT.len();

    let children = match scope_tree.get(&parent) {
        Some(childs) => childs,
        None => return Ok(()),
    };

    for &child in children {
        let data = &mir.visibility_scopes[child];
        assert_eq!(data.parent_scope, Some(parent));
        writeln!(w, "{0:1$}scope {2} {{", "", indent, child.index())?;

        // User variable types (including the user's name in a comment).
        for (id, var) in mir.var_decls.iter_enumerated() {
            // Skip if not declared in this scope.
            if var.source_info.scope != child {
                continue;
            }

            let mut_str = if var.mutability == Mutability::Mut {
                "mut "
            } else {
                ""
            };

            let indent = indent + INDENT.len();
            let indented_var = format!("{0:1$}let {2}{3:?}: {4};",
                                       INDENT,
                                       indent,
                                       mut_str,
                                       id,
                                       var.ty);
            writeln!(w, "{0:1$} // \"{2}\" in {3}",
                     indented_var,
                     ALIGN,
                     var.name,
                     comment(tcx, var.source_info))?;
        }

        write_scope_tree(tcx, mir, scope_tree, w, child, depth + 1)?;

        writeln!(w, "{0:1$}}}", "", depth * INDENT.len())?;
    }

    Ok(())
}

/// Write out a human-readable textual representation of the MIR's `fn` type and the types of its
/// local variables (both user-defined bindings and compiler temporaries).
fn write_mir_intro<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             src: MirSource,
                             mir: &Mir,
                             w: &mut Write)
                             -> io::Result<()> {
    write_mir_sig(tcx, src, mir, w)?;
    writeln!(w, " {{")?;

    // construct a scope tree and write it out
    let mut scope_tree: FnvHashMap<VisibilityScope, Vec<VisibilityScope>> = FnvHashMap();
    for (index, scope_data) in mir.visibility_scopes.iter().enumerate() {
        if let Some(parent) = scope_data.parent_scope {
            scope_tree.entry(parent)
                      .or_insert(vec![])
                      .push(VisibilityScope::new(index));
        } else {
            // Only the argument scope has no parent, because it's the root.
            assert_eq!(index, ARGUMENT_VISIBILITY_SCOPE.index());
        }
    }

    write_scope_tree(tcx, mir, &scope_tree, w, ARGUMENT_VISIBILITY_SCOPE, 1)?;

    write_mir_decls(mir, w)
}

fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write)
                 -> io::Result<()>
{
    match src {
        MirSource::Fn(_) => write!(w, "fn")?,
        MirSource::Const(_) => write!(w, "const")?,
        MirSource::Static(_, hir::MutImmutable) => write!(w, "static")?,
        MirSource::Static(_, hir::MutMutable) => write!(w, "static mut")?,
        MirSource::Promoted(_, i) => write!(w, "{:?} in", i)?
    }

    write!(w, " {}", tcx.node_path_str(src.item_id()))?;

    if let MirSource::Fn(_) = src {
        write!(w, "(")?;

        // fn argument types.
        for (i, arg) in mir.arg_decls.iter_enumerated() {
            if i.index() != 0 {
                write!(w, ", ")?;
            }
            write!(w, "{:?}: {}", Lvalue::Arg(i), arg.ty)?;
        }

        write!(w, ") -> ")?;

        // fn return type.
        match mir.return_ty {
            ty::FnOutput::FnConverging(ty) => write!(w, "{}", ty),
            ty::FnOutput::FnDiverging => write!(w, "!"),
        }
    } else {
        assert!(mir.arg_decls.is_empty());
        write!(w, ": {} =", mir.return_ty.unwrap())
    }
}

fn write_mir_decls(mir: &Mir, w: &mut Write) -> io::Result<()> {
    // Compiler-introduced temporary types.
    for (id, temp) in mir.temp_decls.iter_enumerated() {
        writeln!(w, "{}let mut {:?}: {};", INDENT, id, temp.ty)?;
    }

    // Wrote any declaration? Add an empty line before the first block is printed.
    if !mir.var_decls.is_empty() || !mir.temp_decls.is_empty() {
        writeln!(w, "")?;
    }

    Ok(())
}
<|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.

//! Infrastructure for compiler plugins.
//!
//! Plugins are Rust libraries which extend the behavior of `rustc`
//! in various ways.
//!
//! Plugin authors will use the `Registry` type re-exported by
//! this module, along with its methods.  The rest of the module
//! is for use by `rustc` itself.
//!
//! To define a plugin, build a dylib crate with a
//! `#[plugin_registrar]` function:
//!
//! ```no_run
//! #![crate_name = "myplugin"]
//! #![crate_type = "dylib"]
//! #![feature(plugin_registrar)]
//! #![feature(rustc_private)]
//!
//! extern crate rustc_plugin;
//! extern crate syntax;
//! extern crate syntax_pos;
//!
//! use rustc_plugin::Registry;
//! use syntax::ext::base::{ExtCtxt, MacResult};
//! use syntax_pos::Span;
//! use syntax::tokenstream::TokenTree;
//!
//! #[plugin_registrar]
//! pub fn plugin_registrar(reg: &mut Registry) {
//!     reg.register_macro("mymacro", expand_mymacro);
//! }
//!
//! fn expand_mymacro(cx: &mut ExtCtxt, span: Span, tt: &[TokenTree]) -> Box<MacResult> {
//!     unimplemented!()
//! }
//!
//! # fn main() {}
//! ```
//!
//! WARNING: We currently don't check that the registrar function
//! has the appropriate type!
//!
//! To use a plugin while compiling another crate:
//!
//! ```rust
//! #![feature(plugin)]
//! #![plugin(myplugin)]
//! ```
//!
//! See the [`plugin` feature](../../unstable-book/language-features/plugin.html) of
//! the Unstable Book for more examples.

#![crate_name = "rustc_plugin"]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/nightly/")]
#![deny(warnings)]

#![feature(rustc_diagnostic_macros)]

#[macro_use] extern crate syntax;

extern crate rustc;
extern crate rustc_back;
extern crate rustc_metadata;
extern crate syntax_pos;
extern crate rustc_errors as errors;

pub use self::registry::Registry;

pub mod diagnostics;
pub mod registry;
pub mod load;
pub mod build;

__build_diagnostic_array! { librustc_plugin, DIAGNOSTICS }
<commit_msg>rustc_plugin: use staged API<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.

//! Infrastructure for compiler plugins.
//!
//! Plugins are Rust libraries which extend the behavior of `rustc`
//! in various ways.
//!
//! Plugin authors will use the `Registry` type re-exported by
//! this module, along with its methods.  The rest of the module
//! is for use by `rustc` itself.
//!
//! To define a plugin, build a dylib crate with a
//! `#[plugin_registrar]` function:
//!
//! ```no_run
//! #![crate_name = "myplugin"]
//! #![crate_type = "dylib"]
//! #![feature(plugin_registrar)]
//! #![feature(rustc_private)]
//!
//! extern crate rustc_plugin;
//! extern crate syntax;
//! extern crate syntax_pos;
//!
//! use rustc_plugin::Registry;
//! use syntax::ext::base::{ExtCtxt, MacResult};
//! use syntax_pos::Span;
//! use syntax::tokenstream::TokenTree;
//!
//! #[plugin_registrar]
//! pub fn plugin_registrar(reg: &mut Registry) {
//!     reg.register_macro("mymacro", expand_mymacro);
//! }
//!
//! fn expand_mymacro(cx: &mut ExtCtxt, span: Span, tt: &[TokenTree]) -> Box<MacResult> {
//!     unimplemented!()
//! }
//!
//! # fn main() {}
//! ```
//!
//! WARNING: We currently don't check that the registrar function
//! has the appropriate type!
//!
//! To use a plugin while compiling another crate:
//!
//! ```rust
//! #![feature(plugin)]
//! #![plugin(myplugin)]
//! ```
//!
//! See the [`plugin` feature](../../unstable-book/language-features/plugin.html) of
//! the Unstable Book for more examples.

#![crate_name = "rustc_plugin"]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/nightly/")]
#![deny(warnings)]

#![feature(rustc_diagnostic_macros)]
#![feature(staged_api)]

#[macro_use] extern crate syntax;

extern crate rustc;
extern crate rustc_back;
extern crate rustc_metadata;
extern crate syntax_pos;
extern crate rustc_errors as errors;

pub use self::registry::Registry;

pub mod diagnostics;
pub mod registry;
pub mod load;
pub mod build;

__build_diagnostic_array! { librustc_plugin, DIAGNOSTICS }
<|endoftext|>


<commit_before>use std::error::Error;

use conduit_middleware;
use conduit::Request;
use conduit_cookie::RequestSession;

use Model;
use db::RequestTransaction;
use super::User;
use util::errors::{CargoResult, Unauthorized, ChainError, std_error};

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

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum AuthenticationSource {
    SessionCookie,
    ApiToken,
}

impl conduit_middleware::Middleware for Middleware {
    fn before(&self, req: &mut Request) -> Result<(), Box<Error + Send>> {
        // Check if the request has a session cookie with a `user_id` property inside
        let id = {
            req.session().get("user_id").and_then(|s| s.parse().ok())
        };

        if let Some(id) = id {
            // If it did, look for a user in the database with the given `user_id`
            if let Ok(user) = User::find(req.tx().map_err(std_error)?, id) {
                // Attach the `User` model from the database to the request
                req.mut_extensions().insert(user);
                req.mut_extensions().insert(
                    AuthenticationSource::SessionCookie,
                );
            }
        } else {
            // Otherwise, look for an `Authorization` header on the request
            // and try to find a user in the database with a matching API token
            let user = if let Some(headers) = req.headers().find("Authorization") {
                User::find_by_api_token(&*req.db_conn().map_err(std_error)?, headers[0]).ok()
            } else {
                None
            };
            if let Some(user) = user {
                // Attach the `User` model from the database to the request
                req.mut_extensions().insert(user);
                req.mut_extensions().insert(AuthenticationSource::ApiToken);
            }
        }

        Ok(())
    }
}

pub trait RequestUser {
    fn user(&self) -> CargoResult<&User>;
    fn authentication_source(&self) -> CargoResult<AuthenticationSource>;
}

impl<'a> RequestUser for Request + 'a {
    fn user(&self) -> CargoResult<&User> {
        self.extensions().find::<User>().chain_error(
            || Unauthorized,
        )
    }

    fn authentication_source(&self) -> CargoResult<AuthenticationSource> {
        self.extensions()
            .find::<AuthenticationSource>()
            .cloned()
            .chain_error(|| Unauthorized)
    }
}
<commit_msg>Use diesel from inside the users middleware<commit_after>use std::error::Error;

use conduit_middleware;
use conduit::Request;
use conduit_cookie::RequestSession;
use diesel::prelude::*;

use db::RequestTransaction;
use schema::users;
use super::User;
use util::errors::{CargoResult, Unauthorized, ChainError, std_error};

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

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum AuthenticationSource {
    SessionCookie,
    ApiToken,
}

impl conduit_middleware::Middleware for Middleware {
    fn before(&self, req: &mut Request) -> Result<(), Box<Error + Send>> {
        // Check if the request has a session cookie with a `user_id` property inside
        let id = {
            req.session().get("user_id").and_then(
                |s| s.parse::<i32>().ok(),
            )
        };

        let conn = req.db_conn().map_err(std_error)?;

        if let Some(id) = id {
            // If it did, look for a user in the database with the given `user_id`
            let maybe_user = users::table.find(id).first::<User>(&*conn);
            if let Ok(user) = maybe_user {
                // Attach the `User` model from the database to the request
                req.mut_extensions().insert(user);
                req.mut_extensions().insert(
                    AuthenticationSource::SessionCookie,
                );
            }
        } else {
            // Otherwise, look for an `Authorization` header on the request
            // and try to find a user in the database with a matching API token
            let user = if let Some(headers) = req.headers().find("Authorization") {
                User::find_by_api_token(&conn, headers[0]).ok()
            } else {
                None
            };
            if let Some(user) = user {
                // Attach the `User` model from the database to the request
                req.mut_extensions().insert(user);
                req.mut_extensions().insert(AuthenticationSource::ApiToken);
            }
        }

        Ok(())
    }
}

pub trait RequestUser {
    fn user(&self) -> CargoResult<&User>;
    fn authentication_source(&self) -> CargoResult<AuthenticationSource>;
}

impl<'a> RequestUser for Request + 'a {
    fn user(&self) -> CargoResult<&User> {
        self.extensions().find::<User>().chain_error(
            || Unauthorized,
        )
    }

    fn authentication_source(&self) -> CargoResult<AuthenticationSource> {
        self.extensions()
            .find::<AuthenticationSource>()
            .cloned()
            .chain_error(|| Unauthorized)
    }
}
<|endoftext|>


<commit_before>//! Crate documentation builder
//!
//! This module is extremely similar to cargo install operation, except it's building
//! documentation of a crate and not installing anything.

use std::path::{Path, PathBuf};
use std::env;
use std::sync::Arc;

use cargo::core::{SourceId, Dependency, Registry, Source, Package, Workspace};
use cargo::util::{CargoResult, Config, human, Filesystem};
use cargo::sources::SourceConfigMap;
use cargo::ops::{self, Packages, DefaultExecutor};

/// Builds documentation of a crate and version.
///
/// Crate will be built into current working directory/crate-version.
///
/// It will build latest version, if no version is given.
// idea is to make cargo to download
// and build a crate and its documentation
// instead of doing it manually like in the previous version of cratesfyi
pub fn build_doc(name: &str, vers: Option<&str>, target: Option<&str>) -> CargoResult<Package> {
    let config = try!(Config::default());
    let source_id = try!(SourceId::crates_io(&config));

    let source_map = try!(SourceConfigMap::new(&config));
    let mut source = try!(source_map.load(&source_id));

    // update crates.io-index registry
    try!(source.update());

    let dep = try!(Dependency::parse_no_deprecated(name, vers, &source_id));
    let deps = try!(source.query(&dep));
    let pkg = try!(deps.iter().map(|p| p.package_id()).max()
                   // FIXME: This is probably not a rusty way to handle options and results
                   //        or maybe it is who knows...
                   .map(|pkgid| source.download(pkgid))
                   .unwrap_or(Err(human("PKG download error"))));

    let current_dir = try!(env::current_dir());
    let target_dir = PathBuf::from(current_dir).join("cratesfyi");

    let opts = ops::CompileOptions {
        config: &config,
        jobs: None,
        target: target,
        features: &[],
        all_features: false,
        no_default_features: false,
        spec: Packages::Packages(&[]),
        mode: ops::CompileMode::Doc { deps: false },
        release: false,
        message_format: ops::MessageFormat::Human,
        filter: ops::CompileFilter::new(true,
                                        &[], false,
                                        &[], false,
                                        &[], false,
                                        &[], false),
        target_rustc_args: None,
        target_rustdoc_args: None,
    };

    let ws = try!(Workspace::ephemeral(pkg, &config, Some(Filesystem::new(target_dir)), false));
    try!(ops::compile_ws(&ws, Some(source), &opts, Arc::new(DefaultExecutor)));

    Ok(try!(ws.current()).clone())
}

/// Downloads a crate and returns Cargo Package.
pub fn get_package(name: &str, vers: Option<&str>) -> CargoResult<Package> {
    debug!("Getting package with cargo");
    let config = try!(Config::default());
    let source_id = try!(SourceId::crates_io(&config));

    let source_map = try!(SourceConfigMap::new(&config));
    let mut source = try!(source_map.load(&source_id));

    let dep = try!(Dependency::parse_no_deprecated(name, vers, &source_id));
    let deps = try!(source.query(&dep));
    let pkg = try!(deps.iter().map(|p| p.package_id()).max()
                   // FIXME: This is probably not a rusty way to handle options and results
                   //        or maybe it is who knows...
                   .map(|pkgid| source.download(pkgid))
                   .unwrap_or(Err(human("PKG download error"))));

    Ok(pkg)
}

/// Updates central crates-io.index repository
pub fn update_sources() -> CargoResult<()> {
    let config = try!(Config::default());
    let source_id = try!(SourceId::crates_io(&config));

    let source_map = try!(SourceConfigMap::new(&config));
    let mut source = try!(source_map.load(&source_id));

    source.update()
}

/// Gets source path of a downloaded package.
pub fn source_path(pkg: &Package) -> Option<&Path> {
    // parent of the manifest file is where source codes are stored
    pkg.manifest_path().parent()
}

#[cfg(test)]
mod test {
    use std::path::Path;
    use std::fs::remove_dir_all;
    use super::*;

    #[test]
    fn test_build_doc() {
        let doc = build_doc("rand", None, None);
        assert!(doc.is_ok());

        let doc = doc.unwrap();
        remove_dir_all(format!("{}-{}", doc.manifest().name(), doc.manifest().version())).unwrap();

        let doc = build_doc("SOMECRATEWICHWILLBENVEREXISTS", None, None);
        assert!(doc.is_err());
    }

    #[test]
    fn test_get_package() {
        let pkg = get_package("rand", None);
        assert!(pkg.is_ok());

        let pkg = pkg.unwrap();

        let manifest = pkg.manifest();
        assert_eq!(manifest.name(), "rand");
    }

    #[test]
    fn test_source_path() {
        let pkg = get_package("rand", None).unwrap();
        let source_path = source_path(&pkg).unwrap();
        assert!(source_path.is_dir());

        let cargo_toml_path = Path::new(source_path).join("Cargo.toml");
        assert!(cargo_toml_path.exists());
        assert!(cargo_toml_path.is_file());

        let src_path = Path::new(source_path).join("src");
        assert!(src_path.exists());
        assert!(src_path.is_dir());
    }
}
<commit_msg>Fix build_doc test<commit_after>//! Crate documentation builder
//!
//! This module is extremely similar to cargo install operation, except it's building
//! documentation of a crate and not installing anything.

use std::path::{Path, PathBuf};
use std::env;
use std::sync::Arc;

use cargo::core::{SourceId, Dependency, Registry, Source, Package, Workspace};
use cargo::util::{CargoResult, Config, human, Filesystem};
use cargo::sources::SourceConfigMap;
use cargo::ops::{self, Packages, DefaultExecutor};

/// Builds documentation of a crate and version.
///
/// Crate will be built into current working directory/crate-version.
///
/// It will build latest version, if no version is given.
// idea is to make cargo to download
// and build a crate and its documentation
// instead of doing it manually like in the previous version of cratesfyi
pub fn build_doc(name: &str, vers: Option<&str>, target: Option<&str>) -> CargoResult<Package> {
    let config = try!(Config::default());
    let source_id = try!(SourceId::crates_io(&config));

    let source_map = try!(SourceConfigMap::new(&config));
    let mut source = try!(source_map.load(&source_id));

    // update crates.io-index registry
    try!(source.update());

    let dep = try!(Dependency::parse_no_deprecated(name, vers, &source_id));
    let deps = try!(source.query(&dep));
    let pkg = try!(deps.iter().map(|p| p.package_id()).max()
                   // FIXME: This is probably not a rusty way to handle options and results
                   //        or maybe it is who knows...
                   .map(|pkgid| source.download(pkgid))
                   .unwrap_or(Err(human("PKG download error"))));

    let current_dir = try!(env::current_dir());
    let target_dir = PathBuf::from(current_dir).join("cratesfyi");

    let opts = ops::CompileOptions {
        config: &config,
        jobs: None,
        target: target,
        features: &[],
        all_features: false,
        no_default_features: false,
        spec: Packages::Packages(&[]),
        mode: ops::CompileMode::Doc { deps: false },
        release: false,
        message_format: ops::MessageFormat::Human,
        filter: ops::CompileFilter::new(true,
                                        &[], false,
                                        &[], false,
                                        &[], false,
                                        &[], false),
        target_rustc_args: None,
        target_rustdoc_args: None,
    };

    let ws = try!(Workspace::ephemeral(pkg, &config, Some(Filesystem::new(target_dir)), false));
    try!(ops::compile_ws(&ws, Some(source), &opts, Arc::new(DefaultExecutor)));

    Ok(try!(ws.current()).clone())
}

/// Downloads a crate and returns Cargo Package.
pub fn get_package(name: &str, vers: Option<&str>) -> CargoResult<Package> {
    debug!("Getting package with cargo");
    let config = try!(Config::default());
    let source_id = try!(SourceId::crates_io(&config));

    let source_map = try!(SourceConfigMap::new(&config));
    let mut source = try!(source_map.load(&source_id));

    let dep = try!(Dependency::parse_no_deprecated(name, vers, &source_id));
    let deps = try!(source.query(&dep));
    let pkg = try!(deps.iter().map(|p| p.package_id()).max()
                   // FIXME: This is probably not a rusty way to handle options and results
                   //        or maybe it is who knows...
                   .map(|pkgid| source.download(pkgid))
                   .unwrap_or(Err(human("PKG download error"))));

    Ok(pkg)
}

/// Updates central crates-io.index repository
pub fn update_sources() -> CargoResult<()> {
    let config = try!(Config::default());
    let source_id = try!(SourceId::crates_io(&config));

    let source_map = try!(SourceConfigMap::new(&config));
    let mut source = try!(source_map.load(&source_id));

    source.update()
}

/// Gets source path of a downloaded package.
pub fn source_path(pkg: &Package) -> Option<&Path> {
    // parent of the manifest file is where source codes are stored
    pkg.manifest_path().parent()
}

#[cfg(test)]
mod test {
    use std::path::Path;
    use std::fs::remove_dir_all;
    use super::*;

    #[test]
    fn test_build_doc() {
        let doc = build_doc("rand", None, None);
        assert!(doc.is_ok());

        let root_path = Path::new("cratesfyi");
        assert!(root_path.join("doc").join("rand").exists());

        remove_dir_all(root_path).unwrap();

        let doc = build_doc("SOMECRATEWICHWILLBENVEREXISTS", None, None);
        assert!(doc.is_err());
    }

    #[test]
    fn test_get_package() {
        let pkg = get_package("rand", None);
        assert!(pkg.is_ok());

        let pkg = pkg.unwrap();

        let manifest = pkg.manifest();
        assert_eq!(manifest.name(), "rand");
    }

    #[test]
    fn test_source_path() {
        let pkg = get_package("rand", None).unwrap();
        let source_path = source_path(&pkg).unwrap();
        assert!(source_path.is_dir());

        let cargo_toml_path = Path::new(source_path).join("Cargo.toml");
        assert!(cargo_toml_path.exists());
        assert!(cargo_toml_path.is_file());

        let src_path = Path::new(source_path).join("src");
        assert!(src_path.exists());
        assert!(src_path.is_dir());
    }
}
<|endoftext|>