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

use std::io::Cursor;

use anyhow::anyhow;
use anyhow::bail;
use anyhow::Context;
use bufsize::SizeCounter;
use bytes::buf::Writer;
use bytes::Buf;
use bytes::BufMut;
use bytes::Bytes;
use bytes::BytesMut;
use ghost::phantom;
use serde_json::ser::CompactFormatter;
use serde_json::ser::Formatter;

use crate::binary_type::CopyFromBuf;
use crate::bufext::BufExt;
use crate::bufext::BufMutExt;
use crate::bufext::DeserializeSource;
use crate::deserialize::Deserialize;
use crate::errors::ProtocolError;
use crate::framing::Framing;
use crate::protocol::should_break;
use crate::protocol::Field;
use crate::protocol::Protocol;
use crate::protocol::ProtocolReader;
use crate::protocol::ProtocolWriter;
use crate::protocol::DEFAULT_RECURSION_DEPTH;
use crate::serialize::Serialize;
use crate::thrift_protocol::MessageType;
use crate::thrift_protocol::ProtocolID;
use crate::ttype::TType;
use crate::Result;

#[phantom]
#[derive(Copy, Clone)]
pub struct SimpleJsonProtocol<F = Bytes>;

pub struct SimpleJsonProtocolSerializer<B: BufMutExt> {
    buffer: Writer<B>,
    state: Vec<SerializationState>,
}

pub struct SimpleJsonProtocolDeserializer<B> {
    buffer: B,
    remaining: usize,
}

impl<F> Protocol for SimpleJsonProtocol<F>
where
    F: Framing + 'static,
{
    type Frame = F;
    type Sizer = SimpleJsonProtocolSerializer<SizeCounter>;
    type Serializer = SimpleJsonProtocolSerializer<F::EncBuf>;
    type Deserializer = SimpleJsonProtocolDeserializer<F::DecBuf>;

    const PROTOCOL_ID: ProtocolID = ProtocolID::SimpleJSONProtocol;

    fn serializer<SZ, SER>(size: SZ, ser: SER) -> <Self::Serializer as ProtocolWriter>::Final
    where
        SZ: FnOnce(&mut Self::Sizer),
        SER: FnOnce(&mut Self::Serializer),
    {
        // Instantiate a serializer with SizeCounter to count up the output buffer size
        let mut sizer = SimpleJsonProtocolSerializer {
            buffer: SizeCounter::new().writer(),
            state: vec![SerializationState::NotInContainer],
        };
        size(&mut sizer);
        let sz = sizer.finish();

        // Now that we have the size, allocate an output buffer and serialize into it
        let mut buf = SimpleJsonProtocolSerializer {
            buffer: F::enc_with_capacity(sz).writer(),
            state: vec![SerializationState::NotInContainer],
        };
        ser(&mut buf);

        // Done
        buf.finish()
    }

    fn deserializer(buf: F::DecBuf) -> Self::Deserializer {
        SimpleJsonProtocolDeserializer::new(buf)
    }

    fn into_buffer(deser: Self::Deserializer) -> F::DecBuf {
        deser.into_inner()
    }
}

impl<B: BufMutExt> SimpleJsonProtocolSerializer<B> {
    fn possibly_write_comma(&mut self) {
        match self
            .state
            .last()
            .expect("Invariant of encoding state violated")
        {
            SerializationState::JustEnteredContainer => {
                CompactFormatter
                    .begin_object_key(&mut self.buffer, true)
                    .expect("Somehow failed to do \"io\" on a buffer");
                *self
                    .state
                    .last_mut()
                    .expect("Invariant of encoding state violated") =
                    SerializationState::InContainerValue;
            }
            SerializationState::InContainerKey
            | SerializationState::InContainerValue
            | SerializationState::NotInContainer => CompactFormatter
                .begin_object_key(&mut self.buffer, false)
                .expect("Somehow failed to do \"io\" on a buffer"),
        }
    }

    fn writing_key(&mut self) -> bool {
        match self
            .state
            .last()
            .expect("Invariant of encoding state violated")
        {
            SerializationState::InContainerKey => true,
            _ => false,
        }
    }
}

#[derive(Debug)]
enum SerializationState {
    JustEnteredContainer,
    InContainerKey,
    InContainerValue,
    NotInContainer,
}

impl<B: BufMutExt> ProtocolWriter for SimpleJsonProtocolSerializer<B> {
    type Final = B::Final; // Our final form is whatever the buffer produces

    // TODO what to do here
    fn write_message_begin(&mut self, name: &str, msgtype: MessageType, seqid: u32) {
        self.write_list_begin(TType::Stop, 0);
        self.write_list_value_begin();
        self.write_string(name);
        self.write_list_value_begin();
        self.write_byte(msgtype as i8);
        self.write_list_value_begin();
        self.write_i32(seqid as i32);
    }

    #[inline]
    fn write_message_end(&mut self) {
        self.write_list_end();
    }

    #[inline]
    fn write_struct_begin(&mut self, _name: &str) {
        CompactFormatter
            .begin_object(&mut self.buffer)
            .expect("Somehow failed to do \"io\" on a buffer");
        self.state.push(SerializationState::JustEnteredContainer);
    }

    #[inline]
    fn write_struct_end(&mut self) {
        CompactFormatter
            .end_object(&mut self.buffer)
            .expect("Somehow failed to do \"io\" on a buffer");
        self.state.pop();
    }

    #[inline]
    fn write_field_begin(&mut self, name: &str, _type_id: TType, _id: i16) {
        self.possibly_write_comma();
        self.write_string(name);
        CompactFormatter
            .end_object_key(&mut self.buffer)
            .expect("Somehow failed to do \"io\" on a buffer");
        CompactFormatter
            .begin_object_value(&mut self.buffer)
            .expect("Somehow failed to do \"io\" on a buffer");
    }

    #[inline]
    fn write_field_end(&mut self) {}

    #[inline]
    fn write_field_stop(&mut self) {}

    fn write_map_begin(&mut self, _key_type: TType, _value_type: TType, _size: usize) {
        self.state.push(SerializationState::JustEnteredContainer);
        CompactFormatter
            .begin_object(&mut self.buffer)
            .expect("Somehow failed to do \"io\" on a buffer");
    }

    fn write_map_key_begin(&mut self) {
        self.possibly_write_comma();
        *self
            .state
            .last_mut()
            .expect("Invariant of encoding state violated") = SerializationState::InContainerKey;
    }

    fn write_map_value_begin(&mut self) {
        CompactFormatter
            .end_object_key(&mut self.buffer)
            .expect("Somehow failed to do \"io\" on a buffer");
        CompactFormatter
            .begin_object_value(&mut self.buffer)
            .expect("Somehow failed to do \"io\" on a buffer");
        *self
            .state
            .last_mut()
            .expect("Invariant of encoding state violated") = SerializationState::InContainerValue;
    }

    #[inline]
    fn write_map_end(&mut self) {
        CompactFormatter
            .end_object(&mut self.buffer)
            .expect("Somehow failed to do \"io\" on a buffer");
        self.state.pop();
    }

    fn write_list_begin(&mut self, _elem_type: TType, _size: usize) {
        CompactFormatter
            .begin_array(&mut self.buffer)
            .expect("Somehow failed to do \"io\" on a buffer");
        self.state.push(SerializationState::JustEnteredContainer);
    }

    fn write_list_value_begin(&mut self) {
        self.possibly_write_comma();
    }

    #[inline]
    fn write_list_end(&mut self) {
        CompactFormatter
            .end_array(&mut self.buffer)
            .expect("Somehow failed to do \"io\" on a buffer");
        self.state.pop();
    }

    fn write_set_begin(&mut self, elem_type: TType, size: usize) {
        self.write_list_begin(elem_type, size);
    }

    fn write_set_value_begin(&mut self) {
        self.write_list_value_begin();
    }

    fn write_set_end(&mut self) {
        self.write_list_end();
    }

    fn write_bool(&mut self, value: bool) {
        CompactFormatter
            .write_bool(&mut self.buffer, value)
            .expect("Somehow failed to do \"io\" on a buffer");
    }

    fn write_byte(&mut self, value: i8) {
        if self.writing_key() {
            self.write_string(&value.to_string());
            return;
        }
        CompactFormatter
            .write_i8(&mut self.buffer, value)
            .expect("Somehow failed to do \"io\" on a buffer");
    }

    fn write_i16(&mut self, value: i16) {
        if self.writing_key() {
            self.write_string(&value.to_string());
            return;
        }
        CompactFormatter
            .write_i16(&mut self.buffer, value)
            .expect("Somehow failed to do \"io\" on a buffer");
    }

    fn write_i32(&mut self, value: i32) {
        if self.writing_key() {
            self.write_string(&value.to_string());
            return;
        }
        CompactFormatter
            .write_i32(&mut self.buffer, value)
            .expect("Somehow failed to do \"io\" on a buffer");
    }

    fn write_i64(&mut self, value: i64) {
        if self.writing_key() {
            self.write_string(&value.to_string());
            return;
        }
        CompactFormatter
            .write_i64(&mut self.buffer, value)
            .expect("Somehow failed to do \"io\" on a buffer");
    }

    fn write_double(&mut self, value: f64) {
        if self.writing_key() {
            self.write_string(&value.to_string());
            return;
        }
        CompactFormatter
            .write_f64(&mut self.buffer, value)
            .expect("Somehow failed to do \"io\" on a buffer");
    }

    fn write_float(&mut self, value: f32) {
        if self.writing_key() {
            self.write_string(&value.to_string());
            return;
        }
        CompactFormatter
            .write_f32(&mut self.buffer, value)
            .expect("Somehow failed to do \"io\" on a buffer");
    }

    fn write_string(&mut self, value: &str) {
        serde_json::to_writer(&mut self.buffer, value)
            .expect("Somehow failed to do \"io\" on a buffer");
    }

    fn write_binary(&mut self, value: &[u8]) {
        CompactFormatter
            .begin_string(&mut self.buffer)
            .expect("Somehow failed to do \"io\" on a buffer");
        CompactFormatter
            .write_raw_fragment(
                &mut self.buffer,
                &base64::encode_config(&value, base64::STANDARD_NO_PAD),
            )
            .expect("Somehow failed to do \"io\" on a buffer");
        CompactFormatter
            .end_string(&mut self.buffer)
            .expect("Somehow failed to do \"io\" on a buffer");
    }

    fn finish(self) -> B::Final {
        self.buffer.into_inner().finalize()
    }
}

#[derive(Debug)]
enum CommaState {
    Trailing,
    NonTrailing,
    NoComma,
    End,
}

impl<B: Buf> SimpleJsonProtocolDeserializer<B> {
    pub fn new(buffer: B) -> Self {
        let remaining = buffer.remaining();
        SimpleJsonProtocolDeserializer { buffer, remaining }
    }

    pub fn into_inner(self) -> B {
        self.buffer
    }

    // TODO(azw): codify this (number of bytes left) in the Deserializer API
    // `bytes` (named `chunks` in bytes1.0) does not represent a contiguous slice
    // of the remaining bytes. All we can do is check if there is a byte to return
    /// Returns a byte from the underly buffer if there is enough remaining
    pub fn peek(&self) -> Option<u8> {
        // fast path like https://docs.rs/bytes/1.0.1/src/bytes/buf/buf_impl.rs.html#18
        if !self.buffer.chunk().is_empty() {
            Some(self.buffer.chunk()[0])
        } else {
            None
        }
    }

    /// Like peek but panics if there is none remaining
    fn peek_can_panic(&self) -> u8 {
        self.buffer.chunk()[0]
    }

    fn strip_whitespace(&mut self) {
        while let Some(b) = self.peek() {
            if !&[b' ', b'\t', b'\n', b'\r'].contains(&b) {
                break;
            }
            self.advance(1);
        }
    }
    // Validates that next chars is `val`
    fn eat_only(&mut self, val: &[u8]) -> Result<()> {
        if self.remaining < val.len() {
            bail!(
                "Expected the following chars: {:?}, not enough bytes remaining",
                String::from_utf8_lossy(val)
            )
        }

        for to_check in val {
            let b = self.peek_can_panic();
            if b != *to_check {
                // TODO(azw): better error messages
                bail!("Expected {} got {}", to_check, b)
            }
            self.advance(1);
        }
        Ok(())
    }

    // Validates that next chars is `val`. Strip whitespace before and after
    fn eat(&mut self, val: &[u8]) -> Result<()> {
        self.strip_whitespace();
        self.eat_only(val)?;
        self.strip_whitespace();
        Ok(())
    }

    fn advance(&mut self, len: usize) {
        self.buffer.advance(len);

        // advance will panic if we try to advance more than remaining
        self.remaining -= len
    }

    // Attempts to eat a comma, returns
    // Trailing if this a "trailing" comma, where trailing means its
    //   trailed by the `trailing` byte
    // NonTrailing if its read a comma that isn't trailing
    // NoComma if it found no comma in the middle of the container
    // End if it correctly found no comma at the end of the container
    fn possibly_read_comma(&mut self, trailing: u8) -> CommaState {
        match self.eat(b",") {
            Ok(()) => match self.peek() {
                Some(b) if b == trailing => CommaState::Trailing,
                _ => CommaState::NonTrailing,
            },
            _ => match self.peek() {
                Some(b) if b == trailing => CommaState::End,
                _ => CommaState::NoComma,
            },
        }
    }

    fn read_json_number(&mut self) -> Result<serde_json::Number> {
        self.strip_whitespace();
        let mut ret = Vec::new();

        let as_string = match self.peek() {
            Some(b'"') => {
                self.advance(1);
                true
            }
            _ => false,
        };

        while let Some(b) = self.peek() {
            match b {
                b' ' | b'\t' | b'\n' | b'\r' | b'}' | b']' | b',' | b':' | b'"' => {
                    if as_string && b == b'"' {
                        self.advance(1);
                    }
                    break;
                }
                _ => {
                    ret.push(b);
                    self.advance(1);
                }
            }
        }

        let v: std::result::Result<serde_json::Value, _> = serde_json::from_slice(&ret);
        match v {
            Ok(serde_json::Value::Number(n)) => Ok(n),
            _ => bail!("invalid number"),
        }
    }

    fn read_json_value(&mut self, max_depth: i32) -> Result<serde_json::Value> {
        if max_depth <= 0 {
            bail_err!(ProtocolError::SkipDepthExceeded)
        }

        self.strip_whitespace();
        match self.guess_kind()? {
            ValueKind::Null => {
                self.read_null()?;
                Ok(serde_json::Value::Null)
            }
            ValueKind::Bool => {
                let value = self.read_bool()?;
                Ok(serde_json::Value::Bool(value))
            }
            ValueKind::Number => {
                let value = self.read_json_number()?;
                Ok(serde_json::Value::Number(value))
            }
            ValueKind::String => {
                let value = self.read_string()?;
                Ok(serde_json::Value::String(value))
            }
            ValueKind::Array => {
                let mut vec = Vec::new();
                self.read_list_begin()?;
                while self.read_list_value_begin()? {
                    let element = self.read_json_value(max_depth - 1)?;
                    vec.push(element);
                    self.read_list_value_end()?;
                }
                self.read_list_end()?;
                Ok(serde_json::Value::Array(vec))
            }
            ValueKind::Object => {
                let mut map = serde_json::Map::new();
                self.read_struct_begin(|_| ())?;
                while let Some(b'"') = self.peek() {
                    let key = self.read_string()?;
                    self.eat(b":")?;
                    let value = self.read_json_value(max_depth - 1)?;
                    map.insert(key, value);
                    self.read_field_end()?;
                }
                self.read_struct_end()?;
                Ok(serde_json::Value::Object(map))
            }
        }
    }

    fn skip_inner(&mut self, field_type: TType, max_depth: i32) -> Result<()> {
        if max_depth <= 0 {
            bail_err!(ProtocolError::SkipDepthExceeded)
        }

        match field_type {
            TType::Void => {
                self.read_null()?;
            }
            TType::Bool => {
                self.read_bool()?;
            }
            TType::Byte => {
                self.read_byte()?;
            }
            TType::I16 => {
                self.read_i16()?;
            }
            TType::I32 => {
                self.read_i32()?;
            }
            TType::I64 => {
                self.read_i64()?;
            }
            TType::Double => {
                self.read_double()?;
            }
            TType::Float => {
                self.read_float()?;
            }
            TType::Map => bail_err!(ProtocolError::InvalidTypeInSkip(field_type)),
            TType::Set => bail_err!(ProtocolError::InvalidTypeInSkip(field_type)),
            TType::Struct => {
                self.read_struct_begin(|_| ())?;
                loop {
                    let fields = &[];
                    let (_, type_id, _) = self.read_field_begin(|_| (), fields)?;
                    if type_id == TType::Stop {
                        break;
                    }
                    self.skip_inner(type_id, max_depth - 1)?;
                    self.read_field_end()?;
                }
                self.read_struct_end()?;
            }
            TType::List => {
                let (_, len) = self.read_list_begin()?;
                let mut idx = 0;
                loop {
                    let more = self.read_list_value_begin()?;
                    if should_break(len, more, idx + 1) {
                        break;
                    }

                    let elem_type = self.guess_type()?;
                    self.skip_inner(elem_type, max_depth - 1)?;
                    self.read_list_value_end()?;

                    idx += 1;
                }
                self.read_list_end()?;
            }
            TType::UTF8 => {
                self.read_string()?;
            }
            TType::UTF16 => {
                self.read_string()?;
            }
            TType::String => {
                self.read_binary::<Vec<u8>>()?;
            }
            TType::Stream => bail_err!(ProtocolError::StreamUnsupported),
            TType::Stop => bail_err!(ProtocolError::UnexpectedStopInSkip),
        };
        Ok(())
    }

    // Fallback to guessing what "type" of structure we are parsing and mark
    // the field_id as something impossible so we skip everything underneath this string
    fn guess_type(&mut self) -> Result<TType> {
        match self.guess_kind()? {
            ValueKind::Object => Ok(TType::Struct),
            ValueKind::Array => Ok(TType::List),
            ValueKind::String => Ok(TType::UTF8),
            ValueKind::Null => Ok(TType::Void),
            ValueKind::Bool => Ok(TType::Bool),
            ValueKind::Number => Ok(TType::Double),
        }
    }

    fn guess_kind(&mut self) -> Result<ValueKind> {
        match self.peek() {
            Some(b'{') => Ok(ValueKind::Object),
            Some(b'[') => Ok(ValueKind::Array),
            Some(b'"') => Ok(ValueKind::String),
            Some(b'n') => Ok(ValueKind::Null),
            Some(b't') | Some(b'f') => Ok(ValueKind::Bool),
            Some(b'-') => Ok(ValueKind::Number),
            Some(b) if (b as char).is_ascii_digit() => Ok(ValueKind::Number),
            ch => bail!(
                "Expected [, {{, or \", or number after {:?}",
                ch.map(|a| a as char)
            ),
        }
    }

    fn read_null(&mut self) -> Result<()> {
        self.eat(b"null")
    }

    fn check_null(&mut self) -> bool {
        self.strip_whitespace();
        match self.peek() {
            Some(b'n') => true,
            _ => false,
        }
    }
}

impl<B: Buf> ProtocolReader for SimpleJsonProtocolDeserializer<B> {
    fn read_message_begin<F, T>(&mut self, _msgfn: F) -> Result<(T, MessageType, u32)>
    where
        F: FnOnce(&[u8]) -> T,
    {
        bail!("Not implemented")
    }

    fn read_message_end(&mut self) -> Result<()> {
        bail!("Not implemented")
    }

    fn read_struct_begin<F, T>(&mut self, namefn: F) -> Result<T>
    where
        F: FnOnce(&[u8]) -> T,
    {
        self.eat(b"{")?;
        Ok(namefn(&[]))
    }

    fn read_struct_end(&mut self) -> Result<()> {
        self.eat(b"}")?;
        Ok(())
    }

    fn read_field_begin<F, T>(&mut self, fieldfn: F, fields: &[Field]) -> Result<(T, TType, i16)>
    where
        F: FnOnce(&[u8]) -> T,
    {
        // Check if its time to give up
        self.strip_whitespace();
        match self.peek() {
            Some(b'"') => {}
            _ => return Ok((fieldfn(&[]), TType::Stop, -1)),
        }

        // Something went wrong if we dont find a string
        let field_name = self.read_string()?;
        self.eat(b":")?;

        // Did we find a field we know about?
        if let Ok(idx) = fields.binary_search_by_key(&field_name.as_str(), |f| f.name) {
            let field = &fields[idx];
            if !self.check_null() {
                return Ok((fieldfn(field.name.as_bytes()), field.ttype, field.id));
            }
        }

        let elem_type = self.guess_type()?;

        // -1 means we fallthrough to start skipping
        Ok((fieldfn(field_name.as_bytes()), elem_type, -1))
    }

    fn read_field_end(&mut self) -> Result<()> {
        match self.possibly_read_comma(b'}') {
            CommaState::Trailing => bail!("Found trailing comma"),
            CommaState::NoComma => bail!("Missing comma between fields"),
            _ => {}
        }
        Ok(())
    }

    fn read_map_begin(&mut self) -> Result<(TType, TType, Option<usize>)> {
        self.eat(b"{")?;
        // Meaningless type, self.skip_inner and deserialize do not depend on it
        Ok((TType::Stop, TType::Stop, None))
    }

    fn read_map_key_begin(&mut self) -> Result<bool> {
        self.strip_whitespace();
        match self.peek() {
            Some(b'}') => {
                // We are finished with this map
                return Ok(false);
            }
            _ => {}
        }
        Ok(true)
    }

    fn read_map_value_begin(&mut self) -> Result<()> {
        self.eat(b":")?;
        Ok(())
    }

    #[inline]
    fn read_map_value_end(&mut self) -> Result<()> {
        match self.possibly_read_comma(b'}') {
            CommaState::Trailing => bail!("Found trailing comma"),
            CommaState::NoComma => bail!("Missing comma between fields"),
            _ => {}
        }
        Ok(())
    }

    fn read_map_end(&mut self) -> Result<()> {
        self.eat(b"}")?;
        Ok(())
    }

    fn read_list_begin(&mut self) -> Result<(TType, Option<usize>)> {
        self.eat(b"[")?;
        Ok((TType::Stop, None))
    }

    fn read_list_value_begin(&mut self) -> Result<bool> {
        match self.peek() {
            Some(b']') => return Ok(false),
            _ => {}
        }
        Ok(true)
    }

    #[inline]
    fn read_list_value_end(&mut self) -> Result<()> {
        match self.possibly_read_comma(b']') {
            CommaState::Trailing => bail!("Found trailing comma"),
            CommaState::NoComma => bail!("Missing comma between fields"),
            _ => {}
        }
        Ok(())
    }

    fn read_list_end(&mut self) -> Result<()> {
        self.eat(b"]")?;
        Ok(())
    }

    fn read_set_begin(&mut self) -> Result<(TType, Option<usize>)> {
        self.read_list_begin()
    }

    fn read_set_value_begin(&mut self) -> Result<bool> {
        self.read_list_value_begin()
    }

    #[inline]
    fn read_set_value_end(&mut self) -> Result<()> {
        self.read_list_value_end()
    }

    fn read_set_end(&mut self) -> Result<()> {
        self.read_list_end()
    }

    fn read_bool(&mut self) -> Result<bool> {
        match self.eat(b"true") {
            Ok(_) => Ok(true),
            Err(_) => match self.eat(b"false") {
                Ok(_) => Ok(false),
                Err(_) => bail!("Expected `true` or `false`"),
            },
        }
    }

    fn read_byte(&mut self) -> Result<i8> {
        Ok(self.read_i64()? as i8)
    }

    fn read_i16(&mut self) -> Result<i16> {
        Ok(self.read_i64()? as i16)
    }

    fn read_i32(&mut self) -> Result<i32> {
        Ok(self.read_i64()? as i32)
    }

    fn read_i64(&mut self) -> Result<i64> {
        self.read_json_number()?
            .as_i64()
            .ok_or_else(|| anyhow!("Invalid number"))
    }

    fn read_double(&mut self) -> Result<f64> {
        self.read_json_number()?
            .as_f64()
            .ok_or_else(|| anyhow!("Invalid number"))
    }

    fn read_float(&mut self) -> Result<f32> {
        Ok(self.read_double()? as f32)
    }

    fn read_string(&mut self) -> Result<String> {
        self.strip_whitespace();
        self.eat_only(b"\"")?;
        let mut ret = Vec::new();
        ret.push(b'"');
        loop {
            match self.peek() {
                Some(b'"') => {
                    self.advance(1);
                    break;
                }
                Some(b'\\') => {
                    self.advance(1);
                    ret.push(b'\\');
                    match self.peek() {
                        Some(b'"') => {
                            self.advance(1);
                            ret.push(b'"')
                        }
                        Some(b'\\') => {
                            self.advance(1);
                            ret.push(b'\\')
                        }
                        _ => {}
                    }
                }
                Some(b) => {
                    self.advance(1);
                    ret.push(b);
                }
                None => bail!("Expected some char"),
            }
        }
        ret.push(b'"');

        let v: std::result::Result<serde_json::Value, _> = serde_json::from_slice(&ret);
        match v {
            Ok(serde_json::Value::String(s)) => Ok(s),
            _ => bail!("invalid string  "),
        }
    }

    fn read_binary<V: CopyFromBuf>(&mut self) -> Result<V> {
        self.eat(b"\"")?;
        let mut ret = Vec::new();
        loop {
            match self.peek() {
                Some(b'"') => {
                    self.advance(1);
                    break;
                }
                Some(b) => {
                    self.advance(1);
                    ret.push(b);
                }
                None => bail!("Expected some char"),
            }
        }
        let bin = base64::decode_config(&ret, base64::STANDARD_NO_PAD)
            .context("the `binary` data in JSON string does not contain valid base64")?;
        Ok(V::from_vec(bin))
    }

    /// Override the default skip impl to handle random JSON noise
    fn skip(&mut self, field_type: TType) -> Result<()> {
        self.skip_inner(field_type, DEFAULT_RECURSION_DEPTH)
    }
}

pub trait SerializeRef:
    Serialize<SimpleJsonProtocolSerializer<SizeCounter>>
    + Serialize<SimpleJsonProtocolSerializer<BytesMut>>
where
    for<'a> &'a Self: Serialize<SimpleJsonProtocolSerializer<SizeCounter>>,
    for<'a> &'a Self: Serialize<SimpleJsonProtocolSerializer<BytesMut>>,
{
}

impl<T> SerializeRef for T
where
    T: Serialize<SimpleJsonProtocolSerializer<BytesMut>>,
    T: Serialize<SimpleJsonProtocolSerializer<SizeCounter>>,
    for<'a> &'a T: Serialize<SimpleJsonProtocolSerializer<BytesMut>>,
    for<'a> &'a T: Serialize<SimpleJsonProtocolSerializer<SizeCounter>>,
{
}

pub trait Serializable:
    Serialize<SimpleJsonProtocolSerializer<SizeCounter>>
    + Serialize<SimpleJsonProtocolSerializer<BytesMut>>
{
}

impl<T> Serializable for T where
    T: Serialize<SimpleJsonProtocolSerializer<SizeCounter>>
        + Serialize<SimpleJsonProtocolSerializer<BytesMut>>
{
}

/// Serialize a Thrift value using the simple JSON protocol.
pub fn serialize<T>(v: T) -> Bytes
where
    T: Serializable,
{
    let mut sizer = SimpleJsonProtocolSerializer {
        buffer: SizeCounter::new().writer(),
        state: vec![SerializationState::NotInContainer],
    };
    v.write(&mut sizer);

    let sz = sizer.finish();

    // Now that we have the size, allocate an output buffer and serialize into it
    let mut buf = SimpleJsonProtocolSerializer {
        buffer: BytesMut::with_capacity(sz).writer(),
        state: vec![SerializationState::NotInContainer],
    };
    v.write(&mut buf);

    // Done
    buf.finish()
}

pub trait DeserializeSlice:
    for<'a> Deserialize<SimpleJsonProtocolDeserializer<Cursor<&'a [u8]>>>
{
}

impl<T> DeserializeSlice for T where
    T: for<'a> Deserialize<SimpleJsonProtocolDeserializer<Cursor<&'a [u8]>>>
{
}

/// Deserialize a Thrift blob using the compact protocol.
pub fn deserialize<T, B, C>(b: B) -> Result<T>
where
    B: Into<DeserializeSource<C>>,
    C: BufExt,
    T: Deserialize<SimpleJsonProtocolDeserializer<C>>,
{
    let source: DeserializeSource<C> = b.into();
    let mut deser = SimpleJsonProtocolDeserializer::new(source.0);
    let t = T::read(&mut deser)?;
    if deser.peek().is_some() {
        bail!(ProtocolError::TrailingData);
    }
    Ok(t)
}

// Aligns with the variant names of serde_json::Value.
enum ValueKind {
    Null,
    Bool,
    Number,
    String,
    Array,
    Object,
}

impl<B: Buf> Deserialize<SimpleJsonProtocolDeserializer<B>> for serde_json::Value {
    fn read(p: &mut SimpleJsonProtocolDeserializer<B>) -> Result<Self> {
        p.read_json_value(DEFAULT_RECURSION_DEPTH)
    }
}


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

use num_derive::FromPrimitive;
use num_traits::FromPrimitive;

use crate::errors::ProtocolError;
use crate::Result;

/// Protocol kind. int16
#[repr(i16)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, FromPrimitive)]
pub enum ProtocolID {
    BinaryProtocol = 0,
    JSONProtocol = 1,
    CompactProtocol = 2,
    DebugProtocol = 3,
    VirtualProtocol = 4,
    SimpleJSONProtocol = 5,
}

impl TryFrom<i16> for ProtocolID {
    type Error = anyhow::Error;

    fn try_from(val: i16) -> Result<Self> {
        match ProtocolID::from_i16(val) {
            Some(id) => Ok(id),
            None => bail_err!(ProtocolError::InvalidProtocolID(val)),
        }
    }
}

impl From<ProtocolID> for &'static str {
    fn from(t: ProtocolID) -> &'static str {
        match t {
            ProtocolID::BinaryProtocol => "binary",
            ProtocolID::JSONProtocol => "json",
            ProtocolID::CompactProtocol => "compact",
            ProtocolID::DebugProtocol => "debug",
            ProtocolID::VirtualProtocol => "virtual",
            ProtocolID::SimpleJSONProtocol => "simplejson",
        }
    }
}

/// Message type constants in the Thrift protocol, treated as i32 in golang
#[derive(Debug, Copy, Clone, Eq, PartialEq, FromPrimitive)]
#[repr(u32)]
pub enum MessageType {
    InvalidMessageType = 0,
    Call = 1,
    Reply = 2,
    Exception = 3,
    Oneway = 4, // Unused
}

impl TryFrom<u32> for MessageType {
    type Error = anyhow::Error;

    fn try_from(val: u32) -> Result<Self> {
        match MessageType::from_u32(val) {
            Some(t) => Ok(t),
            None => bail_err!(ProtocolError::InvalidMessageType(val)),
        }
    }
}


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

use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::collections::HashMap;
use std::collections::HashSet;
use std::hash::Hash;
use std::sync::Arc;

use bytes::Bytes;
use ordered_float::OrderedFloat;

use crate::errors::ProtocolError;
use crate::Result;

/// Will be able to add missing types once #![feature(associated_consts)] lands
#[derive(PartialEq, Copy, Clone, Debug)]
#[repr(u8)]
pub enum TType {
    Stop = 0,
    Void = 1,
    Bool = 2,
    Byte = 3,
    // I08    = 3,
    Double = 4,
    I16 = 6,
    I32 = 8,
    I64 = 10,
    String = 11,
    // UTF7   = 11,
    Struct = 12,
    Map = 13,
    Set = 14,
    List = 15,
    UTF8 = 16,
    UTF16 = 17,
    Stream = 18,
    Float = 19,
}

impl TryFrom<i8> for TType {
    type Error = anyhow::Error;

    #[inline]
    fn try_from(val: i8) -> Result<Self> {
        let ret = match val {
            0 => TType::Stop,
            1 => TType::Void,
            2 => TType::Bool,
            3 => TType::Byte,
            4 => TType::Double,
            6 => TType::I16,
            8 => TType::I32,
            10 => TType::I64,
            11 => TType::String,
            12 => TType::Struct,
            13 => TType::Map,
            14 => TType::Set,
            15 => TType::List,
            16 => TType::UTF8,
            17 => TType::UTF16,
            18 => TType::Stream,
            19 => TType::Float,
            _ => bail_err!(ProtocolError::InvalidTypeTag),
        };
        Ok(ret)
    }
}

impl From<TType> for String {
    fn from(t: TType) -> String {
        let tmp: &str = t.into();
        tmp.to_owned()
    }
}

impl From<TType> for &'static str {
    fn from(t: TType) -> &'static str {
        match t {
            TType::Stop => "STOP",
            TType::Void => "VOID",
            TType::Bool => "BOOL",
            TType::Byte => "BYTE",
            // TType::I08 => "I08",
            TType::Double => "DOUBLE",
            TType::I16 => "I16",
            TType::I32 => "I32",
            TType::I64 => "I64",
            TType::String => "STRING",
            // TType::UTF7 => "UTF7",
            TType::Struct => "STRUCT",
            TType::Map => "MAP",
            TType::Set => "SET",
            TType::List => "LIST",
            TType::UTF8 => "UTF8",
            TType::UTF16 => "UTF16",
            TType::Stream => "STREAM",
            TType::Float => "FLOAT",
        }
    }
}

// Get the ttype for a given type
pub trait GetTType {
    const TTYPE: TType;
}

impl GetTType for () {
    const TTYPE: TType = TType::Void;
}

impl GetTType for bool {
    const TTYPE: TType = TType::Bool;
}

impl GetTType for i8 {
    const TTYPE: TType = TType::Byte;
}

impl GetTType for i16 {
    const TTYPE: TType = TType::I16;
}

impl GetTType for i32 {
    const TTYPE: TType = TType::I32;
}

impl GetTType for i64 {
    const TTYPE: TType = TType::I64;
}

impl GetTType for f64 {
    const TTYPE: TType = TType::Double;
}

impl GetTType for f32 {
    const TTYPE: TType = TType::Float;
}

impl GetTType for OrderedFloat<f64> {
    const TTYPE: TType = TType::Double;
}

impl GetTType for OrderedFloat<f32> {
    const TTYPE: TType = TType::Float;
}

impl GetTType for String {
    const TTYPE: TType = TType::String;
}

impl GetTType for Bytes {
    const TTYPE: TType = TType::String;
}

// This only narrowly avoids a collision with Vec<T>, because
// it requires T: GetTType, but u8 does not impl it (only i8).
impl GetTType for Vec<u8> {
    const TTYPE: TType = TType::String;
}

impl<T> GetTType for BTreeSet<T>
where
    T: GetTType + Ord,
{
    const TTYPE: TType = TType::Set;
}

impl<T, S> GetTType for HashSet<T, S>
where
    T: GetTType + Hash + Eq,
    S: std::hash::BuildHasher,
{
    const TTYPE: TType = TType::Set;
}

impl<K, V> GetTType for BTreeMap<K, V>
where
    K: GetTType + Ord,
    V: GetTType,
{
    const TTYPE: TType = TType::Map;
}

impl<K, V, S> GetTType for HashMap<K, V, S>
where
    K: GetTType + Hash + Eq,
    V: GetTType,
    S: std::hash::BuildHasher,
{
    const TTYPE: TType = TType::Map;
}

impl<T> GetTType for Vec<T>
where
    T: GetTType,
{
    const TTYPE: TType = TType::List;
}

impl<T> GetTType for Box<T>
where
    T: GetTType,
{
    const TTYPE: TType = <T as GetTType>::TTYPE;
}

impl<T> GetTType for Arc<T>
where
    T: GetTType,
{
    const TTYPE: TType = <T as GetTType>::TTYPE;
}


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

/// URI is a unique name for a Thrift type, used for storing/loading Thrift
/// types to/from an Any struct.
pub trait GetUri {
    fn uri() -> &'static str;
}


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

use bytes::Buf;
use bytes::BufMut;

use crate::errors::ProtocolError;
use crate::Result;

pub const MAX_VARINT_U64: usize = 64 / 7 + 1; // max number of bytes for a u64 varint

pub fn write_u64<B: BufMut>(buf: &mut B, v: u64) {
    let mut v = v;
    let acc = &mut [0_u8; MAX_VARINT_U64][..];
    let mut idx = 0;

    #[cfg(debug_assertions)]
    fn get_mut(acc: &mut [u8], idx: usize) -> &mut u8 {
        &mut acc[idx]
    }
    #[cfg(not(debug_assertions))]
    #[inline]
    fn get_mut(acc: &mut [u8], idx: usize) -> &mut u8 {
        unsafe { acc.get_unchecked_mut(idx) }
    }

    while v > 0x7f {
        *get_mut(acc, idx) = 0x80 | ((v as u8) & 0x7f);
        idx += 1;
        v >>= 7;
    }
    *get_mut(acc, idx) = (v as u8) & 0x7f;
    idx += 1;

    buf.put_slice(&acc[..idx]);
}

#[derive(Debug)]
enum Complete {
    Done { used: usize, val: u64 },
    More { used: usize, idx: usize, val: u64 },
}

use self::Complete::*;

pub fn read_u64<B: Buf>(buf: &mut B) -> Result<u64> {
    let mut buf = buf;

    // Operate on byte slices
    fn inner<B: Buf>(off: usize, val: u64, buf: &mut B) -> Result<Complete> {
        let inp = buf.chunk();
        let mut val = val;

        ensure_err!(!inp.is_empty(), ProtocolError::EOF);

        for (idx, v) in inp.iter().enumerate() {
            let shl = idx + off;

            // Make sure its not too long to fit into u64
            ensure_err!(idx < MAX_VARINT_U64, ProtocolError::InvalidValue);

            val += ((v & 0x7f) as u64) << (shl * 7);

            if v & 0x80 == 0 {
                return Ok(Done { used: idx + 1, val });
            }
        }

        // Need more input - entire input has been used
        let used = inp.len();
        Ok(More {
            used,
            idx: off + used,
            val,
        })
    }

    let mut ret = 0; // cumulative result
    let mut off = 0; // number of 7 bit digits in
    loop {
        match inner(off, ret, &mut buf)? {
            Done { used, val } => {
                ret = val;
                buf.advance(used);
                break Ok(ret);
            }
            More { used, idx, val } => {
                ret = val;
                off = idx;
                buf.advance(used);
            }
        }
    }
}

#[inline]
pub fn u64_len(v: u64) -> usize {
    // number of 7 bit units + 1
    if v == 0 {
        1
    } else {
        let max_one = 63 - v.leading_zeros();
        (max_one / 7) as usize + 1
    }
}

#[inline]
pub fn zigzag(v: i64) -> u64 {
    let z = (v << 1) ^ (v >> 63);
    z as u64
}

#[inline]
pub fn unzigzag(v: u64) -> i64 {
    (v >> 1) as i64 ^ -(v as i64 & 1)
}

#[cfg(test)]
mod test {
    use std::i16;
    use std::i32;
    use std::i64;
    use std::i8;
    use std::io::Cursor;
    use std::u64;

    use bufsize::SizeCounter;
    use bytes::BytesMut;
    use quickcheck::quickcheck;

    use super::*;
    use crate::bufext::BufMutExt;

    fn baseline_varint_u64<T: BufMut>(buf: &mut T, v: u64) {
        let mut v = v;

        while v > 0x7f {
            buf.put_u8(0x80 | (v as u8 & 0x7f));
            v >>= 7;
        }
        buf.put_u8(v as u8 & 0x7f);
    }

    #[test]
    fn maxsize() {
        assert_eq!(MAX_VARINT_U64, 10);
    }

    quickcheck! {
        fn check_u64_len(v: u64) -> bool {
            let len = u64_len(v);

            let mut buf = SizeCounter::new();
            baseline_varint_u64(&mut buf, v);

            let ret = buf.finalize();

            len == ret
        }
    }

    quickcheck! {
        fn check_u64(v: u64) -> bool {
            let len = u64_len(v);
            let mut baseline = BytesMut::with_capacity(len);
            let mut cps = BytesMut::with_capacity(len);

            baseline_varint_u64(&mut baseline, v);
            write_u64(&mut cps, v);

            baseline.finalize() == cps.finalize()
        }
    }

    quickcheck! {
        fn zigzag_roundtrip(v: i64) -> bool {
            let z = zigzag(v);
            let u = unzigzag(z);

            v == u
        }
    }

    quickcheck! {
        fn varint_u64_roundtrip(v: u64) -> bool {
            let mut bytes = BytesMut::with_capacity(MAX_VARINT_U64);
            write_u64(&mut bytes, v);
            let bytes = bytes.finalize();

            assert_eq!(bytes.len(), u64_len(v));

            let u = read_u64(&mut Cursor::new(bytes)).expect("decode failed");
            v == u
        }
    }

    quickcheck! {
        fn varint_u64_roundtrip2(a: u64, b: u64) -> bool {
            let mut bytes = BytesMut::with_capacity(MAX_VARINT_U64 * 2);
            write_u64(&mut bytes, a);
            write_u64(&mut bytes, b);
            let bytes = bytes.finalize();

            assert_eq!(bytes.len(), u64_len(a) + u64_len(b));

            let mut cur = Cursor::new(bytes);
            let x = read_u64(&mut cur).expect("decode failed");
            let y = read_u64(&mut cur).expect("decode failed");
            x == a && y == b
        }
    }

    #[test]
    fn simple_1byte() {
        let data = [77_u8];
        const WANT: u64 = 77;
        let mut cur = Cursor::new(&data[..]);

        match read_u64(&mut cur) {
            Ok(WANT) => {}
            Ok(bad) => panic!("Unexpected result {}", bad),
            Err(bad) => panic!("Bad result {:?}", bad),
        }

        assert_eq!(cur.position(), 1);
    }

    #[test]
    fn simple_2byte() {
        let data = [0x80 | 77, 88_u8];
        const WANT: u64 = (88 << 7) + 77;
        let mut cur = Cursor::new(&data[..]);

        match read_u64(&mut cur) {
            Ok(WANT) => {}
            Ok(bad) => panic!("Unexpected result {} wanted {}", bad, WANT),
            Err(bad) => panic!("Bad result {:?}", bad),
        }

        assert_eq!(cur.position(), 2);
    }

    #[test]
    fn simple_3byte() {
        let data = [0x80 | 77, 0x80 | 88, 99_u8];
        const WANT: u64 = (99 << 14) + (88 << 7) + 77;
        let mut cur = Cursor::new(&data[..]);

        match read_u64(&mut cur) {
            Ok(WANT) => {}
            Ok(bad) => panic!("Unexpected result {} wanted {}", bad, WANT),
            Err(bad) => panic!("Bad result {:?}", bad),
        }

        assert_eq!(cur.position(), 3);
    }

    #[test]
    fn simple_3byte_leftover() {
        let data = [0x80 | 77, 0x80 | 88, 99_u8, 44_u8];
        const WANT: u64 = (99 << 14) + (88 << 7) + 77;
        let mut cur = Cursor::new(&data[..]);

        match read_u64(&mut cur) {
            Ok(WANT) => {}
            Ok(bad) => panic!("Unexpected result {} wanted {}", bad, WANT),
            Err(bad) => panic!("Bad result {:?}", bad),
        }

        assert_eq!(cur.position(), 3);
    }

    #[test]
    fn simple_max() {
        let data = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01];
        const WANT: u64 = u64::MAX;
        let mut cur = Cursor::new(&data[..]);

        match read_u64(&mut cur) {
            Ok(WANT) => {}
            Ok(bad) => panic!("Unexpected result {} wanted {}", bad, WANT),
            Err(bad) => panic!("Bad result {:?}", bad),
        }

        assert_eq!(cur.position(), 10);
    }

    #[test]
    fn simple_zero() {
        let data = [0x00];
        const WANT: u64 = 0;
        let mut cur = Cursor::new(&data[..]);

        match read_u64(&mut cur) {
            Ok(WANT) => {}
            Ok(bad) => panic!("Unexpected result {} wanted {}", bad, WANT),
            Err(bad) => panic!("Bad result {:?}", bad),
        }

        assert_eq!(cur.position(), 1);
    }

    #[test]
    fn multi_small() {
        let data = [0x80 | 77, 88_u8, 0x80 | 77, 0x80 | 88, 99_u8];
        const WANT1: u64 = (88 << 7) + 77;
        const WANT2: u64 = (99 << 14) + (88 << 7) + 77;
        let mut cur = Cursor::new(&data[..]);

        match read_u64(&mut cur) {
            Ok(WANT1) => {}
            Ok(bad) => panic!("Unexpected result {} wanted {}", bad, WANT1),
            Err(bad) => panic!("Bad result {:?}", bad),
        }
        assert_eq!(cur.position(), 2);

        match read_u64(&mut cur) {
            Ok(WANT2) => {}
            Ok(bad) => panic!("Unexpected result {} wanted {}", bad, WANT2),
            Err(bad) => panic!("Bad result {:?}", bad),
        }

        assert_eq!(cur.position(), 5);
    }

    #[test]
    fn multi_chained() {
        let data1 = [0x80 | 77];
        let data2 = [88_u8, 0x80 | 77];
        let data3 = [0x80 | 88, 99_u8];

        let mut data = Cursor::new(data1)
            .chain(Cursor::new(data2))
            .chain(Cursor::new(data3));

        const WANT1: u64 = (88 << 7) + 77;
        const WANT2: u64 = (99 << 14) + (88 << 7) + 77;

        match read_u64(&mut data) {
            Ok(WANT1) => {}
            Ok(bad) => panic!("Unexpected result {} wanted {}", bad, WANT1),
            Err(bad) => panic!("Bad result {:?}", bad),
        }

        match read_u64(&mut data) {
            Ok(WANT2) => {}
            Ok(bad) => panic!("Unexpected result {} wanted {}", bad, WANT2),
            Err(bad) => panic!("Bad result {:?}", bad),
        }
    }

    #[test]
    fn bad_toolong() {
        let data = [0x80_u8; 11];
        let mut cur = Cursor::new(&data[..]);

        match read_u64(&mut cur) {
            Ok(bad) => panic!("Unexpected result {}", bad),
            Err(err) => match err.downcast_ref::<ProtocolError>() {
                Some(ProtocolError::InvalidValue) => {}
                _ => panic!("Bad result {:?}", err),
            },
        }

        assert_eq!(cur.position(), 0);
    }

    #[test]
    fn bad_tooshort() {
        let data = [0x80_u8];
        let mut cur = Cursor::new(&data[..]);

        match read_u64(&mut cur) {
            Ok(bad) => panic!("Unexpected result {}", bad),
            Err(err) => match err.downcast_ref::<ProtocolError>() {
                Some(_) => {}
                _ => panic!("Bad result {}", err),
            },
        }

        assert_eq!(cur.position(), 1);
    }

    #[test]
    #[ignore] // doesn't fail as expected - returns u64::MAX
    fn bad_toobig() {
        let data = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f];
        let mut cur = Cursor::new(&data[..]);

        match read_u64(&mut cur) {
            Ok(bad) => panic!("Unexpected result {}", bad),
            Err(err) => match err.downcast_ref::<ProtocolError>() {
                Some(ProtocolError::InvalidValue) => {}
                _ => panic!("Bad result {:?}", err),
            },
        }

        assert_eq!(cur.position(), 0);
    }

    static INT64_VALUES: &[i64] = &[
        459i64,
        0,
        1,
        -1,
        i8::MIN as i64,
        i8::MIN as i64 + 1,
        i8::MAX as i64,
        i16::MIN as i64,
        i16::MIN as i64 + 1,
        i16::MAX as i64,
        i32::MIN as i64,
        i32::MIN as i64 + 1,
        i32::MAX as i64,
        i64::MIN,
        i64::MIN + 1,
        i64::MAX,
        -2147483535,
        34359738481,
        -35184372088719,
    ];

    #[test]
    fn roundtrip_zigzag() {
        for v in INT64_VALUES.iter() {
            let u = zigzag(*v);
            assert_eq!(*v, unzigzag(u));
        }
    }

    #[test]
    fn roundtrip_list() {
        let mut buf = BytesMut::with_capacity(MAX_VARINT_U64 * INT64_VALUES.len());

        for v in INT64_VALUES.iter() {
            write_u64(&mut buf, zigzag(*v));
        }

        let bytes = buf.finalize();
        let mut cur = Cursor::new(bytes);

        for v in INT64_VALUES.iter() {
            let u = read_u64(&mut cur).map(unzigzag).expect("read failed");

            assert_eq!(*v, u, "mismatch want {} got {}", v, u);
        }
    }
}


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

use anyhow::Result;
use fbthrift_test_if::errors::test_service::AsTestException;
use fbthrift_test_if::errors::test_service::Method1Error;
use fbthrift_test_if::types::TestException;

#[test]
fn test_as_exception() -> Result<()> {
    let me = Method1Error::ex(TestException::default());
    assert_eq!(Some(&TestException::default()), me.as_test_exception());

    let me = Method1Error::ThriftError(anyhow::anyhow!(""));
    assert_eq!(None, me.as_test_exception());

    Ok(())
}

#[test]
fn test_as_exception_anyhow() -> Result<()> {
    let ae: anyhow::Error = Method1Error::ex(TestException::default()).into();
    assert_eq!(Some(&TestException::default()), ae.as_test_exception());

    let ae: anyhow::Error = Method1Error::ThriftError(anyhow::anyhow!("")).into();
    assert_eq!(None, ae.as_test_exception());

    Ok(())
}


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

use anyhow::Result;
use fbthrift::binary_protocol::deserialize;
use fbthrift::binary_protocol::serialize;
use fbthrift::ttype::TType;
use fbthrift_test_if::Un;
use proptest::prelude::*;

use crate::proptest::gen_main_struct;

#[test]
fn test_unknown_union() -> Result<()> {
    // Build the empty union
    let u = Un::default();

    let s = serialize(&u);
    // only TType::Stop
    assert_eq!(&[TType::Stop as u8], s.as_ref());

    // Assert that deserialize builds the exact some struct
    assert_eq!(u, deserialize(s).unwrap());

    // ...
    // extra weirdness
    // Build an explicit unknown
    let explicit_unknown = Un::UnknownField(100);
    let s2 = serialize(explicit_unknown);
    // only Stop
    assert_eq!(&[TType::Stop as u8], s2.as_ref());

    Ok(())
}

proptest! {
#[test]
fn test_prop_serialize_deserialize(s in gen_main_struct()) {
    let processed = deserialize(serialize(&s)).unwrap();
    prop_assert_eq!(s, processed);
}
}


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

use anyhow::Result;
use fbthrift::compact_protocol::deserialize;
use fbthrift::compact_protocol::serialize;
use fbthrift::ttype::TType;
use fbthrift_test_if::Un;
use proptest::prelude::*;

use crate::proptest::gen_main_struct;

#[test]
fn test_unknown_union() -> Result<()> {
    // Build the empty union
    let u = Un::default();

    let s = serialize(&u);
    // only TType::Stop
    assert_eq!(&[TType::Stop as u8], s.as_ref());

    // Assert that deserialize builds the exact some struct
    assert_eq!(u, deserialize(s).unwrap());

    // ...
    // extra weirdness
    // Build an explicit unknown
    let explicit_unknown = Un::UnknownField(100);
    let s2 = serialize(explicit_unknown);
    // only Stop
    assert_eq!(&[TType::Stop as u8], s2.as_ref());

    Ok(())
}

proptest! {
#[test]
fn test_prop_serialize_deserialize(s in gen_main_struct()) {
    let processed = deserialize(serialize(&s)).unwrap();
    prop_assert_eq!(s, processed);
}
}


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

use std::error::Error;

use anyhow::Result;
use fbthrift_test_if::types::TestException;
use fbthrift_test_if::types::TestExceptionMsgOverride;
use fbthrift_test_if::types::TestExceptionMsgOverrideOptional;

#[test]
fn test_should_implement_error() -> Result<()> {
    let err = TestException {
        message: "invalid grape peeler".into(),
        ..Default::default()
    };
    assert!(matches!(err.source(), None));

    Ok(())
}

#[test]
fn test_should_print_debug_by_default() -> Result<()> {
    let err = TestException {
        message: "invalid grape peeler".into(),
        ..Default::default()
    };
    assert_eq!(format!("{}", err), format!("{:?}", err),);

    Ok(())
}

#[test]
fn test_should_use_message_field_override() -> Result<()> {
    let err = TestExceptionMsgOverride {
        message: "invalid grape peeler".into(),
        ..Default::default()
    };
    assert_eq!(
        format!("TestExceptionMsgOverride: {}", err.message),
        format!("{}", err)
    );

    Ok(())
}

#[test]
fn test_should_use_message_field_override_optional() -> Result<()> {
    let err = TestExceptionMsgOverrideOptional {
        message: Some("invalid grape peeler".into()),
        ..Default::default()
    };
    assert_eq!(
        format!(
            "TestExceptionMsgOverrideOptional: Some(\"{}\")",
            err.message.as_ref().unwrap(),
        ),
        format!("{}", err)
    );

    let err = TestExceptionMsgOverrideOptional {
        message: None,
        ..Default::default()
    };
    assert_eq!(
        format!("TestExceptionMsgOverrideOptional: None"),
        format!("{}", err)
    );

    Ok(())
}


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

#![deny(warnings)]
mod as_exception;
mod binary;
mod compact;
mod exceptions;
mod proptest;
mod simplejson;


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

use std::collections::BTreeMap;

use fbthrift_test_if::En;
use fbthrift_test_if::MainStruct;
use fbthrift_test_if::Small;
use fbthrift_test_if::SubStruct;
use fbthrift_test_if::Un;
use fbthrift_test_if::UnOne;
use fbthrift_test_if::UnTwo;
use proptest::prelude::*;

prop_compose! {
    pub(crate) fn gen_map()(
        m in prop::collection::btree_map(".*", 1..1000i32, 1..10)
    ) -> BTreeMap<String, i32> { m }
}

prop_compose! {
    pub(crate) fn gen_small()(
        num in 1..1000i32, two in 1..1000i64
    ) -> Small { Small {num, two, ..Default::default()} }
}

prop_compose! {
    pub(crate) fn gen_small_vec()(
        m in prop::collection::vec(gen_small(), 1..100)
    ) -> Vec<Small> { m }
}

prop_compose! {
    pub(crate) fn gen_substruct()(
        opt_def in prop::option::of(".*"),
        req_def in ".*",
        key_map in prop::option::of(prop::collection::btree_map(gen_small(), 1..1000i32, 1..10)),
        bin in prop::collection::vec(0..255u8, 1..200)
    ) -> SubStruct {SubStruct { optDef: opt_def, req_def, key_map, bin, ..Default::default()}}
}

pub(crate) fn gen_union() -> impl Strategy<Value = Un> {
    prop_oneof![
        any::<i32>().prop_map(|one| Un::un1(UnOne {
            one,
            ..Default::default()
        })),
        any::<i32>().prop_map(|two| Un::un2(UnTwo {
            two,
            ..Default::default()
        })),
    ]
}

pub(crate) fn gen_enum() -> impl Strategy<Value = En> {
    prop_oneof![Just(En::ONE), Just(En::TWO),]
}

prop_compose! {
    pub(crate) fn gen_main_struct()(
        foo in ".*",
        m in gen_map(),
        bar in ".*",
        l in gen_small_vec(),
        s in gen_substruct(),
        int_keys in prop::collection::btree_map(1..1000i32, 1..1000i32, 1..10),
        opt in prop::option::of(".*"),
        u in gen_union(),
        e in gen_enum()
    ) -> MainStruct {
        MainStruct {
            foo,
            m,
            bar,
            l,
            s,
            int_keys,
            opt,
            u,
            e,
            ..Default::default()
        }
    }
}


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

use std::collections::BTreeMap;
use std::io::Cursor;

use anyhow::Result;
use fbthrift::simplejson_protocol::deserialize;
use fbthrift::simplejson_protocol::serialize;
use fbthrift::simplejson_protocol::SimpleJsonProtocolDeserializer;
use fbthrift::Deserialize;
use fbthrift_test_if::Basic;
use fbthrift_test_if::Containers;
use fbthrift_test_if::En;
use fbthrift_test_if::MainStruct;
use fbthrift_test_if::MainStructNoBinary;
use fbthrift_test_if::Small;
use fbthrift_test_if::SubStruct;
use fbthrift_test_if::Un;
use fbthrift_test_if::UnOne;
use proptest::prelude::*;

use crate::proptest::gen_main_struct;

#[test]
fn test_large_roundtrip() -> Result<()> {
    // Build the big struct
    let mut m = BTreeMap::new();
    m.insert("m1".to_string(), 1);
    m.insert("m2".to_string(), 2);

    let sub = SubStruct {
        ..Default::default()
    };

    let u = Un::un1(UnOne {
        one: 1,
        ..Default::default()
    });
    let e = En::TWO;

    let mut int_keys = BTreeMap::new();
    int_keys.insert(42, 43);
    int_keys.insert(44, 45);

    let r = MainStruct {
        foo: "foo".to_string(),
        m,
        bar: "test".to_string(),
        s: sub,
        l: vec![
            Small {
                num: 1,
                two: 2,
                ..Default::default()
            },
            Small {
                num: 2,
                two: 3,
                ..Default::default()
            },
        ],
        u,
        e,
        int_keys,
        opt: None,
        ..Default::default()
    };

    // serialize it and assert that it serializes correctly
    let s = String::from_utf8(serialize(&r).to_vec()).unwrap();

    // Note that default optionals are there
    // but non-default optionals are not there
    // That is an artifact on how the serialize trait works
    let expected_string = r#"{
        "foo":"foo",
        "m":{"m1":1,"m2":2},
        "bar":"test",
        "s":{"optDef":"IAMOPT","req_def":"IAMREQ","bin":""},
        "l":[{"num":1,"two":2},{"num":2,"two":3}],
        "u":{"un1":{"one":1}},
        "e":2,
        "int_keys":{"42":43,"44":45}
    }"#
    .replace([' ', '\n'], "");
    assert_eq!(expected_string, s);

    // It at least needs to be valid json, the serialize then
    // deserialize and compare will come in the next diff
    let v: serde_json::Result<serde_json::Value> = serde_json::from_str(&s);
    assert!(v.is_ok());

    // Assert that deserialize builts the exact same struct
    assert_eq!(r, deserialize(s).unwrap());

    Ok(())
}

#[test]
fn test_struct_key() -> Result<()> {
    // See the `structKey` test in cpp_compat_test

    let mut h = std::collections::BTreeMap::new();
    h.insert(
        Small {
            ..Default::default()
        },
        1,
    );
    let sub = SubStruct {
        key_map: Some(h),
        // In rust we need to specify optionals with defaults as None
        // instead of relying on ..Default::default()
        optDef: None,
        ..Default::default()
    };

    let s = String::from_utf8(serialize(&sub).to_vec()).unwrap();
    let expected_string = r#"{
        "req_def":"IAMREQ",
        "key_map":{{"num":0,"two":0}:1},
        "bin":""
    }"#
    .replace([' ', '\n'], "");
    assert_eq!(expected_string, s);

    // It's definitely not JSON...
    let v: serde_json::Result<serde_json::Value> = serde_json::from_str(&s);
    assert!(v.is_err());

    // ...but it needs to deserialize
    assert_eq!(sub, deserialize(&s).unwrap());

    // ...though not to serde_json::Value.
    if let Ok(wat) = deserialize(&s) {
        let _: serde_json::Value = wat;
        panic!("map with struct keys is not supposed to deserialize to Value");
    }

    Ok(())
}

#[test]
fn test_weird_text() -> Result<()> {
    // See the `weirdText` test in cpp_compat_test

    let mut sub = SubStruct {
        optDef: Some("stuff\twith\nescape\\characters'...\"lots{of}fun</xml>".to_string()),
        bin: "1234".as_bytes().to_vec(),
        ..Default::default()
    };

    let s = String::from_utf8(serialize(&sub).to_vec()).unwrap();
    let expected_string = r#"{
        "optDef":"stuff\twith\nescape\\characters'...\"lots{of}fun</xml>",
        "req_def":"IAMREQ",
        "bin":"MTIzNA"
    }"#
    .replace([' ', '\n'], "");
    assert_eq!(expected_string, s);
    // Make sure its equal
    assert_eq!(sub, deserialize(s).unwrap());

    // Unicode escaping
    sub.optDef = Some("UNICODE\u{1F60A}UH OH".to_string());

    let s = String::from_utf8(serialize(&sub).to_vec()).unwrap();
    let expected_string = r#"{
        "optDef":"UNICODEðŸ˜ŠUH OH",
        "req_def":"IAMREQ",
        "bin":"MTIzNA"
    }"#
    // Double-space to deal with "tabs"
    .replace("  ", "")
    .replace('\n', "");
    assert_eq!(expected_string, s);
    // Make sure its equal
    assert_eq!(sub, deserialize(s).unwrap());

    Ok(())
}

#[test]
fn test_skip_complex() -> Result<()> {
    // See the `skipComplex` test in cpp_compat_test

    let sub = SubStruct {
        optDef: Some("thing".to_string()),
        bin: "1234".as_bytes().to_vec(),
        ..Default::default()
    };

    let input = r#"{
        "optDef":"thing",
        "req_def":"IAMREQ",
        "bin":"MTIzNA",
        "extra":[1,{"thing":"thing2"}],
        "extra_map":{"thing":null,"thing2":2},
        "extra_bool":true
    }"#
    .replace([' ', '\n'], "");
    // Make sure everything is skipped properly
    assert_eq!(sub, deserialize(input).unwrap());

    Ok(())
}

#[test]
fn test_need_commas() -> Result<()> {
    // See the `needCommas` test in cpp_compat_test

    // Note the missing commas

    let input = r#"{
        "num":1
        "two":2
    }"#
    .replace([' ', '\n'], "");
    assert!(deserialize::<Small, _, _>(input).is_err());

    // even when skipping
    let input2 = r#"{
        "num":1,
        "two":2,
        "extra_map":{"thing":null,"thing2":2}
        "extra_bool":true
    }"#
    .replace([' ', '\n'], "");
    assert!(deserialize::<Small, _, _>(input2).is_err());

    Ok(())
}

#[test]
fn test_need_commas_containers() -> Result<()> {
    // See the `needCommasContainers` test in cpp_compat_test

    let goodinput = r#"{
        "m":{"m1":"m1","m2":"m2"}
    }"#;
    // Note the missing comma
    let badinput = r#"{
        "m":{"m1":"m1""m2":"m2"}
    }"#;
    assert!(deserialize::<Containers, _, _>(goodinput).is_ok());
    assert!(deserialize::<Containers, _, _>(badinput).is_err());

    let goodinput2 = r#"{
        "l":["l1","l2"]
    }"#;
    // Note the missing comma
    let badinput2 = r#"{
        "l":["l1""l2"]
    }"#;
    assert!(deserialize::<Containers, _, _>(goodinput2).is_ok());
    assert!(deserialize::<Containers, _, _>(badinput2).is_err());

    Ok(())
}

#[test]
fn test_null_stuff() -> Result<()> {
    // See the `nullStuff` test in cpp_compat_test

    let sub = SubStruct {
        optDef: None,
        bin: "1234".as_bytes().to_vec(),
        ..Default::default()
    };

    let input = r#"{
        "optDef":null,
        "req_def":"IAMREQ",
        "bin":"MTIzNA"
    }"#
    .replace([' ', '\n'], "");
    // Make sure everything is skipped properly
    assert_eq!(sub, deserialize(input).unwrap());

    Ok(())
}

#[test]
fn infinite_spaces() -> Result<()> {
    let mut m = BTreeMap::new();
    m.insert("m1".to_string(), 1);
    m.insert("m2".to_string(), 2);

    let sub = SubStruct {
        ..Default::default()
    };

    let u = Un::un1(UnOne {
        one: 1,
        ..Default::default()
    });
    let e = En::TWO;

    let mut int_keys = BTreeMap::new();
    int_keys.insert(42, 43);
    int_keys.insert(44, 45);

    let r = MainStruct {
        foo: "foo".to_string(),
        m,
        bar: " test ".to_string(),
        s: sub,
        l: vec![
            Small {
                num: 1,
                two: 2,
                ..Default::default()
            },
            Small {
                num: 2,
                ..Default::default()
            },
        ],
        u,
        e,
        int_keys,
        opt: None,
        ..Default::default()
    };

    let input = r#"{
         "foo"  :  "foo" ,
          "m" : { "m1" :  1   , "m2" : 2 }  ,
        "bar":" test ",
        "s":{"optDef":  "IAMOPT"  ,"req_def":  "IAMREQ","bin": ""  },
        "l":[{"num":1,"two":2},{"num"  :2 ," two" : 3 } ],
        "u":{"un1":{"one":  1  } },
        "e":  2  ,
        "int_keys"  :{"42"   :  43,  "44":45}
    }"#;

    // Assert that deserialize builts the exact same struct
    assert_eq!(r, deserialize(input).unwrap());

    Ok(())
}

#[test]
fn test_bool() -> Result<()> {
    let b = Basic {
        b: true,
        b2: false,
        ..Default::default()
    };
    // serialize it and assert that it serializes correctly
    let s = String::from_utf8(serialize(&b).to_vec()).unwrap();

    // Assert that deserialize builts the exact same struct
    assert_eq!(b, deserialize(s).unwrap());

    Ok(())
}

#[test]
fn test_serde_compat() -> Result<()> {
    // Build the big struct
    let mut m = BTreeMap::new();
    m.insert("m1".to_string(), 1);
    m.insert("m2".to_string(), 2);

    let u = Un::un1(UnOne {
        one: 1,
        ..Default::default()
    });
    let e = En::TWO;

    let mut int_keys = BTreeMap::new();
    int_keys.insert(42, 43);
    int_keys.insert(44, 45);

    let r = MainStructNoBinary {
        foo: "foo".to_string(),
        m,
        bar: "test".to_string(),
        l: vec![
            Small {
                num: 1,
                two: 2,
                ..Default::default()
            },
            Small {
                num: 2,
                two: 3,
                ..Default::default()
            },
        ],
        u,
        e,
        int_keys,
        opt: None,
        ..Default::default()
    };

    let fbthrift_s = String::from_utf8(serialize(&r).to_vec()).unwrap();
    // We aren't going to get full compat, but at least make it so fbthrift
    // can deserialize
    // what serde has written out
    let serde_s = serde_json::to_string(&r).unwrap();

    // but passing between them should work
    assert_eq!(r, serde_json::from_str(&fbthrift_s).unwrap());
    assert_eq!(r, deserialize(&serde_s).unwrap());
    Ok(())
}

#[test]
fn test_multiple_deser() -> Result<()> {
    // Tests that we don't too eagerly advance the buffer
    let b1 = Basic {
        b: true,
        b2: false,
        ..Default::default()
    };
    let b2 = Basic {
        b: true,
        b2: true,
        ..Default::default()
    };
    // serialize it and assert that it serializes correctly
    let s1 = String::from_utf8(serialize(&b1).to_vec()).unwrap();
    let s2 = String::from_utf8(serialize(&b2).to_vec()).unwrap();
    let to_check = format!("{} {}", s1, s2);

    let mut deserializer = SimpleJsonProtocolDeserializer::new(Cursor::new(to_check.as_bytes()));
    // Assert that deserialize builts the exact same struct
    assert_eq!(b1, Basic::read(&mut deserializer)?);
    assert_eq!(b2, Basic::read(&mut deserializer)?);

    Ok(())
}

#[test]
fn test_not_enough() -> Result<()> {
    // Tests that we can deserialize until
    // we run out, and don't panic
    let b1 = Basic {
        b: true,
        b2: false,
        ..Default::default()
    };
    let b2 = Basic {
        b: true,
        b2: true,
        ..Default::default()
    };
    // serialize it and assert that it serializes correctly
    let s1 = String::from_utf8(serialize(&b1).to_vec()).unwrap();
    let s2 = String::from_utf8(serialize(b2).to_vec()).unwrap();
    let to_check = format!("{} {}", s1, s2);

    let mut deserializer = SimpleJsonProtocolDeserializer::new(Cursor::new(
        // 6 should cover the } and a `true` value
        &to_check.as_bytes()[..to_check.as_bytes().len() - 6],
    ));
    // Assert that deserialize builts the exact same struct
    assert_eq!(b1, Basic::read(&mut deserializer)?);
    assert!(Basic::read(&mut deserializer).is_err());

    Ok(())
}

#[test]
fn test_unknown_union() -> Result<()> {
    // See unknownUnion

    // Build the empty union
    let u = Un::default();

    let s = String::from_utf8(serialize(&u).to_vec()).unwrap();
    let expected_string = "{}";
    assert_eq!(expected_string, s);

    // Assert that deserialize builts the exact same struct
    assert_eq!(u, deserialize(s).unwrap());

    // ...
    // extra weirdness
    // Build an explicit unknown
    let explicit_unknown = Un::UnknownField(100);
    let s2 = String::from_utf8(serialize(explicit_unknown).to_vec()).unwrap();
    let expected_string = "{}";
    assert_eq!(expected_string, s2);

    // Deserializes to the default -1 case, this matches the other
    // protocols behavior
    assert_eq!(u, deserialize(s2).unwrap());

    // backwards compat test
    let old_output = r#"{
        "UnknownField":-1
    }"#
    .replace([' ', '\n'], "");

    assert_eq!(u, deserialize(old_output).unwrap());

    Ok(())
}

proptest! {
#[test]
fn test_prop_serialize_deserialize(s in gen_main_struct()) {
    let processed = deserialize(serialize(&s)).unwrap();
    prop_assert_eq!(s, processed);
}
}


// @generated by autocargo
use std::env;
use std::fs;
use std::path::Path;

use thrift_compiler::Config;
use thrift_compiler::GenContext;

#[rustfmt::skip]
fn main() {
    // Rerun if this gets rewritten.
    println!("cargo:rerun-if-changed=thrift_build.rs");

    let out_dir = env::var_os("OUT_DIR").expect("OUT_DIR env not provided");
    let out_dir: &Path = out_dir.as_ref();
    fs::write(
        out_dir.join("cratemap"),
        "test_thrift crate",
    ).expect("Failed to write cratemap");

    let conf = {
        let mut conf = Config::from_env(GenContext::Lib).expect("Failed to instantiate thrift_compiler::Config");

        let path_from_manifest_to_base: &Path = "../../../../../..".as_ref();
        let cargo_manifest_dir =
            env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not provided");
        let cargo_manifest_dir: &Path = cargo_manifest_dir.as_ref();
        let base_path = cargo_manifest_dir
            .join(path_from_manifest_to_base)
            .canonicalize()
            .expect("Failed to canonicalize base_path");
        // TODO: replace canonicalize() with std::path::absolute() when
        // https://github.com/rust-lang/rust/pull/91673 is available (~Rust 1.60)
        // and remove this block.
        #[cfg(windows)]
        let base_path = Path::new(
            base_path
                .as_path()
                .to_string_lossy()
                .trim_start_matches(r"\\?\"),
            )
            .to_path_buf();

        conf.base_path(base_path);

        let options = "types_crate=fbthrift_test_if__types,serde";
        if !options.is_empty() {
            conf.options(options);
        }

        let include_srcs = vec![

        ];
        conf.include_srcs(include_srcs);

        conf
    };

    conf
        .run(&[
            "../test_thrift.thrift"
        ])
        .expect("Failed while running thrift compilation");
}


// @generated by autocargo
::codegen_includer_proc_macro::include!();


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

use std::io::Cursor;
use std::u8;

use bytes::Buf;
use bytes::Bytes;

use super::BOOL_VALUES;
use super::BYTE_VALUES;
use super::DOUBLE_VALUES;
use super::FLOAT_VALUES;
use super::INT16_VALUES;
use super::INT32_VALUES;
use super::INT64_VALUES;
use crate::thrift_protocol::MessageType;
use crate::ttype::TType;
use crate::BinaryProtocol;
use crate::Protocol;
use crate::ProtocolReader;
use crate::ProtocolWriter;

#[test]
fn read_write_bool_list() {
    let thetype = TType::Bool;
    let thelen = BOOL_VALUES.len();

    // Write
    let buf = serialize!(BinaryProtocol, |p| {
        p.write_list_begin(thetype, thelen);

        for v in &BOOL_VALUES {
            p.write_bool(*v);
        }

        p.write_list_end();
    });

    // Read
    let mut deserializer = <BinaryProtocol>::deserializer(Cursor::new(buf));
    {
        let (thetype2, thelen2) = deserializer
            .read_list_begin()
            .expect("failed to read header");

        assert_eq!(thetype, thetype2);
        assert_eq!(Some(thelen), thelen2);

        for v in &BOOL_VALUES {
            assert_eq!(*v, deserializer.read_bool().expect("failed to read bool"));
        }
        deserializer
            .read_list_end()
            .expect("failed to read list end");
    }
}

#[test]
fn read_write_string_list() {
    let string_values = vec![
        String::from(""),
        String::from("a"),
        String::from("st[uf]f"),
        String::from("st,u:ff with spaces"),
        String::from("stuff\twith\nescape\\characters'...\"lots{of}fun</xml>"),
    ];
    let thetype = TType::String;
    let thelen = string_values.len();

    let buf = serialize!(BinaryProtocol, |p| {
        p.write_list_begin(thetype, thelen);

        for v in &string_values {
            p.write_string(v);
        }
        p.write_list_end();
    });

    let mut deserializer = <BinaryProtocol>::deserializer(Cursor::new(buf));
    {
        let (thetype2, thelen2) = deserializer
            .read_list_begin()
            .expect("failed to read header");

        assert_eq!(thetype, thetype2);
        assert_eq!(Some(thelen), thelen2);

        for v in &string_values {
            assert_eq!(
                *v,
                deserializer.read_string().expect("failed to read string")
            );
        }
        deserializer
            .read_list_end()
            .expect("failed to read list end");
    }
}

#[test]
fn read_write_byte_list() {
    let thetype = TType::Byte;
    let thelen = BYTE_VALUES.len();

    let buf = serialize!(BinaryProtocol, |p| {
        p.write_list_begin(thetype, thelen);

        for v in &BYTE_VALUES {
            p.write_byte(*v);
        }
        p.write_list_end();
    });

    let mut deserializer = <BinaryProtocol>::deserializer(Cursor::new(buf));
    {
        let (thetype2, thelen2) = deserializer
            .read_list_begin()
            .expect("failed to read header");

        assert_eq!(thetype, thetype2);
        assert_eq!(Some(thelen), thelen2);

        for v in &BYTE_VALUES {
            assert_eq!(*v, deserializer.read_byte().expect("failed to read byte"));
        }
        deserializer
            .read_list_end()
            .expect("failed to read list end");
    }
}

#[test]
fn read_write_i16_list() {
    let thetype = TType::I16;
    let thelen = INT16_VALUES.len();

    let buf = serialize!(BinaryProtocol, |p| {
        p.write_list_begin(thetype, thelen);

        for v in &INT16_VALUES {
            p.write_i16(*v);
        }
        p.write_list_end();
    });

    let mut deserializer = <BinaryProtocol>::deserializer(Cursor::new(buf));
    {
        let (thetype2, thelen2) = deserializer
            .read_list_begin()
            .expect("failed to read header");

        assert_eq!(thetype, thetype2);
        assert_eq!(Some(thelen), thelen2);

        for v in &INT16_VALUES {
            assert_eq!(*v, deserializer.read_i16().expect("failed to read i16"));
        }
        deserializer
            .read_list_end()
            .expect("failed to read list end");
    }
}

#[test]
fn read_write_i32_list() {
    let thetype = TType::I32;
    let thelen = INT32_VALUES.len();

    let buf = serialize!(BinaryProtocol, |p| {
        p.write_list_begin(thetype, thelen);

        for v in &INT32_VALUES {
            p.write_i32(*v);
        }
        p.write_list_end();
    });

    let mut deserializer = <BinaryProtocol>::deserializer(Cursor::new(buf));
    {
        let (thetype2, thelen2) = deserializer
            .read_list_begin()
            .expect("failed to read header");

        assert_eq!(thetype, thetype2);
        assert_eq!(Some(thelen), thelen2);

        for v in &INT32_VALUES {
            assert_eq!(*v, deserializer.read_i32().expect("failed to read i32"));
        }
        deserializer
            .read_list_end()
            .expect("failed to read list end");
    }
}

#[test]
fn read_write_i64_list() {
    let thetype = TType::I64;
    let thelen = INT64_VALUES.len();

    let buf = serialize!(BinaryProtocol, |p| {
        p.write_list_begin(thetype, thelen);

        for v in &INT64_VALUES {
            p.write_i64(*v);
        }
        p.write_list_end();
    });

    let mut deserializer = <BinaryProtocol>::deserializer(Cursor::new(buf));
    {
        let (thetype2, thelen2) = deserializer
            .read_list_begin()
            .expect("failed to read header");

        assert_eq!(thetype, thetype2);
        assert_eq!(Some(thelen), thelen2);

        for v in &INT64_VALUES {
            assert_eq!(*v, deserializer.read_i64().expect("failed to read i64"));
        }
        deserializer
            .read_list_end()
            .expect("failed to read list end");
    }
}

#[test]
fn read_write_f32_list() {
    let thetype = TType::Float;
    let thelen = FLOAT_VALUES.len();

    let buf = serialize!(BinaryProtocol, |p| {
        p.write_list_begin(thetype, thelen);

        for v in &FLOAT_VALUES {
            p.write_float(*v);
        }
        p.write_list_end();
    });

    let mut deserializer = <BinaryProtocol>::deserializer(Cursor::new(buf));
    {
        let (thetype2, thelen2) = deserializer
            .read_list_begin()
            .expect("failed to read header");

        assert_eq!(thetype, thetype2);
        assert_eq!(Some(thelen), thelen2);

        for v in &FLOAT_VALUES {
            let val = deserializer.read_float().expect("failed to read f32");
            // In Rust, NaN != NaN
            if v.is_nan() {
                assert!(val.is_nan());
            } else {
                assert_eq!(*v, val);
            }
        }
        deserializer
            .read_list_end()
            .expect("failed to read list end");
    }
}

#[test]
fn read_write_f64_list() {
    let thetype = TType::Double;
    let thelen = DOUBLE_VALUES.len();

    let buf = serialize!(BinaryProtocol, |p| {
        p.write_list_begin(thetype, thelen);

        for v in &DOUBLE_VALUES {
            p.write_double(*v);
        }
        p.write_list_end();
    });

    let mut deserializer = <BinaryProtocol>::deserializer(Cursor::new(buf));
    {
        let (thetype2, thelen2) = deserializer
            .read_list_begin()
            .expect("failed to read header");

        assert_eq!(thetype, thetype2);
        assert_eq!(Some(thelen), thelen2);

        for v in &DOUBLE_VALUES {
            let val = deserializer.read_double().expect("failed to read f64");
            // In Rust, NaN != NaN :)
            if v.is_nan() {
                assert!(val.is_nan());
            } else {
                assert_eq!(*v, val);
            }
        }
        deserializer
            .read_list_end()
            .expect("failed to read list end");
    }
}

#[test]
fn read_write_f64_set() {
    let thetype = TType::Double;
    let thelen = DOUBLE_VALUES.len();

    let buf = serialize!(BinaryProtocol, |p| {
        p.write_set_begin(thetype, thelen);

        for v in &DOUBLE_VALUES {
            p.write_double(*v);
        }
        p.write_list_end();
    });

    let mut deserializer = <BinaryProtocol>::deserializer(Cursor::new(buf));
    {
        let (thetype2, thelen2) = deserializer
            .read_set_begin()
            .expect("failed to read header");

        assert_eq!(thetype, thetype2);
        assert_eq!(Some(thelen), thelen2);

        for v in &DOUBLE_VALUES {
            let val = deserializer.read_double().expect("failed to read f64");
            // In Rust, NaN != NaN :)
            if v.is_nan() {
                assert!(val.is_nan());
            } else {
                assert_eq!(*v, val);
            }
        }
        assert!(deserializer.read_set_end().is_ok());
    }
}

#[test]
fn read_write_string_i64_map() {
    let key_type = TType::String;
    let value_type = TType::I64;
    let thelen = INT64_VALUES.len();
    let string_keys: Vec<String> = INT64_VALUES.iter().map(|&v| v.to_string()).collect();

    let buf = serialize!(BinaryProtocol, |p| {
        p.write_map_begin(key_type, value_type, thelen);

        for (k, v) in string_keys.iter().zip(INT64_VALUES.iter()) {
            p.write_string(k);
            p.write_i64(*v);
        }
        p.write_map_end();
    });

    let mut deserializer = <BinaryProtocol>::deserializer(Cursor::new(buf));
    {
        let (key_type2, value_type2, thelen2) = deserializer
            .read_map_begin()
            .expect("failed to read header");

        assert_eq!(key_type, key_type2);
        assert_eq!(value_type, value_type2);
        assert_eq!(Some(thelen), thelen2);

        for (k, v) in string_keys.iter().zip(INT64_VALUES.iter()) {
            assert_eq!(
                *k,
                deserializer.read_string().expect("failed to read string")
            );
            assert_eq!(*v, deserializer.read_i64().expect("failed to read i64"));
        }
        assert!(deserializer.read_map_end().is_ok());
    }
}

#[test]
fn read_write_message() {
    let msg_name = String::from("hello_message");
    let msg_type = MessageType::Call;
    let seq_id = 1;

    let buf = serialize!(BinaryProtocol, |p| {
        p.write_message_begin(&msg_name, msg_type, seq_id);
        p.write_message_end();
    });

    let mut deserializer = <BinaryProtocol>::deserializer(Cursor::new(buf));
    {
        let (msg_name2, msg_type2, seq_id2) = deserializer
            .read_message_begin(|msg| String::from_utf8(msg.to_vec()).expect("bad msg"))
            .expect("failed to read message");
        assert_eq!(msg_name, msg_name2);
        assert_eq!(msg_type, msg_type2);
        assert_eq!(seq_id, seq_id2);

        assert!(deserializer.read_message_end().is_ok());
    }
}

#[test]
fn write_message_begin() {
    let buf = serialize!(BinaryProtocol, |serializer| {
        // Write the following information:
        //  1) Version bitwise or'd with MessageType: (0x80001000 | 0x00000001) = [128, 1, 0, 1]
        //  2) String name prefixed by i32 string length: [0, 0, 0, 4, 116, 101, 115, 116]
        //  3) i32 seqid: [0, 0, 0, 1]
        let _ = serializer.write_message_begin(
            "test",
            MessageType::try_from(1).expect("try_from failed"),
            1,
        );
        let _ = serializer.write_message_end();
    });

    let buf = buf;
    let vec = vec![128, 1, 0, 1, 0, 0, 0, 4, 116, 101, 115, 116, 0, 0, 0, 1];

    assert_eq!(vec, buf);
}

#[test]
fn serializer_overflow() {
    let vec: Vec<u8> = (0..u8::MAX).collect();
    let buf = serialize!(BinaryProtocol, |p| for i in 0..u8::MAX {
        let _ = p.write_byte(i as i8);
    });

    let buf = buf;

    assert_eq!(vec, buf);
}

#[test]
fn read_message_begin() {
    // Data in vec:
    //  1) Version bitwise or'd with MessageType: (0x80001000 | 0x00000001) = [128, 1, 0, 1]
    //  2) String name prefixed by i32 string length: [0, 0, 0, 4, 116, 101, 115, 116]
    //  3) i32 seqid: [0, 0, 0, 1]
    let vec = vec![128, 1, 0, 1, 0, 0, 0, 4, 116, 101, 115, 116, 0, 0, 0, 1];
    let mut deserializer = <BinaryProtocol>::deserializer(Cursor::new(Bytes::from(vec)));

    let rmb =
        deserializer.read_message_begin(|msg| String::from_utf8(msg.to_vec()).expect("bad msg"));
    let _ = deserializer.read_message_end();

    match rmb {
        Ok((name, mty, sid)) => {
            assert_eq!(name, "test");
            assert_eq!(mty, MessageType::try_from(1).expect("try_from failed"));
            assert_eq!(sid, 1);
        }
        Err(_) => panic!(),
    }
}

#[test]
fn deserializer_underflow() {
    use super::super::errors::ProtocolError;

    let vec = vec![0u8, 0u8, 0u8, 1u8];
    let mut deserializer = <BinaryProtocol>::deserializer(Cursor::new(Bytes::from(vec)));

    let last_val = deserializer.read_i32();

    match last_val {
        Ok(i) => assert_eq!(i, 1i32, "read incorrect value for last_val"),
        Err(_) => panic!("Error encoutered reading final i32 from vec"),
    };

    match deserializer.read_i32() {
        Ok(v) => panic!("got unexpected value {}", v),
        Err(err) => match err.downcast_ref::<ProtocolError>() {
            Some(ProtocolError::EOF) => {}
            _ => panic!("got unexpected err {:?}", err),
        },
    }
}

#[test]
fn read_binary_from_chained_buffer() {
    use super::super::binary_protocol::BinaryProtocolDeserializer;

    let buf1 = Cursor::new(b"\x00\x00\x00\x05hello\x00\x00\x00\x06 ");
    let buf2 = Cursor::new(b"world");
    let joined = buf1.chain(buf2);

    let mut deserializer = BinaryProtocolDeserializer::new(joined);

    let result: Vec<u8> = deserializer
        .read_binary()
        .expect("read \"hello\" from the buffer");
    assert_eq!(result.as_slice(), b"hello");

    let result: Vec<u8> = deserializer
        .read_binary()
        .expect("read \" world\" from the buffer");
    assert_eq!(result.as_slice(), b" world");
}