/// Serialization and deserialization of a group element's compressed representation.
pub mod projective {
    use pairing::{CurveAffine, CurveProjective, EncodedPoint};
    use serde::de::Error as DeserializeError;
    use serde::{Deserialize, Deserializer, Serialize, Serializer};

    const ERR_LEN: &str = "wrong length of deserialized group element";
    const ERR_CODE: &str = "deserialized bytes don't encode a group element";

    pub fn serialize<S, C>(c: &C, s: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
        C: CurveProjective,
    {
        c.into_affine().into_compressed().as_ref().serialize(s)
    }

    pub fn deserialize<'de, D, C>(d: D) -> Result<C, D::Error>
    where
        D: Deserializer<'de>,
        C: CurveProjective,
    {
        let bytes = <Vec<u8>>::deserialize(d)?;
        if bytes.len() != <C::Affine as CurveAffine>::Compressed::size() {
            return Err(D::Error::custom(ERR_LEN));
        }
        let mut compressed = <C::Affine as CurveAffine>::Compressed::empty();
        compressed.as_mut().copy_from_slice(&bytes);
        let to_err = |_| D::Error::custom(ERR_CODE);
        Ok(compressed.into_affine().map_err(to_err)?.into_projective())
    }
}

/// Serialization and deserialization of vectors of projective curve elements.
pub mod projective_vec {
    use std::borrow::Borrow;
    use std::marker::PhantomData;

    use pairing::CurveProjective;
    use serde::{Deserialize, Deserializer, Serialize, Serializer};

    use super::projective;

    /// A wrapper type to facilitate serialization and deserialization of group elements.
    struct CurveWrap<C, B>(B, PhantomData<C>);

    impl<C, B> CurveWrap<C, B> {
        fn new(c: B) -> Self {
            CurveWrap(c, PhantomData)
        }
    }

    impl<C: CurveProjective, B: Borrow<C>> Serialize for CurveWrap<C, B> {
        fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
            projective::serialize(self.0.borrow(), s)
        }
    }

    impl<'de, C: CurveProjective> Deserialize<'de> for CurveWrap<C, C> {
        fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
            Ok(CurveWrap::new(projective::deserialize(d)?))
        }
    }

    pub fn serialize<S, C>(vec: &[C], s: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
        C: CurveProjective,
    {
        let wrap_vec: Vec<CurveWrap<C, &C>> = vec.iter().map(CurveWrap::new).collect();
        wrap_vec.serialize(s)
    }

    pub fn deserialize<'de, D, C>(d: D) -> Result<Vec<C>, D::Error>
    where
        D: Deserializer<'de>,
        C: CurveProjective,
    {
        let wrap_vec = <Vec<CurveWrap<C, C>>>::deserialize(d)?;
        Ok(wrap_vec.into_iter().map(|CurveWrap(c, _)| c).collect())
    }
}

/// Serialization and deserialization of vectors of field elements.
pub mod field_vec {
    use std::borrow::Borrow;
    use std::marker::PhantomData;

    use pairing::{PrimeField, PrimeFieldRepr};
    use serde::de::Error as DeserializeError;
    use serde::ser::Error as SerializeError;
    use serde::{Deserialize, Deserializer, Serialize, Serializer};

    /// A wrapper type to facilitate serialization and deserialization of field elements.
    pub struct FieldWrap<F, B>(B, PhantomData<F>);

    impl<F, B> FieldWrap<F, B> {
        pub fn new(f: B) -> Self {
            FieldWrap(f, PhantomData)
        }
    }

    impl<F> FieldWrap<F, F> {
        pub fn into_inner(self) -> F {
            self.0
        }
    }

    impl<F: PrimeField, B: Borrow<F>> Serialize for FieldWrap<F, B> {
        fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
            let mut bytes = Vec::new();
            self.0
                .borrow()
                .into_repr()
                .write_be(&mut bytes)
                .map_err(|_| S::Error::custom("failed to write bytes"))?;
            bytes.serialize(s)
        }
    }

    impl<'de, F: PrimeField> Deserialize<'de> for FieldWrap<F, F> {
        fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
            let bytes: Vec<u8> = Deserialize::deserialize(d)?;
            let mut repr = F::zero().into_repr();
            repr.read_be(&bytes[..])
                .map_err(|_| D::Error::custom("failed to write bytes"))?;
            Ok(FieldWrap::new(F::from_repr(repr).map_err(|_| {
                D::Error::custom("invalid field element representation")
            })?))
        }
    }

    pub fn serialize<S, F>(vec: &[F], s: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
        F: PrimeField,
    {
        let wrap_vec: Vec<FieldWrap<F, &F>> = vec.iter().map(FieldWrap::new).collect();
        wrap_vec.serialize(s)
    }

    pub fn deserialize<'de, D, F>(d: D) -> Result<Vec<F>, D::Error>
    where
        D: Deserializer<'de>,
        F: PrimeField,
    {
        let wrap_vec = <Vec<FieldWrap<F, F>>>::deserialize(d)?;
        Ok(wrap_vec.into_iter().map(|FieldWrap(f, _)| f).collect())
    }
}

#[cfg(test)]
mod tests {
    use bincode;
    use pairing::bls12_381::Bls12;
    use pairing::Engine;
    use rand::{self, Rng};

    #[derive(Debug, Serialize, Deserialize)]
    pub struct Vecs<E: Engine> {
        #[serde(with = "super::projective_vec")]
        curve_points: Vec<E::G1>,
        #[serde(with = "super::field_vec")]
        field_elements: Vec<E::Fr>,
    }

    impl<E: Engine> PartialEq for Vecs<E> {
        fn eq(&self, other: &Self) -> bool {
            self.curve_points == other.curve_points && self.field_elements == other.field_elements
        }
    }

    #[test]
    fn vecs() {
        let mut rng = rand::thread_rng();
        let vecs: Vecs<Bls12> = Vecs {
            curve_points: rng.gen_iter().take(10).collect(),
            field_elements: rng.gen_iter().take(10).collect(),
        };
        let ser_vecs = bincode::serialize(&vecs).expect("serialize vecs");
        let de_vecs = bincode::deserialize(&ser_vecs).expect("deserialize vecs");
        assert_eq!(vecs, de_vecs);
    }
}