<commit_before>use std::io::File;
use std::io::{Reader, Writer, Seek, SeekSet, SeekEnd};
use std::io::{IoResult, IoError, InvalidInput};
use std::iter;
use std::iter::range_inclusive;
use std::path::BytesContainer;
use error;
use error::ZipError;
use maybe_utf8::MaybeUTF8;
use flate;
use crc32;
use format;
use fileinfo;
use fileinfo::{CompressionMethod, FileInfo};

pub struct ZipReader<R> {
    reader: R,
    end_record: format::EndOfCentralDirectoryRecord,
}

pub struct Files<'a, R> {
    zip_reader: &'a mut ZipReader<R>,
    current_entry: u16,
    current_offset: u64,
}

impl<'a, R:Reader+Seek> Iterator<Result<FileInfo, ZipError>> for Files<'a, R> {
    fn next(&mut self) -> Option<Result<FileInfo, ZipError>> {
        if self.current_entry < self.zip_reader.end_record.total_entry_count {
            match self.zip_reader.reader.seek(self.current_offset as i64, SeekSet) {
                Ok(()) => {}
                Err(err) => { return Some(Err(error::IoError(err))); }
            }
            let h = match format::CentralDirectoryHeader::read(&mut self.zip_reader.reader) {
                Ok(h) => h,
                Err(err) => { return Some(Err(err)); }
            };
            let info = FileInfo::from_cdh(&h);
            self.current_entry += 1;
            self.current_offset += h.total_size() as u64;
            Some(Ok(info))
        } else {
            None
        }
    }
}

impl ZipReader<File> {
    pub fn open(path: &Path) -> Result<ZipReader<File>, ZipError> {
        ZipReader::new(try_io!(File::open(path)))
    }
}

impl<R:Reader+Seek> ZipReader<R> {
    pub fn new(reader: R) -> Result<ZipReader<R>, ZipError> {
        // find the End of Central Directory record, looking backwards from the end of the file
        let mut r = reader;
        try_io!(r.seek(0, SeekEnd));
        let file_size = try_io!(r.tell());
        let mut end_record_offset : Option<u64> = None;
        for i in range_inclusive(4, file_size) {
            let offset = file_size - i;
            try_io!(r.seek(offset as i64, SeekSet));

            let sig = try_io!(r.read_le_u32());

            // TODO: check for false positives here
            if sig == format::EOCDR_SIGNATURE {
                end_record_offset = Some(offset);
                break;
            }

        }

        match end_record_offset {
            Some(offset) => {
                try_io!(r.seek(offset as i64, SeekSet));
                let e = format::EndOfCentralDirectoryRecord::read(&mut r).unwrap();
                Ok(ZipReader {reader: r, end_record: e})
            },
            None => Err(error::NotAZipFile)
        }
    }

    pub fn files_raw<'a>(&'a mut self) -> Files<'a, R> {
        let cdr_offset = self.end_record.central_directory_offset;
        Files {
            zip_reader: self,
            current_entry: 0,
            current_offset: cdr_offset as u64
        }
    }

    pub fn files<'a>(&'a mut self) -> iter::Map<Result<FileInfo, ZipError>, FileInfo,
                                                Files<'a, R>> {
        self.files_raw().map(|fileinfo_or_err| fileinfo_or_err.unwrap())
    }

    pub fn file_names<'a>(&'a mut self) -> iter::Map<Result<FileInfo, ZipError>, MaybeUTF8,
                                                     Files<'a, R>> {
        self.files_raw().map(|fileinfo_or_err| fileinfo_or_err.unwrap().name)
    }

    pub fn info<T:BytesContainer>(&mut self, name: T) -> Result<FileInfo, ZipError> {
        for i in self.files() {
            if i.name.equiv(&name) {
                return Ok(i);
            }
        }
        Err(error::FileNotFoundInArchive)
    }

    // TODO: Create a Reader for the cases when you don't want to decompress the whole file
    pub fn read(&mut self, f: &FileInfo) -> Result<Vec<u8>, ZipError> {
        try_io!(self.reader.seek(f.local_file_header_offset as i64, SeekSet));
        let h = format::LocalFileHeader::read(&mut self.reader).unwrap();
        let file_offset = f.local_file_header_offset as i64 + h.total_size() as i64;

        let result =
            match CompressionMethod::from_u16(h.compression_method) {
                fileinfo::Store => self.read_stored_file(file_offset, h.uncompressed_size),
                fileinfo::Deflate => self.read_deflated_file(file_offset, h.compressed_size, h.uncompressed_size),
                _ => fail!()
            };
        let result = try_io!(result);

        // Check the CRC32 of the result against the one stored in the header
        let crc = crc32::crc32(result.as_slice());

        if crc == h.crc32 { Ok(result) }
        else { Err(error::CrcError) }
    }

    fn read_stored_file(&mut self, pos: i64, uncompressed_size: u32) -> IoResult<Vec<u8>> {
        try!(self.reader.seek(pos, SeekSet));
        self.reader.read_exact(uncompressed_size as uint)
    }

    fn read_deflated_file(&mut self, pos: i64, compressed_size: u32, uncompressed_size: u32) -> IoResult<Vec<u8>> {
        try!(self.reader.seek(pos, SeekSet));
        let compressed_bytes = try!(self.reader.read_exact(compressed_size as uint));
        let uncompressed_bytes = match flate::inflate_bytes(compressed_bytes.as_slice()) {
            Some(bytes) => bytes,
            None => return Err(IoError { kind: InvalidInput, desc: "decompression failure", detail: None })
        };
        assert!(uncompressed_bytes.len() as u32 == uncompressed_size);
        // FIXME try not to copy the buffer, or switch to the incremental fashion
        Ok(Vec::from_slice(uncompressed_bytes.as_slice()))
    }

    // when we make read return a Reader, we will be able to loop here and copy
    // blocks of a fixed size from Reader to Writer
    pub fn extract<T:Writer>(&mut self, f: &FileInfo, writer: &mut T) -> Result<(), ZipError> {
        match self.read(f) {
            Ok(bytes) => { try_io!(writer.write(bytes.as_slice())); Ok(()) },
            Err(x) => Err(x)
        }
    }

}

<commit_msg>fixed two edge cases that the invalid archive can cause a hard task failure.<commit_after>use std::io::File;
use std::io::{Reader, Writer, Seek, SeekSet, SeekEnd};
use std::io::{IoResult, IoError, InvalidInput};
use std::iter;
use std::iter::range_inclusive;
use std::path::BytesContainer;
use error;
use error::ZipError;
use maybe_utf8::MaybeUTF8;
use flate;
use crc32;
use format;
use fileinfo;
use fileinfo::{CompressionMethod, FileInfo};

pub struct ZipReader<R> {
    reader: R,
    end_record: format::EndOfCentralDirectoryRecord,
}

pub struct Files<'a, R> {
    zip_reader: &'a mut ZipReader<R>,
    current_entry: u16,
    current_offset: u64,
}

impl<'a, R:Reader+Seek> Iterator<Result<FileInfo, ZipError>> for Files<'a, R> {
    fn next(&mut self) -> Option<Result<FileInfo, ZipError>> {
        if self.current_entry < self.zip_reader.end_record.total_entry_count {
            match self.zip_reader.reader.seek(self.current_offset as i64, SeekSet) {
                Ok(()) => {}
                Err(err) => { return Some(Err(error::IoError(err))); }
            }
            let h = match format::CentralDirectoryHeader::read(&mut self.zip_reader.reader) {
                Ok(h) => h,
                Err(err) => { return Some(Err(err)); }
            };
            let info = FileInfo::from_cdh(&h);
            self.current_entry += 1;
            self.current_offset += h.total_size() as u64;
            Some(Ok(info))
        } else {
            None
        }
    }
}

impl ZipReader<File> {
    pub fn open(path: &Path) -> Result<ZipReader<File>, ZipError> {
        ZipReader::new(try_io!(File::open(path)))
    }
}

impl<R:Reader+Seek> ZipReader<R> {
    pub fn new(reader: R) -> Result<ZipReader<R>, ZipError> {
        // find the End of Central Directory record, looking backwards from the end of the file
        let mut r = reader;
        try_io!(r.seek(0, SeekEnd));
        let file_size = try_io!(r.tell());
        let mut end_record_offset : Option<u64> = None;
        for i in range_inclusive(4, file_size) {
            let offset = file_size - i;
            try_io!(r.seek(offset as i64, SeekSet));

            let sig = try_io!(r.read_le_u32());

            // TODO: check for false positives here
            if sig == format::EOCDR_SIGNATURE {
                end_record_offset = Some(offset);
                break;
            }

        }

        match end_record_offset {
            Some(offset) => {
                try_io!(r.seek(offset as i64, SeekSet));
                let e = try!(format::EndOfCentralDirectoryRecord::read(&mut r));
                Ok(ZipReader {reader: r, end_record: e})
            },
            None => Err(error::NotAZipFile)
        }
    }

    pub fn files_raw<'a>(&'a mut self) -> Files<'a, R> {
        let cdr_offset = self.end_record.central_directory_offset;
        Files {
            zip_reader: self,
            current_entry: 0,
            current_offset: cdr_offset as u64
        }
    }

    pub fn files<'a>(&'a mut self) -> iter::Map<Result<FileInfo, ZipError>, FileInfo,
                                                Files<'a, R>> {
        self.files_raw().map(|fileinfo_or_err| fileinfo_or_err.unwrap())
    }

    pub fn file_names<'a>(&'a mut self) -> iter::Map<Result<FileInfo, ZipError>, MaybeUTF8,
                                                     Files<'a, R>> {
        self.files_raw().map(|fileinfo_or_err| fileinfo_or_err.unwrap().name)
    }

    pub fn info<T:BytesContainer>(&mut self, name: T) -> Result<FileInfo, ZipError> {
        for i in self.files() {
            if i.name.equiv(&name) {
                return Ok(i);
            }
        }
        Err(error::FileNotFoundInArchive)
    }

    // TODO: Create a Reader for the cases when you don't want to decompress the whole file
    pub fn read(&mut self, f: &FileInfo) -> Result<Vec<u8>, ZipError> {
        try_io!(self.reader.seek(f.local_file_header_offset as i64, SeekSet));
        let h = try!(format::LocalFileHeader::read(&mut self.reader));
        let file_offset = f.local_file_header_offset as i64 + h.total_size() as i64;

        let result =
            match CompressionMethod::from_u16(h.compression_method) {
                fileinfo::Store => self.read_stored_file(file_offset, h.uncompressed_size),
                fileinfo::Deflate => self.read_deflated_file(file_offset, h.compressed_size, h.uncompressed_size),
                _ => fail!()
            };
        let result = try_io!(result);

        // Check the CRC32 of the result against the one stored in the header
        let crc = crc32::crc32(result.as_slice());

        if crc == h.crc32 { Ok(result) }
        else { Err(error::CrcError) }
    }

    fn read_stored_file(&mut self, pos: i64, uncompressed_size: u32) -> IoResult<Vec<u8>> {
        try!(self.reader.seek(pos, SeekSet));
        self.reader.read_exact(uncompressed_size as uint)
    }

    fn read_deflated_file(&mut self, pos: i64, compressed_size: u32, uncompressed_size: u32) -> IoResult<Vec<u8>> {
        try!(self.reader.seek(pos, SeekSet));
        let compressed_bytes = try!(self.reader.read_exact(compressed_size as uint));
        let uncompressed_bytes = match flate::inflate_bytes(compressed_bytes.as_slice()) {
            Some(bytes) => bytes,
            None => return Err(IoError { kind: InvalidInput, desc: "decompression failure", detail: None })
        };
        assert!(uncompressed_bytes.len() as u32 == uncompressed_size);
        // FIXME try not to copy the buffer, or switch to the incremental fashion
        Ok(Vec::from_slice(uncompressed_bytes.as_slice()))
    }

    // when we make read return a Reader, we will be able to loop here and copy
    // blocks of a fixed size from Reader to Writer
    pub fn extract<T:Writer>(&mut self, f: &FileInfo, writer: &mut T) -> Result<(), ZipError> {
        match self.read(f) {
            Ok(bytes) => { try_io!(writer.write(bytes.as_slice())); Ok(()) },
            Err(x) => Err(x)
        }
    }

}

<|endoftext|>


<commit_before>use std::{error, fmt};
use std::io::{self, Read};

use crate::{ImageResult, ImageError};
use crate::image::ImageFormat;
use crate::Rgba;
use crate::error::DecodingError;
use super::vp8::{Vp8Decoder, Frame as VP8Frame};
use super::lossless::{LosslessDecoder, LosslessFrame};
use byteorder::{ReadBytesExt, LittleEndian, BigEndian};

#[derive(Debug, Clone, Copy)]
enum ExtendedWebPDecoderError {
    HeaderInvalid,
}

enum SimpleFrame {
    Lossy(VP8Frame),
    Lossless(LosslessFrame),
}

impl fmt::Display for ExtendedWebPDecoderError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            ExtendedWebPDecoderError::HeaderInvalid => {
                f.write_str("Invalid Header")
            }
        }
    }
}

impl From<ExtendedWebPDecoderError> for ImageError {
    fn from(e: ExtendedWebPDecoderError) -> ImageError {
        ImageError::Decoding(DecodingError::new(ImageFormat::WebP.into(), e))
    }
}

impl error::Error for ExtendedWebPDecoderError {}

#[derive(Debug, Copy, Clone)]
pub(crate) struct WebPExtendedInfo {
    icc_profile: bool,
    alpha: bool,
    exif_metadata: bool,
    xmp_metadata: bool,
    animation: bool,
    canvas_width: u32,
    canvas_height: u32,
}

pub(crate) struct WebPExtendedImage {
    info: WebPExtendedInfo,
    frame: ExtendedFrame,
}

enum ExtendedFrame {
    Animation(WebPAnimated),
    Static(WebPStatic),
}

struct WebPStatic {
    alpha: Option<AlphaChunk>,
    frame: SimpleFrame,
}

struct WebPAnimated {
    background_color: Rgba<u8>,
    loop_count: u16,
    frames: Vec<SimpleFrame>,
}

pub(crate) fn read_extended_header<R: Read>(reader: &mut R) -> ImageResult<WebPExtendedInfo> {
    let chunk_flags = reader.read_u8()?;

    let reserved_first = chunk_flags & 0b11000000;
    let icc_profile = chunk_flags & 0b00100000 != 0;
    let alpha = chunk_flags & 0b00010000 != 0;
    let exif_metadata = chunk_flags & 0b00001000 != 0;
    let xmp_metadata = chunk_flags & 0b00000100 != 0;
    let animation = chunk_flags & 0b00000010 != 0;
    let reserved_second = chunk_flags & 0b00000001;

    let mut reserved_third: [u8; 3] = [0; 3];
    reader.read_exact(&mut reserved_third)?;

    if reserved_first != 0 || reserved_second != 0 || reserved_third != [0, 0, 0] {
        return Err(ExtendedWebPDecoderError::HeaderInvalid.into());
    }

    let canvas_width = read_3_bytes(reader)?;
    let canvas_height = read_3_bytes(reader)?;

    let info = WebPExtendedInfo {
        icc_profile,
        alpha,
        exif_metadata,
        xmp_metadata,
        animation,
        canvas_width,
        canvas_height,
    };

    return Ok(info);
}

pub(crate) fn read_extended_chunks<R: Read>(info: WebPExtendedInfo, reader: &mut R) -> ImageResult<WebPExtendedFrame> {
    if info.icc_profile {
        //ignore iccp
        ignore_chunk(reader, b"ICCP")?;
        println!("ignored iccp");
    }

    if info.animation {
        //read animation
        read_animation(reader)?;
    }

    //image data

    if info.exif_metadata {
        //ignore exif metadat
        ignore_chunk(reader, b"EXIF")?;
        println!("ignored exif");
    }

    if info.xmp_metadata {
        //ignore xmp metadata
        ignore_chunk(reader, b"XMP ")?;
        println!("ignored xmp");
    }

    todo!()
}

fn ignore_chunk<R: Read>(reader: &mut R, chunk_fourcc: &[u8; 4]) -> ImageResult<()> {
    let mut chunk: [u8; 4] = [0; 4];
    reader.read_exact(&mut chunk)?;

    if &chunk != chunk_fourcc {
        return Err(ExtendedWebPDecoderError::HeaderInvalid.into());
    }

    let mut len = u64::from(reader.read_u32::<LittleEndian>()?);

    if len % 2 != 0 {
        // RIFF chunks containing an uneven number of bytes append
        // an extra 0x00 at the end of the chunk
        //
        // The addition cannot overflow since we have a u64 that was created from a u32
        len += 1;
    }

    io::copy(&mut reader.by_ref().take(len), &mut io::sink())?;

    Ok(())
}

fn read_animation<R: Read>(reader: &mut R) -> ImageResult<()> {
    //read anim chunk
    let mut chunk: [u8; 4] = [0; 4];

    reader.read_exact(&mut chunk)?;

    if &chunk != b"ANIM" {
        return Err(ExtendedWebPDecoderError::HeaderInvalid.into());
    }

    let _len = reader.read_u32::<LittleEndian>()?;

    let _background_color = reader.read_u32::<LittleEndian>()?;

    let loop_count = reader.read_u16::<LittleEndian>()?;

    read_anim_frame(reader)?;

    Ok(())
}

fn read_anim_frame<R: Read>(reader: &mut R) -> ImageResult<SimpleFrame> {
    let mut chunk: [u8; 4] = [0; 4];
    reader.read_exact(&mut chunk)?;

    if &chunk != b"ANMF" {
        return Err(ExtendedWebPDecoderError::HeaderInvalid.into());
    }

    let frame_x = read_3_bytes(reader)?;
    let frame_y = read_3_bytes(reader)?;

    let frame_width = read_3_bytes(reader)? + 1;
    let frame_height = read_3_bytes(reader)? + 1;
    let duration = read_3_bytes(reader)?;

    let frame_info = reader.read_u8()?;
    let reserved = frame_info & 0b11111100;
    if reserved != 0 {
        return Err(ExtendedWebPDecoderError::HeaderInvalid.into());
    }
    let use_alpha_blending = frame_info & 0b00000010 == 0;
    let dispose = frame_info & 0b00000001 != 0;

    println!("{frame_x}, {frame_y}, {frame_width}, {frame_height}, {duration}");

    //read normal bitstream now
    read_simple_bitstream(reader)
}

fn read_3_bytes<R: Read>(reader: &mut R) -> ImageResult<u32> {
    let mut buffer: [u8; 3] = [0; 3];
    reader.read_exact(&mut buffer)?;
    let value: u32 = (u32::from(buffer[0]) << 16) | (u32::from(buffer[1]) << 8) | u32::from(buffer[2]);
    Ok(value)
}

fn read_simple_bitstream<R: Read>(reader: &mut R) -> ImageResult<SimpleFrame> {
    let mut chunk = [0; 4];
    reader.read_exact(&mut chunk)?;

    match &chunk {
        b"VP8 " => {
            let len = reader.read_u32::<LittleEndian>()?;

            let mut vp8_decoder = Vp8Decoder::new(reader);
            let frame = vp8_decoder.decode_frame()?;

            Ok(SimpleFrame::Lossy(frame.clone()))
        }
        b"VP8L" => {
            let len = reader.read_u32::<LittleEndian>()?;

            let mut lossless_decoder = LosslessDecoder::new(reader);
            let frame = lossless_decoder.decode_frame()?;

            Ok(SimpleFrame::Lossless(frame.clone()))
        }
        _ => Err(ExtendedWebPDecoderError::HeaderInvalid.into())
    }
}

struct AlphaChunk {
    preprocessing: bool,
    filtering_method: FilteringMethod,
    lossless_compression: bool,
    data: Vec<u8>,
}

enum FilteringMethod {
    None,
    Horizontal,
    Vertical,
    Gradient,
}

impl FilteringMethod {
    fn from_num(num: u8) -> Self {
        match num {
            0 => FilteringMethod::None,
            1 => FilteringMethod::Horizontal,
            2 => FilteringMethod::Vertical,
            3 => FilteringMethod::Gradient,
            _ => panic!("Invalid filter for alpha chunk in WebP image, should be unreachable"),
        }
    }
}

//note only for VP8 frames
fn read_alpha_chunk<R: Read>(reader: &mut R, width: u32, height: u32) -> ImageResult<AlphaChunk> {
    let mut chunk: [u8; 4] = [0; 4];
    reader.read_exact(&mut chunk)?;

    if &chunk != b"ALPH" {
        return Err(ExtendedWebPDecoderError::HeaderInvalid.into());
    }

    //TODO: if odd, add 1
    let len = reader.read_u32::<LittleEndian>()?;

    let info_byte = reader.read_u8()?;

    let reserved = info_byte & 0b11000000;
    let preprocessing = (info_byte & 0b00110000) >> 4;
    let filtering = (info_byte & 0b00001100) >> 2;
    let compression = info_byte & 0b00000011;

    if reserved != 0 {
        return Err(ExtendedWebPDecoderError::HeaderInvalid.into());
    }

    let preprocessing = match preprocessing {
        0 => false,
        1 => true,
        _ => return Err(ExtendedWebPDecoderError::HeaderInvalid.into()),
    };

    let filtering_method = FilteringMethod::from_num(filtering);

    let lossless_compression = match compression {
        0 => false,
        1 => true,
        _ => return Err(ExtendedWebPDecoderError::HeaderInvalid.into()),
    };

    let mut framedata = Vec::new();
    reader.take(len as u64).read_to_end(&mut framedata)?;

    let data = if lossless_compression {
        let cursor = std::io::Cursor::new(framedata);

        let mut decoder = LosslessDecoder::new(cursor);
        let frame = decoder.decode_frame_implicit_dims()?;

        //TODO: change to proper cast
        let mut data = vec![0; (width * height) as usize];

        frame.fill_green(&mut data)

        frame
    } else {
        framedata
    };

    let chunk = AlphaChunk {
        preprocessing,
        filtering_method,
        lossless_compression,
        data,
    }

    Ok(chunk)
}<commit_msg>changed reading alpha/non alpha frames<commit_after>use std::{error, fmt};
use std::io::{self, Read};

use crate::{ImageResult, ImageError};
use crate::image::ImageFormat;
use crate::Rgba;
use crate::error::DecodingError;
use super::vp8::{Vp8Decoder, Frame as VP8Frame};
use super::lossless::{LosslessDecoder, LosslessFrame};
use byteorder::{ReadBytesExt, LittleEndian, BigEndian};

#[derive(Debug, Clone, Copy)]
enum ExtendedWebPDecoderError {
    HeaderInvalid,
}

enum SimpleFrame {
    Lossy(VP8Frame),
    Lossless(LosslessFrame),
}

impl fmt::Display for ExtendedWebPDecoderError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            ExtendedWebPDecoderError::HeaderInvalid => {
                f.write_str("Invalid Header")
            }
        }
    }
}

impl From<ExtendedWebPDecoderError> for ImageError {
    fn from(e: ExtendedWebPDecoderError) -> ImageError {
        ImageError::Decoding(DecodingError::new(ImageFormat::WebP.into(), e))
    }
}

impl error::Error for ExtendedWebPDecoderError {}

#[derive(Debug, Copy, Clone)]
pub(crate) struct WebPExtendedInfo {
    icc_profile: bool,
    alpha: bool,
    exif_metadata: bool,
    xmp_metadata: bool,
    animation: bool,
    canvas_width: u32,
    canvas_height: u32,
}

pub(crate) struct WebPExtendedImage {
    info: WebPExtendedInfo,
    frame: ExtendedFrame,
}

enum ExtendedFrame {
    Animation(WebPAnimated),
    Static(WebPStatic),
}

struct WebPStatic {
    alpha: Option<AlphaChunk>,
    frame: SimpleFrame,
}

struct WebPAnimated {
    background_color: Rgba<u8>,
    loop_count: u16,
    frames: Vec<WebPStatic>,
}

pub(crate) fn read_extended_header<R: Read>(reader: &mut R) -> ImageResult<WebPExtendedInfo> {
    let chunk_flags = reader.read_u8()?;

    let reserved_first = chunk_flags & 0b11000000;
    let icc_profile = chunk_flags & 0b00100000 != 0;
    let alpha = chunk_flags & 0b00010000 != 0;
    let exif_metadata = chunk_flags & 0b00001000 != 0;
    let xmp_metadata = chunk_flags & 0b00000100 != 0;
    let animation = chunk_flags & 0b00000010 != 0;
    let reserved_second = chunk_flags & 0b00000001;

    let mut reserved_third: [u8; 3] = [0; 3];
    reader.read_exact(&mut reserved_third)?;

    if reserved_first != 0 || reserved_second != 0 || reserved_third != [0, 0, 0] {
        return Err(ExtendedWebPDecoderError::HeaderInvalid.into());
    }

    let canvas_width = read_3_bytes(reader)?;
    let canvas_height = read_3_bytes(reader)?;

    let info = WebPExtendedInfo {
        icc_profile,
        alpha,
        exif_metadata,
        xmp_metadata,
        animation,
        canvas_width,
        canvas_height,
    };

    return Ok(info);
}

pub(crate) fn read_extended_chunks<R: Read>(info: WebPExtendedInfo, reader: &mut R) -> ImageResult<WebPExtendedFrame> {
    if info.icc_profile {
        //ignore iccp
        ignore_chunk(reader, b"ICCP")?;
        println!("ignored iccp");
    }

    if info.animation {
        //read animation
        read_animation(reader)?;
    }

    //image data

    if info.exif_metadata {
        //ignore exif metadat
        ignore_chunk(reader, b"EXIF")?;
        println!("ignored exif");
    }

    if info.xmp_metadata {
        //ignore xmp metadata
        ignore_chunk(reader, b"XMP ")?;
        println!("ignored xmp");
    }

    todo!()
}

fn ignore_chunk<R: Read>(reader: &mut R, chunk_fourcc: &[u8; 4]) -> ImageResult<()> {
    let mut chunk: [u8; 4] = [0; 4];
    reader.read_exact(&mut chunk)?;

    if &chunk != chunk_fourcc {
        return Err(ExtendedWebPDecoderError::HeaderInvalid.into());
    }

    let mut len = u64::from(reader.read_u32::<LittleEndian>()?);

    if len % 2 != 0 {
        // RIFF chunks containing an uneven number of bytes append
        // an extra 0x00 at the end of the chunk
        //
        // The addition cannot overflow since we have a u64 that was created from a u32
        len += 1;
    }

    io::copy(&mut reader.by_ref().take(len), &mut io::sink())?;

    Ok(())
}

fn read_animation<R: Read>(reader: &mut R) -> ImageResult<()> {
    //read anim chunk
    let mut chunk: [u8; 4] = [0; 4];

    reader.read_exact(&mut chunk)?;

    if &chunk != b"ANIM" {
        return Err(ExtendedWebPDecoderError::HeaderInvalid.into());
    }

    let _len = reader.read_u32::<LittleEndian>()?;

    let _background_color = reader.read_u32::<LittleEndian>()?;

    let loop_count = reader.read_u16::<LittleEndian>()?;

    read_anim_frame(reader)?;

    Ok(())
}

fn read_anim_frame<R: Read>(reader: &mut R) -> ImageResult<SimpleFrame> {
    let mut chunk: [u8; 4] = [0; 4];
    reader.read_exact(&mut chunk)?;

    if &chunk != b"ANMF" {
        return Err(ExtendedWebPDecoderError::HeaderInvalid.into());
    }

    let frame_x = read_3_bytes(reader)?;
    let frame_y = read_3_bytes(reader)?;

    let frame_width = read_3_bytes(reader)? + 1;
    let frame_height = read_3_bytes(reader)? + 1;
    let duration = read_3_bytes(reader)?;

    let frame_info = reader.read_u8()?;
    let reserved = frame_info & 0b11111100;
    if reserved != 0 {
        return Err(ExtendedWebPDecoderError::HeaderInvalid.into());
    }
    let use_alpha_blending = frame_info & 0b00000010 == 0;
    let dispose = frame_info & 0b00000001 != 0;

    println!("{frame_x}, {frame_y}, {frame_width}, {frame_height}, {duration}");

    //read normal bitstream now
}

fn read_3_bytes<R: Read>(reader: &mut R) -> ImageResult<u32> {
    let mut buffer: [u8; 3] = [0; 3];
    reader.read_exact(&mut buffer)?;
    let value: u32 = (u32::from(buffer[0]) << 16) | (u32::from(buffer[1]) << 8) | u32::from(buffer[2]);
    Ok(value)
}

fn read_image<R: Read>(reader: &mut R) -> WebPStatic {
    let mut chunk = [0; 4];
    reader.read_exact(&mut chunk)?;

    match &chunk {
        b"VP8 " => {
            let len = reader.read_u32::<LittleEndian>()?;

            let mut vp8_decoder = Vp8Decoder::new(reader);
            let frame = vp8_decoder.decode_frame()?;

            let frame = SimpleFrame::Lossy(frame.clone());

            let img = WebPStatic {
                alpha: None,
                frame,
            };

            Ok(img)
        }
        b"VP8L" => {
            let len = reader.read_u32::<LittleEndian>()?;

            let mut lossless_decoder = LosslessDecoder::new(reader);
            let frame = lossless_decoder.decode_frame()?;

            let frame = SimpleFrame::Lossless(frame.clone());

            let img = WebPStatic {
                alpha: None,
                frame,
            };

            Ok(img)
        }
        b"ALPH" => {
            let alpha = read_alpha_chunk(reader);

            let mut chunk = [0; 4];
            reader.read_exact(&mut chunk)?;

            if chunk != b"VP8 " {
                return Err(ExtendedWebPDecoderError::HeaderInvalid.into());
            }

            let len = reader.read_u32::<LittleEndian>()?;

            let mut vp8_decoder = Vp8Decoder::new(reader);
            let frame = vp8_decoder.decode_frame()?;

            let frame = SimpleFrame::Lossy(frame.clone());

            let img = WebPStatic {
                alpha,
                frame,
            };

            Ok(img)
        }
        _ => Err(ExtendedWebPDecoderError::HeaderInvalid.into())
    }
}

struct AlphaChunk {
    preprocessing: bool,
    filtering_method: FilteringMethod,
    lossless_compression: bool,
    data: Vec<u8>,
}

enum FilteringMethod {
    None,
    Horizontal,
    Vertical,
    Gradient,
}

impl FilteringMethod {
    fn from_num(num: u8) -> Self {
        match num {
            0 => FilteringMethod::None,
            1 => FilteringMethod::Horizontal,
            2 => FilteringMethod::Vertical,
            3 => FilteringMethod::Gradient,
            _ => panic!("Invalid filter for alpha chunk in WebP image, should be unreachable"),
        }
    }
}

//note only for VP8 frames
fn read_alpha_chunk<R: Read>(reader: &mut R, width: u32, height: u32) -> ImageResult<AlphaChunk> {

    //TODO: if odd, add 1
    let len = reader.read_u32::<LittleEndian>()?;

    let info_byte = reader.read_u8()?;

    let reserved = info_byte & 0b11000000;
    let preprocessing = (info_byte & 0b00110000) >> 4;
    let filtering = (info_byte & 0b00001100) >> 2;
    let compression = info_byte & 0b00000011;

    if reserved != 0 {
        return Err(ExtendedWebPDecoderError::HeaderInvalid.into());
    }

    let preprocessing = match preprocessing {
        0 => false,
        1 => true,
        _ => return Err(ExtendedWebPDecoderError::HeaderInvalid.into()),
    };

    let filtering_method = FilteringMethod::from_num(filtering);

    let lossless_compression = match compression {
        0 => false,
        1 => true,
        _ => return Err(ExtendedWebPDecoderError::HeaderInvalid.into()),
    };

    let mut framedata = Vec::new();
    reader.take(len as u64).read_to_end(&mut framedata)?;

    let data = if lossless_compression {
        let cursor = std::io::Cursor::new(framedata);

        let mut decoder = LosslessDecoder::new(cursor);
        let frame = decoder.decode_frame_implicit_dims()?;

        //TODO: change to proper cast
        let mut data = vec![0; (width * height) as usize];

        frame.fill_green(&mut data)

        frame
    } else {
        framedata
    };

    let chunk = AlphaChunk {
        preprocessing,
        filtering_method,
        lossless_compression,
        data,
    }

    Ok(chunk)
}<|endoftext|>


<commit_before>//! A basic input + output stream example, copying the mic input stream to the default output stream

extern crate coreaudio;

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

use coreaudio::audio_unit::{AudioUnit, Element, SampleFormat, Scope, StreamFormat};
use coreaudio::audio_unit::audio_format::LinearPcmFlags;
use coreaudio::audio_unit::render_callback::{self, data};
use coreaudio::sys::*;

const SAMPLE_RATE: f64 = 44100.0;

type S = f32; const SAMPLE_FORMAT: SampleFormat = SampleFormat::F32;
// type S = i32; const SAMPLE_FORMAT: SampleFormat = SampleFormat::I32;
// type S = i16; const SAMPLE_FORMAT: SampleFormat = SampleFormat::I16;
// type S = i8; const SAMPLE_FORMAT: SampleFormat = SampleFormat::I8;

pub fn run_example() -> Result<(), coreaudio::Error> {
    let mut input_audio_unit = AudioUnit::new(coreaudio::audio_unit::IOType::RemoteIO)?;
    let mut output_audio_unit = AudioUnit::new(coreaudio::audio_unit::IOType::RemoteIO)?;

    // iOS doesn't let you reconfigure an "initialized" audio unit, so uninitialize them
    input_audio_unit.uninitialize()?;
    output_audio_unit.uninitialize()?;

    configure_for_recording(&mut input_audio_unit)?;

    let format_flag = match SAMPLE_FORMAT {
        SampleFormat::F32 => LinearPcmFlags::IS_FLOAT,
        SampleFormat::I32 | SampleFormat::I16 | SampleFormat::I8 => LinearPcmFlags::IS_SIGNED_INTEGER,
    };

    // Using IS_NON_INTERLEAVED everywhere because data::Interleaved is commented out / not implemented
    let in_stream_format = StreamFormat {
        sample_rate: SAMPLE_RATE,
        sample_format: SAMPLE_FORMAT,
        flags: format_flag | LinearPcmFlags::IS_PACKED | LinearPcmFlags::IS_NON_INTERLEAVED,
        // audio_unit.set_input_callback is hardcoded to 1 buffer, and when using non_interleaved
        // we are forced to 1 channel
        channels_per_frame: 1,
    };

    let out_stream_format = StreamFormat {
        sample_rate: SAMPLE_RATE,
        sample_format: SAMPLE_FORMAT,
        flags: format_flag | LinearPcmFlags::IS_PACKED | LinearPcmFlags::IS_NON_INTERLEAVED,
        // you can change this to 1
        channels_per_frame: 2,
    };

    println!("input={:#?}", &in_stream_format);
    println!("output={:#?}", &out_stream_format);
    println!("input_asbd={:#?}", &in_stream_format.to_asbd());
    println!("output_asbd={:#?}", &out_stream_format.to_asbd());

    let id = kAudioUnitProperty_StreamFormat;
    input_audio_unit.set_property(id, Scope::Output, Element::Input, Some(&in_stream_format.to_asbd()))?;
    output_audio_unit.set_property(id, Scope::Input, Element::Output, Some(&out_stream_format.to_asbd()))?;

    let buffer_left = Arc::new(Mutex::new(VecDeque::<S>::new()));
    let producer_left = buffer_left.clone();
    let consumer_left = buffer_left.clone();
    let buffer_right = Arc::new(Mutex::new(VecDeque::<S>::new()));
    let producer_right = buffer_right.clone();
    let consumer_right = buffer_right.clone();

    // seed roughly 1 second of data to create a delay in the feedback loop for easier testing
    for buffer in vec![buffer_left, buffer_right] {
        let mut buffer = buffer.lock().unwrap();
        for _ in 0..(out_stream_format.sample_rate as i32) {
            buffer.push_back(0 as S);
        }
    }

    type Args = render_callback::Args<data::NonInterleaved<S>>;

    println!("set_input_callback");
    input_audio_unit.set_input_callback(move |args| {
        let Args {
            num_frames,
            mut data,
            ..
        } = args;
        let buffer_left = producer_left.lock().unwrap();
        let buffer_right = producer_right.lock().unwrap();
        let mut buffers = vec![buffer_left, buffer_right];
        for i in 0..num_frames {
            for (ch, channel) in data.channels_mut().enumerate() {
                let value: S = channel[i];
                buffers[ch].push_back(value);
            }
        }
        Ok(())
    })?;
    input_audio_unit.initialize()?;
    input_audio_unit.start()?;

    println!("set_render_callback");
    output_audio_unit.set_render_callback(move |args: Args| {
        let Args {
            num_frames,
            mut data,
            ..
        } = args;

        let buffer_left = consumer_left.lock().unwrap();
        let buffer_right = consumer_right.lock().unwrap();
        let mut buffers = vec![buffer_left, buffer_right];
        for i in 0..num_frames {
            // Default other channels to copy value from first channel as a fallback
            let zero: S = 0 as S;
            let f: S = *buffers[0].front().unwrap_or(&zero);
            for (ch, channel) in data.channels_mut().enumerate() {
                let sample: S = buffers[ch].pop_front().unwrap_or(f);
                channel[i] = sample;
            }
        }
        Ok(())
    })?;
    output_audio_unit.initialize()?;
    output_audio_unit.start()?;

    // for the purposes of this demo, leak these so that after returning the audio units will
    // keep running
    std::mem::forget(input_audio_unit);
    std::mem::forget(output_audio_unit);

    Ok(())
}

fn configure_for_recording(audio_unit: &mut AudioUnit) -> Result<(), coreaudio::Error> {
    println!("Configure audio unit for recording");

    // Enable mic recording
    let enable_input = 1u32;
    audio_unit.set_property(
        kAudioOutputUnitProperty_EnableIO,
        Scope::Input,
        Element::Input,
        Some(&enable_input),
    )?;

    // Disable output
    let disable_output = 0u32;
    audio_unit.set_property(
        kAudioOutputUnitProperty_EnableIO,
        Scope::Output,
        Element::Output,
        Some(&disable_output),
    )?;

    Ok(())
}
<commit_msg>Tweak iOS example to use sample rate from the output device (old devices use 44.1 new devices use 48)<commit_after>//! A basic input + output stream example, copying the mic input stream to the default output stream

extern crate coreaudio;

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

use coreaudio::audio_unit::{AudioUnit, Element, SampleFormat, Scope, StreamFormat};
use coreaudio::audio_unit::audio_format::LinearPcmFlags;
use coreaudio::audio_unit::render_callback::{self, data};
use coreaudio::sys::*;

type S = f32; const SAMPLE_FORMAT: SampleFormat = SampleFormat::F32;
// type S = i32; const SAMPLE_FORMAT: SampleFormat = SampleFormat::I32;
// type S = i16; const SAMPLE_FORMAT: SampleFormat = SampleFormat::I16;
// type S = i8; const SAMPLE_FORMAT: SampleFormat = SampleFormat::I8;

pub fn run_example() -> Result<(), coreaudio::Error> {
    let mut input_audio_unit = AudioUnit::new(coreaudio::audio_unit::IOType::RemoteIO)?;
    let mut output_audio_unit = AudioUnit::new(coreaudio::audio_unit::IOType::RemoteIO)?;

    // Read device sample rate off the output stream
    let id = kAudioUnitProperty_StreamFormat;
    let asbd: AudioStreamBasicDescription =
        output_audio_unit.get_property(id, Scope::Output, Element::Output)?;
    let sample_rate = asbd.mSampleRate;

    // iOS doesn't let you reconfigure an "initialized" audio unit, so uninitialize them
    input_audio_unit.uninitialize()?;
    output_audio_unit.uninitialize()?;

    configure_for_recording(&mut input_audio_unit)?;

    let format_flag = match SAMPLE_FORMAT {
        SampleFormat::F32 => LinearPcmFlags::IS_FLOAT,
        SampleFormat::I32 | SampleFormat::I16 | SampleFormat::I8 => LinearPcmFlags::IS_SIGNED_INTEGER,
    };

    // Using IS_NON_INTERLEAVED everywhere because data::Interleaved is commented out / not implemented
    let in_stream_format = StreamFormat {
        sample_rate: sample_rate,
        sample_format: SAMPLE_FORMAT,
        flags: format_flag | LinearPcmFlags::IS_PACKED | LinearPcmFlags::IS_NON_INTERLEAVED,
        // audio_unit.set_input_callback is hardcoded to 1 buffer, and when using non_interleaved
        // we are forced to 1 channel
        channels_per_frame: 1,
    };

    let out_stream_format = StreamFormat {
        sample_rate: sample_rate,
        sample_format: SAMPLE_FORMAT,
        flags: format_flag | LinearPcmFlags::IS_PACKED | LinearPcmFlags::IS_NON_INTERLEAVED,
        // you can change this to 1
        channels_per_frame: 2,
    };

    println!("input={:#?}", &in_stream_format);
    println!("output={:#?}", &out_stream_format);
    println!("input_asbd={:#?}", &in_stream_format.to_asbd());
    println!("output_asbd={:#?}", &out_stream_format.to_asbd());

    let id = kAudioUnitProperty_StreamFormat;
    input_audio_unit.set_property(id, Scope::Output, Element::Input, Some(&in_stream_format.to_asbd()))?;
    output_audio_unit.set_property(id, Scope::Input, Element::Output, Some(&out_stream_format.to_asbd()))?;

    let buffer_left = Arc::new(Mutex::new(VecDeque::<S>::new()));
    let producer_left = buffer_left.clone();
    let consumer_left = buffer_left.clone();
    let buffer_right = Arc::new(Mutex::new(VecDeque::<S>::new()));
    let producer_right = buffer_right.clone();
    let consumer_right = buffer_right.clone();

    // seed roughly 1 second of data to create a delay in the feedback loop for easier testing
    for buffer in vec![buffer_left, buffer_right] {
        let mut buffer = buffer.lock().unwrap();
        for _ in 0..(out_stream_format.sample_rate as i32) {
            buffer.push_back(0 as S);
        }
    }

    type Args = render_callback::Args<data::NonInterleaved<S>>;

    println!("set_input_callback");
    input_audio_unit.set_input_callback(move |args| {
        let Args {
            num_frames,
            mut data,
            ..
        } = args;
        let buffer_left = producer_left.lock().unwrap();
        let buffer_right = producer_right.lock().unwrap();
        let mut buffers = vec![buffer_left, buffer_right];
        for i in 0..num_frames {
            for (ch, channel) in data.channels_mut().enumerate() {
                let value: S = channel[i];
                buffers[ch].push_back(value);
            }
        }
        Ok(())
    })?;
    input_audio_unit.initialize()?;
    input_audio_unit.start()?;

    println!("set_render_callback");
    output_audio_unit.set_render_callback(move |args: Args| {
        let Args {
            num_frames,
            mut data,
            ..
        } = args;

        let buffer_left = consumer_left.lock().unwrap();
        let buffer_right = consumer_right.lock().unwrap();
        let mut buffers = vec![buffer_left, buffer_right];
        for i in 0..num_frames {
            // Default other channels to copy value from first channel as a fallback
            let zero: S = 0 as S;
            let f: S = *buffers[0].front().unwrap_or(&zero);
            for (ch, channel) in data.channels_mut().enumerate() {
                let sample: S = buffers[ch].pop_front().unwrap_or(f);
                channel[i] = sample;
            }
        }
        Ok(())
    })?;
    output_audio_unit.initialize()?;
    output_audio_unit.start()?;

    // for the purposes of this demo, leak these so that after returning the audio units will
    // keep running
    std::mem::forget(input_audio_unit);
    std::mem::forget(output_audio_unit);

    Ok(())
}

fn configure_for_recording(audio_unit: &mut AudioUnit) -> Result<(), coreaudio::Error> {
    println!("Configure audio unit for recording");

    // Enable mic recording
    let enable_input = 1u32;
    audio_unit.set_property(
        kAudioOutputUnitProperty_EnableIO,
        Scope::Input,
        Element::Input,
        Some(&enable_input),
    )?;

    // Disable output
    let disable_output = 0u32;
    audio_unit.set_property(
        kAudioOutputUnitProperty_EnableIO,
        Scope::Output,
        Element::Output,
        Some(&disable_output),
    )?;

    Ok(())
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate rotor_http;
extern crate rotor;
extern crate mio;
extern crate libc;

use std::env;
use std::thread;
use std::os::unix::io::AsRawFd;

type StateMachine<'a> = rotor::transports::accept::Serve<
                        mio::tcp::TcpListener,
                        rotor::transports::greedy_stream::Stream<
                            mio::tcp::TcpStream,
                            rotor_http::http1::Client<Context, HelloWorld>,
                            Context>,
                        Context>;
type Timeo = ();

struct Context {
    counter: usize,
}

trait Counter {
    fn increment(&mut self);
    fn get(&self) -> usize;
}

impl Counter for Context {
    fn increment(&mut self) { self.counter += 1; }
    fn get(&self) -> usize { self.counter }
}

struct HelloWorld;

impl<C:Counter> rotor_http::http1::Handler<C> for HelloWorld {
    fn request(req: rotor_http::http1::Request,
               res: &mut rotor_http::http1::ResponseBuilder,
               ctx: &mut C)
    {
        ctx.increment();
        match req.uri {
            hyper::uri::RequestUri::AbsolutePath(ref p) if &p[..] == "/" => {
                res.set_status(hyper::status::StatusCode::Ok);
                res.put_body("Hello World!");
            }
            hyper::uri::RequestUri::AbsolutePath(ref p) if &p[..] == "/num"
            => {
                res.set_status(hyper::status::StatusCode::Ok);
                res.put_body(format!("This host visited {} times",
                                     ctx.get()));
            }
            hyper::uri::RequestUri::AbsolutePath(p) => {
                res.set_status(hyper::status::StatusCode::Ok);
                res.put_body(format!("Hello {}!", &p[1..]));
            }
            _ => {}  // Do nothing: not found or bad request
        }
    }
}

fn main() {
    let threads = env::var("THREADS").unwrap_or("2".to_string())
        .parse().unwrap();
    let mut children = Vec::new();
    for _ in 0..threads {
        let sock = mio::tcp::TcpSocket::v4().unwrap();
        let one = 1i32;
        unsafe {
            assert!(libc::funcs::bsd43::setsockopt(
                sock.as_raw_fd(), libc::SOL_SOCKET,
                libc::SO_REUSEPORT,
                &one as *const libc::c_int as *const libc::c_void, 4) == 0);
        }
        sock.bind(&"127.0.0.1:6754".parse().unwrap()).unwrap();
        let lst = sock.listen(4096).unwrap();
        children.push(thread::spawn(move || {
            let mut event_loop = mio::EventLoop::new().unwrap();
            let mut handler = rotor::Handler::new(Context {
                counter: 0,
            }, &mut event_loop);
            event_loop.channel().send(rotor::handler::Notify::NewMachine(
                StateMachine::new(lst))).unwrap();
            event_loop.run(&mut handler).unwrap();
        }));
    }
    for child in children {
        child.join().unwrap();
    }
}
<commit_msg>Ported last example<commit_after>extern crate hyper;
extern crate rotor_http;
extern crate rotor;
extern crate mio;
extern crate libc;

use std::env;
use std::thread;
use std::os::unix::io::AsRawFd;

use rotor_http::HttpServer;

struct Context {
    counter: usize,
}

trait Counter {
    fn increment(&mut self);
    fn get(&self) -> usize;
}

impl Counter for Context {
    fn increment(&mut self) { self.counter += 1; }
    fn get(&self) -> usize { self.counter }
}

struct HelloWorld;

impl<C:Counter> rotor_http::http1::Handler<C> for HelloWorld {
    fn request(req: rotor_http::http1::Request,
               res: &mut rotor_http::http1::ResponseBuilder,
               ctx: &mut C)
    {
        ctx.increment();
        match req.uri {
            hyper::uri::RequestUri::AbsolutePath(ref p) if &p[..] == "/" => {
                res.set_status(hyper::status::StatusCode::Ok);
                res.put_body("Hello World!");
            }
            hyper::uri::RequestUri::AbsolutePath(ref p) if &p[..] == "/num"
            => {
                res.set_status(hyper::status::StatusCode::Ok);
                res.put_body(format!("This host visited {} times",
                                     ctx.get()));
            }
            hyper::uri::RequestUri::AbsolutePath(p) => {
                res.set_status(hyper::status::StatusCode::Ok);
                res.put_body(format!("Hello {}!", &p[1..]));
            }
            _ => {}  // Do nothing: not found or bad request
        }
    }
}

fn main() {

    let threads = env::var("THREADS").unwrap_or("2".to_string())
        .parse().unwrap();
    let mut children = Vec::new();
    for _ in 0..threads {
        let sock = mio::tcp::TcpSocket::v4().unwrap();
        let one = 1i32;
        unsafe {
            assert!(libc::setsockopt(
                sock.as_raw_fd(), libc::SOL_SOCKET,
                libc::SO_REUSEPORT,
                &one as *const libc::c_int as *const libc::c_void, 4) == 0);
        }
        sock.bind(&"127.0.0.1:6754".parse().unwrap()).unwrap();
        let listener = sock.listen(4096).unwrap();
        children.push(thread::spawn(move || {
            let mut event_loop = mio::EventLoop::new().unwrap();
            let mut handler = rotor::Handler::new(Context {
                counter: 0,
            }, &mut event_loop);
            handler.add_root(&mut event_loop,
                HttpServer::<_, HelloWorld>::new(listener));
            event_loop.run(&mut handler).unwrap();
        }));
    }
    for child in children {
        child.join().unwrap();
    }
}
<|endoftext|>


<commit_before>use crate::command_prelude::*;

use cargo::core::{GitReference, SourceId};
use cargo::ops;
use cargo::util::ToUrl;

pub fn cli() -> App {
    subcommand("install")
        .about("Install a Rust binary. Default location is $HOME/.cargo/bin")
        .arg(opt("quiet", "No output printed to stdout").short("q"))
        .arg(Arg::with_name("crate").empty_values(false).multiple(true))
        .arg(
            opt("version", "Specify a version to install")
                .alias("vers")
                .value_name("VERSION")
                .requires("crate"),
        )
        .arg(
            opt("git", "Git URL to install the specified crate from")
                .value_name("URL")
                .conflicts_with_all(&["path", "registry"]),
        )
        .arg(
            opt("branch", "Branch to use when installing from git")
                .value_name("BRANCH")
                .requires("git"),
        )
        .arg(
            opt("tag", "Tag to use when installing from git")
                .value_name("TAG")
                .requires("git"),
        )
        .arg(
            opt("rev", "Specific commit to use when installing from git")
                .value_name("SHA")
                .requires("git"),
        )
        .arg(
            opt("path", "Filesystem path to local crate to install")
                .value_name("PATH")
                .conflicts_with_all(&["git", "registry"]),
        )
        .arg(opt(
            "list",
            "list all installed packages and their versions",
        ))
        .arg_jobs()
        .arg(opt("force", "Force overwriting existing crates or binaries").short("f"))
        .arg_features()
        .arg(opt("debug", "Build in debug mode instead of release mode"))
        .arg_targets_bins_examples(
            "Install only the specified binary",
            "Install all binaries",
            "Install only the specified example",
            "Install all examples",
        )
        .arg_target_triple("Build for the target triple")
        .arg(opt("root", "Directory to install packages into").value_name("DIR"))
        .arg(
            opt("registry", "Registry to use")
                .value_name("REGISTRY")
                .requires("crate")
                .conflicts_with_all(&["git", "path"]),
        )
        .after_help(
            "\
This command manages Cargo's local set of installed binary crates. Only packages
which have [[bin]] targets can be installed, and all binaries are installed into
the installation root's `bin` folder. The installation root is determined, in
order of precedence, by `--root`, `$CARGO_INSTALL_ROOT`, the `install.root`
configuration key, and finally the home directory (which is either
`$CARGO_HOME` if set or `$HOME/.cargo` by default).

There are multiple sources from which a crate can be installed. The default
location is crates.io but the `--git`, `--path`, and `registry` flags can
change this source. If the source contains more than one package (such as
crates.io or a git repository with multiple crates) the `<crate>` argument is
required to indicate which crate should be installed.

Crates from crates.io can optionally specify the version they wish to install
via the `--version` flags, and similarly packages from git repositories can
optionally specify the branch, tag, or revision that should be installed. If a
crate has multiple binaries, the `--bin` argument can selectively install only
one of them, and if you'd rather install examples the `--example` argument can
be used as well.

By default cargo will refuse to overwrite existing binaries. The `--force` flag
enables overwriting existing binaries. Thus you can reinstall a crate with
`cargo install --force <crate>`.

Omitting the <crate> specification entirely will install the crate in the
current directory. That is, `install` is equivalent to the more explicit
`install --path .`. This behaviour is deprecated, and no longer supported as
of the Rust 2018 edition.

If the source is crates.io or `--git` then by default the crate will be built
in a temporary target directory. To avoid this, the target directory can be
specified by setting the `CARGO_TARGET_DIR` environment variable to a relative
path. In particular, this can be useful for caching build artifacts on
continuous integration systems.",
        )
}

pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
    let registry = args.registry(config)?;

    if let Some(path) = args.value_of_path("path", config) {
        config.reload_rooted_at(path)?;
    } else {
        config.reload_rooted_at(config.home().clone().into_path_unlocked())?;
    }

    let workspace = args.workspace(config).ok();
    let mut compile_opts = args.compile_options(config, CompileMode::Build, workspace.as_ref())?;

    compile_opts.build_config.release = !args.is_present("debug");

    let krates = args
        .values_of("crate")
        .unwrap_or_default()
        .collect::<Vec<_>>();

    let mut from_cwd = false;

    let source = if let Some(url) = args.value_of("git") {
        let url = url.to_url()?;
        let gitref = if let Some(branch) = args.value_of("branch") {
            GitReference::Branch(branch.to_string())
        } else if let Some(tag) = args.value_of("tag") {
            GitReference::Tag(tag.to_string())
        } else if let Some(rev) = args.value_of("rev") {
            GitReference::Rev(rev.to_string())
        } else {
            GitReference::Branch("master".to_string())
        };
        SourceId::for_git(&url, gitref)?
    } else if let Some(path) = args.value_of_path("path", config) {
        SourceId::for_path(&path)?
    } else if krates.is_empty() {
        from_cwd = true;
        SourceId::for_path(config.cwd())?
    } else if let Some(registry) = registry {
        SourceId::alt_registry(config, &registry)?
    } else {
        SourceId::crates_io(config)?
    };

    let version = args.value_of("version");
    let root = args.value_of("root");

    if args.is_present("list") {
        ops::install_list(root, config)?;
    } else {
        ops::install(
            root,
            krates,
            source,
            from_cwd,
            version,
            &compile_opts,
            args.is_present("force"),
        )?;
    }
    Ok(())
}
<commit_msg>Auto merge of #6823 - spl:clarify-install-path, r=alexcrichton<commit_after>use crate::command_prelude::*;

use cargo::core::{GitReference, SourceId};
use cargo::ops;
use cargo::util::ToUrl;

pub fn cli() -> App {
    subcommand("install")
        .about("Install a Rust binary. Default location is $HOME/.cargo/bin")
        .arg(opt("quiet", "No output printed to stdout").short("q"))
        .arg(Arg::with_name("crate").empty_values(false).multiple(true))
        .arg(
            opt("version", "Specify a version to install")
                .alias("vers")
                .value_name("VERSION")
                .requires("crate"),
        )
        .arg(
            opt("git", "Git URL to install the specified crate from")
                .value_name("URL")
                .conflicts_with_all(&["path", "registry"]),
        )
        .arg(
            opt("branch", "Branch to use when installing from git")
                .value_name("BRANCH")
                .requires("git"),
        )
        .arg(
            opt("tag", "Tag to use when installing from git")
                .value_name("TAG")
                .requires("git"),
        )
        .arg(
            opt("rev", "Specific commit to use when installing from git")
                .value_name("SHA")
                .requires("git"),
        )
        .arg(
            opt("path", "Filesystem path to local crate to install")
                .value_name("PATH")
                .conflicts_with_all(&["git", "registry"]),
        )
        .arg(opt(
            "list",
            "list all installed packages and their versions",
        ))
        .arg_jobs()
        .arg(opt("force", "Force overwriting existing crates or binaries").short("f"))
        .arg_features()
        .arg(opt("debug", "Build in debug mode instead of release mode"))
        .arg_targets_bins_examples(
            "Install only the specified binary",
            "Install all binaries",
            "Install only the specified example",
            "Install all examples",
        )
        .arg_target_triple("Build for the target triple")
        .arg(opt("root", "Directory to install packages into").value_name("DIR"))
        .arg(
            opt("registry", "Registry to use")
                .value_name("REGISTRY")
                .requires("crate")
                .conflicts_with_all(&["git", "path"]),
        )
        .after_help(
            "\
This command manages Cargo's local set of installed binary crates. Only packages
which have [[bin]] targets can be installed, and all binaries are installed into
the installation root's `bin` folder. The installation root is determined, in
order of precedence, by `--root`, `$CARGO_INSTALL_ROOT`, the `install.root`
configuration key, and finally the home directory (which is either
`$CARGO_HOME` if set or `$HOME/.cargo` by default).

There are multiple sources from which a crate can be installed. The default
location is crates.io but the `--git`, `--path`, and `registry` flags can
change this source. If the source contains more than one package (such as
crates.io or a git repository with multiple crates) the `<crate>` argument is
required to indicate which crate should be installed.

Crates from crates.io can optionally specify the version they wish to install
via the `--version` flags, and similarly packages from git repositories can
optionally specify the branch, tag, or revision that should be installed. If a
crate has multiple binaries, the `--bin` argument can selectively install only
one of them, and if you'd rather install examples the `--example` argument can
be used as well.

By default cargo will refuse to overwrite existing binaries. The `--force` flag
enables overwriting existing binaries. Thus you can reinstall a crate with
`cargo install --force <crate>`.

Omitting the <crate> specification entirely will install the crate in the
current directory. This behaviour is deprecated, and it no longer works in the
Rust 2018 edition. Use the more explicit `install --path .` instead.

If the source is crates.io or `--git` then by default the crate will be built
in a temporary target directory. To avoid this, the target directory can be
specified by setting the `CARGO_TARGET_DIR` environment variable to a relative
path. In particular, this can be useful for caching build artifacts on
continuous integration systems.",
        )
}

pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
    let registry = args.registry(config)?;

    if let Some(path) = args.value_of_path("path", config) {
        config.reload_rooted_at(path)?;
    } else {
        config.reload_rooted_at(config.home().clone().into_path_unlocked())?;
    }

    let workspace = args.workspace(config).ok();
    let mut compile_opts = args.compile_options(config, CompileMode::Build, workspace.as_ref())?;

    compile_opts.build_config.release = !args.is_present("debug");

    let krates = args
        .values_of("crate")
        .unwrap_or_default()
        .collect::<Vec<_>>();

    let mut from_cwd = false;

    let source = if let Some(url) = args.value_of("git") {
        let url = url.to_url()?;
        let gitref = if let Some(branch) = args.value_of("branch") {
            GitReference::Branch(branch.to_string())
        } else if let Some(tag) = args.value_of("tag") {
            GitReference::Tag(tag.to_string())
        } else if let Some(rev) = args.value_of("rev") {
            GitReference::Rev(rev.to_string())
        } else {
            GitReference::Branch("master".to_string())
        };
        SourceId::for_git(&url, gitref)?
    } else if let Some(path) = args.value_of_path("path", config) {
        SourceId::for_path(&path)?
    } else if krates.is_empty() {
        from_cwd = true;
        SourceId::for_path(config.cwd())?
    } else if let Some(registry) = registry {
        SourceId::alt_registry(config, &registry)?
    } else {
        SourceId::crates_io(config)?
    };

    let version = args.value_of("version");
    let root = args.value_of("root");

    if args.is_present("list") {
        ops::install_list(root, config)?;
    } else {
        ops::install(
            root,
            krates,
            source,
            from_cwd,
            version,
            &compile_opts,
            args.is_present("force"),
        )?;
    }
    Ok(())
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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
//
//    https://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.

use crate::{
    additional_cpp_generator::AdditionalNeed,
    conversion::{
        api::{Api, Use},
        ConvertError,
    },
    known_types::KNOWN_TYPES,
    type_to_cpp::type_to_cpp,
    types::{make_ident, Namespace, TypeName},
};
use quote::quote;
use std::collections::{HashMap, HashSet};
use syn::{
    parse_quote, punctuated::Punctuated, ForeignItem, GenericArgument, Item, PathArguments,
    PathSegment, Type, TypePath, TypePtr,
};

use super::non_pod_struct::new_non_pod_struct;

/// Results of some type conversion, annotated with a list of every type encountered,
/// and optionally any extra API we need in order to use this type.
pub(crate) struct Annotated<T> {
    pub(crate) ty: T,
    pub(crate) types_encountered: HashSet<TypeName>,
    pub(crate) extra_apis: Vec<Api>,
}

impl<T> Annotated<T> {
    fn new(ty: T, types_encountered: HashSet<TypeName>, extra_apis: Vec<Api>) -> Self {
        Self {
            ty,
            types_encountered,
            extra_apis,
        }
    }

    fn map<T2, F: FnOnce(T) -> T2>(self, fun: F) -> Annotated<T2> {
        Annotated {
            ty: fun(self.ty),
            types_encountered: self.types_encountered,
            extra_apis: self.extra_apis,
        }
    }
}

pub(crate) struct TypeConverter {
    types_found: Vec<TypeName>,
    typedefs: HashMap<TypeName, Type>,
    concrete_templates: HashMap<String, TypeName>,
}

impl TypeConverter {
    pub(crate) fn new() -> Self {
        Self {
            types_found: Vec::new(),
            typedefs: HashMap::new(),
            concrete_templates: HashMap::new(),
        }
    }

    pub(crate) fn push(&mut self, ty: TypeName) {
        self.types_found.push(ty);
    }

    pub(crate) fn insert_typedef(&mut self, id: TypeName, target: Type) {
        self.typedefs.insert(id, target);
    }

    pub(crate) fn convert_boxed_type(
        &mut self,
        ty: Box<Type>,
        ns: &Namespace,
    ) -> Result<Annotated<Box<Type>>, ConvertError> {
        Ok(self.convert_type(*ty, ns)?.map(Box::new))
    }

    pub(crate) fn convert_type(
        &mut self,
        ty: Type,
        ns: &Namespace,
    ) -> Result<Annotated<Type>, ConvertError> {
        let result = match ty {
            Type::Path(p) => {
                let newp = self.convert_type_path(p, ns)?;
                if let Type::Path(newpp) = &newp.ty {
                    // Special handling because rust_Str (as emitted by bindgen)
                    // doesn't simply get renamed to a different type _identifier_.
                    // This plain type-by-value (as far as bindgen is concerned)
                    // is actually a &str.
                    if KNOWN_TYPES.should_dereference_in_cpp(newpp) {
                        Annotated::new(
                            Type::Reference(parse_quote! {
                                &str
                            }),
                            newp.types_encountered,
                            newp.extra_apis,
                        )
                    } else {
                        newp
                    }
                } else {
                    newp
                }
            }
            Type::Reference(mut r) => {
                let innerty = self.convert_boxed_type(r.elem, ns)?;
                r.elem = innerty.ty;
                Annotated::new(
                    Type::Reference(r),
                    innerty.types_encountered,
                    innerty.extra_apis,
                )
            }
            Type::Ptr(ptr) => self.convert_ptr_to_reference(ptr, ns)?,
            _ => Annotated::new(ty, HashSet::new(), Vec::new()),
        };
        Ok(result)
    }

    fn convert_type_path(
        &mut self,
        mut typ: TypePath,
        ns: &Namespace,
    ) -> Result<Annotated<Type>, ConvertError> {
        let mut types_encountered = HashSet::new();
        if typ.path.segments.iter().next().unwrap().ident != "root" {
            let ty = TypeName::from_type_path(&typ);
            // If the type looks like it is unqualified, check we know it
            // already, and if not, qualify it according to the current
            // namespace. This is a bit of a shortcut compared to having a full
            // resolution pass which can search all known namespaces.
            if !KNOWN_TYPES.is_known_type(&ty) {
                let num_segments = typ.path.segments.len();
                if num_segments > 1 {
                    return Err(ConvertError::UnsupportedBuiltInType(ty));
                }
                if !self.types_found.contains(&ty) {
                    typ.path.segments = std::iter::once(&"root".to_string())
                        .chain(ns.iter())
                        .map(|s| {
                            let i = make_ident(s);
                            parse_quote! { #i }
                        })
                        .chain(typ.path.segments.into_iter())
                        .collect();
                }
            }
        }

        typ.path.segments = typ
            .path
            .segments
            .into_iter()
            .map(|s| -> Result<PathSegment, ConvertError> {
                let ident = &s.ident;
                let args = match s.arguments {
                    PathArguments::AngleBracketed(mut ab) => {
                        let mut innerty = self.convert_punctuated(ab.args, ns)?;
                        ab.args = innerty.ty;
                        types_encountered.extend(innerty.types_encountered.drain());
                        PathArguments::AngleBracketed(ab)
                    }
                    _ => s.arguments,
                };
                Ok(parse_quote!( #ident #args ))
            })
            .collect::<Result<_, _>>()?;

        let mut last_seg_args = Self::get_last_segment_args(&typ);

        let mut tn = TypeName::from_type_path(&typ);
        types_encountered.insert(tn.clone());
        // Let's see if this is a typedef.
        let typ = match self.resolve_typedef(&tn)? {
            None => typ,
            Some(Type::Path(resolved_tp)) => {
                types_encountered.insert(TypeName::from_type_path(&resolved_tp));
                let typedef_target_args = Self::get_last_segment_args(&resolved_tp);
                if let Some(typedef_target_args) = typedef_target_args {
                    if last_seg_args.is_some() {
                        return Err(ConvertError::ConflictingTemplatedArgsWithTypedef(tn));
                    }
                    last_seg_args = Some(typedef_target_args);
                    tn = TypeName::from_type_path(&resolved_tp);
                }
                resolved_tp.clone()
            }
            Some(other) => return Ok(Annotated::new(other.clone(), HashSet::new(), Vec::new())),
        };

        // This will strip off any path arguments...
        let mut typ = KNOWN_TYPES.known_type_substitute_path(&typ).unwrap_or(typ);
        let mut extra_apis = Vec::new();
        // but then we'll put them back again as necessary.
        if let Some(last_seg_args) = last_seg_args {
            let last_seg = typ.path.segments.last_mut().unwrap();
            last_seg.arguments = last_seg_args;
            // Is it one of the things built into cxx?
            if !KNOWN_TYPES.is_cxx_acceptable_generic(&tn) {
                // Oh poop. It's a generic type which cxx won't be able to handle.
                // We'll have to come up with a concrete type in both the cxx::bridge (in Rust)
                // and a corresponding typedef in C++.
                let (new_tn, api) = self.get_templated_typename(&Type::Path(typ));
                typ = new_tn.to_type_path();
                extra_apis.extend(api.into_iter());
                types_encountered.remove(&tn);
                types_encountered.insert(new_tn);
            }
        }
        Ok(Annotated::new(
            Type::Path(typ),
            types_encountered,
            extra_apis,
        ))
    }

    fn get_last_segment_args(typ: &TypePath) -> Option<PathArguments> {
        let mut seg_iter = typ.path.segments.iter().peekable();
        while let Some(seg) = seg_iter.next() {
            if !seg.arguments.is_empty() {
                if seg_iter.peek().is_some() {
                    panic!("Did not expect bindgen to create a type with path arguments on a non-final segment")
                } else {
                    return Some(seg.arguments.clone());
                }
            }
        }
        None
    }

    fn convert_punctuated<P>(
        &mut self,
        pun: Punctuated<GenericArgument, P>,
        ns: &Namespace,
    ) -> Result<Annotated<Punctuated<GenericArgument, P>>, ConvertError>
    where
        P: Default,
    {
        let mut new_pun = Punctuated::new();
        let mut types_encountered = HashSet::new();
        let mut extra_apis = Vec::new();
        for arg in pun.into_iter() {
            new_pun.push(match arg {
                GenericArgument::Type(t) => {
                    let mut innerty = self.convert_type(t, ns)?;
                    types_encountered.extend(innerty.types_encountered.drain());
                    extra_apis.extend(innerty.extra_apis.drain(..));
                    GenericArgument::Type(innerty.ty)
                }
                _ => arg,
            });
        }
        Ok(Annotated::new(new_pun, types_encountered, extra_apis))
    }

    fn resolve_typedef<'b>(&'b self, tn: &TypeName) -> Result<Option<&'b Type>, ConvertError> {
        match self.typedefs.get(&tn) {
            None => Ok(None),
            Some(resolution) => match resolution {
                Type::Path(typ) => {
                    let tn = TypeName::from_type_path(typ);
                    Ok(Some(self.resolve_typedef(&tn)?.unwrap_or(resolution)))
                }
                _ => Ok(Some(resolution)),
            },
        }
    }

    fn convert_ptr_to_reference(
        &mut self,
        ptr: TypePtr,
        ns: &Namespace,
    ) -> Result<Annotated<Type>, ConvertError> {
        let mutability = ptr.mutability;
        let elem = self.convert_boxed_type(ptr.elem, ns)?;
        // TODO - in the future, we should check if this is a rust::Str and throw
        // a wobbler if not. rust::Str should only be seen _by value_ in C++
        // headers; it manifests as &str in Rust but on the C++ side it must
        // be a plain value. We should detect and abort.
        Ok(elem.map(|elem| match mutability {
            Some(_) => Type::Path(parse_quote! {
                Pin < & #mutability #elem >
            }),
            None => Type::Reference(parse_quote! {
                & #elem
            }),
        }))
    }

    fn add_concrete_type(&self, tyname: &TypeName, rs_definition: &Type) -> Api {
        let final_ident = make_ident(tyname.get_final_ident());
        let bridge_item = Some(Item::Impl(parse_quote! {
            impl UniquePtr<#final_ident> {}
        }));
        let mut fulltypath: Vec<_> = ["bindgen", "root"].iter().map(|x| make_ident(x)).collect();
        fulltypath.push(final_ident.clone());
        let tynamestring = tyname.to_cpp_name();
        Api {
            ns: tyname.get_namespace().clone(),
            id: final_ident.clone(),
            use_stmt: Use::Unused,
            global_items: vec![Item::Impl(parse_quote! {
                unsafe impl cxx::ExternType for #(#fulltypath)::* {
                    type Id = cxx::type_id!(#tynamestring);
                    type Kind = cxx::kind::Opaque;
                }
            })],
            bridge_item,
            extern_c_mod_item: Some(ForeignItem::Verbatim(quote! {
                type #final_ident = super::bindgen::root::#final_ident;
            })),
            additional_cpp: Some(AdditionalNeed::ConcreteTemplatedTypeTypedef(
                tyname.clone(),
                Box::new(rs_definition.clone()),
            )),
            deps: HashSet::new(),
            id_for_allowlist: None,
            bindgen_mod_item: Some(Item::Struct(new_non_pod_struct(final_ident))),
            impl_entry: None,
        }
    }

    fn get_templated_typename(&mut self, rs_definition: &Type) -> (TypeName, Option<Api>) {
        let count = self.concrete_templates.len();
        // We just use this as a hash key, essentially.
        let cpp_definition = type_to_cpp(rs_definition);
        let e = self.concrete_templates.get(&cpp_definition);
        match e {
            Some(tn) => (tn.clone(), None),
            None => {
                let tn = TypeName::new(&Namespace::new(), &format!("AutocxxConcrete{}", count));
                self.concrete_templates
                    .insert(cpp_definition.clone(), tn.clone());
                let api = self.add_concrete_type(&tn, rs_definition);
                (tn, Some(api))
            }
        }
    }
}
<commit_msg>Simplify resolve_typedef.<commit_after>// Copyright 2020 Google LLC
//
// 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
//
//    https://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.

use crate::{
    additional_cpp_generator::AdditionalNeed,
    conversion::{
        api::{Api, Use},
        ConvertError,
    },
    known_types::KNOWN_TYPES,
    type_to_cpp::type_to_cpp,
    types::{make_ident, Namespace, TypeName},
};
use quote::quote;
use std::collections::{HashMap, HashSet};
use syn::{
    parse_quote, punctuated::Punctuated, ForeignItem, GenericArgument, Item, PathArguments,
    PathSegment, Type, TypePath, TypePtr,
};

use super::non_pod_struct::new_non_pod_struct;

/// Results of some type conversion, annotated with a list of every type encountered,
/// and optionally any extra API we need in order to use this type.
pub(crate) struct Annotated<T> {
    pub(crate) ty: T,
    pub(crate) types_encountered: HashSet<TypeName>,
    pub(crate) extra_apis: Vec<Api>,
}

impl<T> Annotated<T> {
    fn new(ty: T, types_encountered: HashSet<TypeName>, extra_apis: Vec<Api>) -> Self {
        Self {
            ty,
            types_encountered,
            extra_apis,
        }
    }

    fn map<T2, F: FnOnce(T) -> T2>(self, fun: F) -> Annotated<T2> {
        Annotated {
            ty: fun(self.ty),
            types_encountered: self.types_encountered,
            extra_apis: self.extra_apis,
        }
    }
}

pub(crate) struct TypeConverter {
    types_found: Vec<TypeName>,
    typedefs: HashMap<TypeName, Type>,
    concrete_templates: HashMap<String, TypeName>,
}

impl TypeConverter {
    pub(crate) fn new() -> Self {
        Self {
            types_found: Vec::new(),
            typedefs: HashMap::new(),
            concrete_templates: HashMap::new(),
        }
    }

    pub(crate) fn push(&mut self, ty: TypeName) {
        self.types_found.push(ty);
    }

    pub(crate) fn insert_typedef(&mut self, id: TypeName, target: Type) {
        self.typedefs.insert(id, target);
    }

    pub(crate) fn convert_boxed_type(
        &mut self,
        ty: Box<Type>,
        ns: &Namespace,
    ) -> Result<Annotated<Box<Type>>, ConvertError> {
        Ok(self.convert_type(*ty, ns)?.map(Box::new))
    }

    pub(crate) fn convert_type(
        &mut self,
        ty: Type,
        ns: &Namespace,
    ) -> Result<Annotated<Type>, ConvertError> {
        let result = match ty {
            Type::Path(p) => {
                let newp = self.convert_type_path(p, ns)?;
                if let Type::Path(newpp) = &newp.ty {
                    // Special handling because rust_Str (as emitted by bindgen)
                    // doesn't simply get renamed to a different type _identifier_.
                    // This plain type-by-value (as far as bindgen is concerned)
                    // is actually a &str.
                    if KNOWN_TYPES.should_dereference_in_cpp(newpp) {
                        Annotated::new(
                            Type::Reference(parse_quote! {
                                &str
                            }),
                            newp.types_encountered,
                            newp.extra_apis,
                        )
                    } else {
                        newp
                    }
                } else {
                    newp
                }
            }
            Type::Reference(mut r) => {
                let innerty = self.convert_boxed_type(r.elem, ns)?;
                r.elem = innerty.ty;
                Annotated::new(
                    Type::Reference(r),
                    innerty.types_encountered,
                    innerty.extra_apis,
                )
            }
            Type::Ptr(ptr) => self.convert_ptr_to_reference(ptr, ns)?,
            _ => Annotated::new(ty, HashSet::new(), Vec::new()),
        };
        Ok(result)
    }

    fn convert_type_path(
        &mut self,
        mut typ: TypePath,
        ns: &Namespace,
    ) -> Result<Annotated<Type>, ConvertError> {
        let mut types_encountered = HashSet::new();
        if typ.path.segments.iter().next().unwrap().ident != "root" {
            let ty = TypeName::from_type_path(&typ);
            // If the type looks like it is unqualified, check we know it
            // already, and if not, qualify it according to the current
            // namespace. This is a bit of a shortcut compared to having a full
            // resolution pass which can search all known namespaces.
            if !KNOWN_TYPES.is_known_type(&ty) {
                let num_segments = typ.path.segments.len();
                if num_segments > 1 {
                    return Err(ConvertError::UnsupportedBuiltInType(ty));
                }
                if !self.types_found.contains(&ty) {
                    typ.path.segments = std::iter::once(&"root".to_string())
                        .chain(ns.iter())
                        .map(|s| {
                            let i = make_ident(s);
                            parse_quote! { #i }
                        })
                        .chain(typ.path.segments.into_iter())
                        .collect();
                }
            }
        }

        typ.path.segments = typ
            .path
            .segments
            .into_iter()
            .map(|s| -> Result<PathSegment, ConvertError> {
                let ident = &s.ident;
                let args = match s.arguments {
                    PathArguments::AngleBracketed(mut ab) => {
                        let mut innerty = self.convert_punctuated(ab.args, ns)?;
                        ab.args = innerty.ty;
                        types_encountered.extend(innerty.types_encountered.drain());
                        PathArguments::AngleBracketed(ab)
                    }
                    _ => s.arguments,
                };
                Ok(parse_quote!( #ident #args ))
            })
            .collect::<Result<_, _>>()?;

        let mut last_seg_args = Self::get_last_segment_args(&typ);

        let mut tn = TypeName::from_type_path(&typ);
        types_encountered.insert(tn.clone());
        // Let's see if this is a typedef.
        let typ = match self.resolve_typedef(&tn) {
            None => typ,
            Some(Type::Path(resolved_tp)) => {
                types_encountered.insert(TypeName::from_type_path(&resolved_tp));
                let typedef_target_args = Self::get_last_segment_args(&resolved_tp);
                if let Some(typedef_target_args) = typedef_target_args {
                    if last_seg_args.is_some() {
                        return Err(ConvertError::ConflictingTemplatedArgsWithTypedef(tn));
                    }
                    last_seg_args = Some(typedef_target_args);
                    tn = TypeName::from_type_path(&resolved_tp);
                }
                resolved_tp.clone()
            }
            Some(other) => return Ok(Annotated::new(other.clone(), HashSet::new(), Vec::new())),
        };

        // This will strip off any path arguments...
        let mut typ = KNOWN_TYPES.known_type_substitute_path(&typ).unwrap_or(typ);
        let mut extra_apis = Vec::new();
        // but then we'll put them back again as necessary.
        if let Some(last_seg_args) = last_seg_args {
            let last_seg = typ.path.segments.last_mut().unwrap();
            last_seg.arguments = last_seg_args;
            // Is it one of the things built into cxx?
            if !KNOWN_TYPES.is_cxx_acceptable_generic(&tn) {
                // Oh poop. It's a generic type which cxx won't be able to handle.
                // We'll have to come up with a concrete type in both the cxx::bridge (in Rust)
                // and a corresponding typedef in C++.
                let (new_tn, api) = self.get_templated_typename(&Type::Path(typ));
                typ = new_tn.to_type_path();
                extra_apis.extend(api.into_iter());
                types_encountered.remove(&tn);
                types_encountered.insert(new_tn);
            }
        }
        Ok(Annotated::new(
            Type::Path(typ),
            types_encountered,
            extra_apis,
        ))
    }

    fn get_last_segment_args(typ: &TypePath) -> Option<PathArguments> {
        let mut seg_iter = typ.path.segments.iter().peekable();
        while let Some(seg) = seg_iter.next() {
            if !seg.arguments.is_empty() {
                if seg_iter.peek().is_some() {
                    panic!("Did not expect bindgen to create a type with path arguments on a non-final segment")
                } else {
                    return Some(seg.arguments.clone());
                }
            }
        }
        None
    }

    fn convert_punctuated<P>(
        &mut self,
        pun: Punctuated<GenericArgument, P>,
        ns: &Namespace,
    ) -> Result<Annotated<Punctuated<GenericArgument, P>>, ConvertError>
    where
        P: Default,
    {
        let mut new_pun = Punctuated::new();
        let mut types_encountered = HashSet::new();
        let mut extra_apis = Vec::new();
        for arg in pun.into_iter() {
            new_pun.push(match arg {
                GenericArgument::Type(t) => {
                    let mut innerty = self.convert_type(t, ns)?;
                    types_encountered.extend(innerty.types_encountered.drain());
                    extra_apis.extend(innerty.extra_apis.drain(..));
                    GenericArgument::Type(innerty.ty)
                }
                _ => arg,
            });
        }
        Ok(Annotated::new(new_pun, types_encountered, extra_apis))
    }

    fn resolve_typedef<'b>(&'b self, tn: &TypeName) -> Option<&'b Type> {
        self.typedefs.get(&tn).and_then(|resolution| match resolution {
            Type::Path(typ) => {
                let tn = TypeName::from_type_path(typ);
                Some(self.resolve_typedef(&tn).unwrap_or(resolution))
            }
            _ => Some(resolution),
        })
    }

    fn convert_ptr_to_reference(
        &mut self,
        ptr: TypePtr,
        ns: &Namespace,
    ) -> Result<Annotated<Type>, ConvertError> {
        let mutability = ptr.mutability;
        let elem = self.convert_boxed_type(ptr.elem, ns)?;
        // TODO - in the future, we should check if this is a rust::Str and throw
        // a wobbler if not. rust::Str should only be seen _by value_ in C++
        // headers; it manifests as &str in Rust but on the C++ side it must
        // be a plain value. We should detect and abort.
        Ok(elem.map(|elem| match mutability {
            Some(_) => Type::Path(parse_quote! {
                Pin < & #mutability #elem >
            }),
            None => Type::Reference(parse_quote! {
                & #elem
            }),
        }))
    }

    fn add_concrete_type(&self, tyname: &TypeName, rs_definition: &Type) -> Api {
        let final_ident = make_ident(tyname.get_final_ident());
        let bridge_item = Some(Item::Impl(parse_quote! {
            impl UniquePtr<#final_ident> {}
        }));
        let mut fulltypath: Vec<_> = ["bindgen", "root"].iter().map(|x| make_ident(x)).collect();
        fulltypath.push(final_ident.clone());
        let tynamestring = tyname.to_cpp_name();
        Api {
            ns: tyname.get_namespace().clone(),
            id: final_ident.clone(),
            use_stmt: Use::Unused,
            global_items: vec![Item::Impl(parse_quote! {
                unsafe impl cxx::ExternType for #(#fulltypath)::* {
                    type Id = cxx::type_id!(#tynamestring);
                    type Kind = cxx::kind::Opaque;
                }
            })],
            bridge_item,
            extern_c_mod_item: Some(ForeignItem::Verbatim(quote! {
                type #final_ident = super::bindgen::root::#final_ident;
            })),
            additional_cpp: Some(AdditionalNeed::ConcreteTemplatedTypeTypedef(
                tyname.clone(),
                Box::new(rs_definition.clone()),
            )),
            deps: HashSet::new(),
            id_for_allowlist: None,
            bindgen_mod_item: Some(Item::Struct(new_non_pod_struct(final_ident))),
            impl_entry: None,
        }
    }

    fn get_templated_typename(&mut self, rs_definition: &Type) -> (TypeName, Option<Api>) {
        let count = self.concrete_templates.len();
        // We just use this as a hash key, essentially.
        let cpp_definition = type_to_cpp(rs_definition);
        let e = self.concrete_templates.get(&cpp_definition);
        match e {
            Some(tn) => (tn.clone(), None),
            None => {
                let tn = TypeName::new(&Namespace::new(), &format!("AutocxxConcrete{}", count));
                self.concrete_templates
                    .insert(cpp_definition.clone(), tn.clone());
                let api = self.add_concrete_type(&tn, rs_definition);
                (tn, Some(api))
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::prelude::*;
use std::fs::File;
use std::path::Path;
use diesel::result::Error;
use diesel;
use diesel::*;
use self::models::{ImageLocation, SubmitImageLocation};
use database::schema::image_locations::dsl::*;
use database::schema::image_locations;
use super::database;

pub mod models;

static IMAGE_PATH: &'static str = "/static/media";

pub fn load_image(file_name: String) -> Option<File> {
    let conn = database::get_db_connection();

    let image_location: ImageLocation = match image_locations.filter(name.eq(file_name)).
        first::<ImageLocation>(&*conn) {
        Ok(image_location) => image_location,
        Err(_) => return None,
    };

    match File::open(image_location.url) {
        Ok(file) => Some(file),
        Err(_) => None,
    }
}

/// Uploads the image to the server with the given filename.
/// Returns the identifier of the image.
pub fn store_image(image_name: String, image: Vec<u8>) -> io::Result<String> {
    let file_path: String = format!("{path}/{filename}", path = IMAGE_PATH, filename = image_name);
    let mut file = File::create(Path::new( format!(".{path}", path=file_path).as_str() )).unwrap();
    file.write(image.as_slice()).unwrap();

    Ok(file_path)
}

pub fn insert_image_location(image_name: String, image_path: String) -> Result<i32, Error> {
    let conn = &*database::get_db_connection();

    println!("inserting image path {}", image_path.clone());/

    let image_location = SubmitImageLocation { name: image_name, url: image_path };

    match diesel::insert(&image_location)
        .into(image_locations)
        .execute(conn) {
        Ok(_) => (),
        Err(e) => return Err(e),
    };
    println!("Getting image id!");

    match image_locations::table
        .order(image_locations::id.desc())
        .first::<ImageLocation>(conn) {
        Ok(img_loc) => Ok(img_loc.id),
        Err(e) => Err(e),
    }
}<commit_msg>Images - Fixed: Extra / was removed...<commit_after>use std::io;
use std::io::prelude::*;
use std::fs::File;
use std::path::Path;
use diesel::result::Error;
use diesel;
use diesel::*;
use self::models::{ImageLocation, SubmitImageLocation};
use database::schema::image_locations::dsl::*;
use database::schema::image_locations;
use super::database;

pub mod models;

static IMAGE_PATH: &'static str = "/static/media";

pub fn load_image(file_name: String) -> Option<File> {
    let conn = database::get_db_connection();

    let image_location: ImageLocation = match image_locations.filter(name.eq(file_name)).
        first::<ImageLocation>(&*conn) {
        Ok(image_location) => image_location,
        Err(_) => return None,
    };

    match File::open(image_location.url) {
        Ok(file) => Some(file),
        Err(_) => None,
    }
}

/// Uploads the image to the server with the given filename.
/// Returns the identifier of the image.
pub fn store_image(image_name: String, image: Vec<u8>) -> io::Result<String> {
    let file_path: String = format!("{path}/{filename}", path = IMAGE_PATH, filename = image_name);
    let mut file = File::create(Path::new( format!(".{path}", path=file_path).as_str() )).unwrap();
    file.write(image.as_slice()).unwrap();

    Ok(file_path)
}

pub fn insert_image_location(image_name: String, image_path: String) -> Result<i32, Error> {
    let conn = &*database::get_db_connection();

    println!("inserting image path {}", image_path.clone());

    let image_location = SubmitImageLocation { name: image_name, url: image_path };

    match diesel::insert(&image_location)
        .into(image_locations)
        .execute(conn) {
        Ok(_) => (),
        Err(e) => return Err(e),
    };
    println!("Getting image id!");

    match image_locations::table
        .order(image_locations::id.desc())
        .first::<ImageLocation>(conn) {
        Ok(img_loc) => Ok(img_loc.id),
        Err(e) => Err(e),
    }
}<|endoftext|>