You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: eip712.rs
    path of file: ./repos/ethers-rs/ethers-contract/ethers-contract-derive/src
    
    the code of the file until where you have to start completion: use crate::utils;
use ethers_core::{
    abi::{Address, ParamType},
    macros::ethers_core_crate,
    types::{transaction::eip712::EIP712Domain, H256},
    utils::keccak256,
};
use inflector::Inflector;
use proc_macro2::{Literal, TokenStream};
use quote::quote;
use syn::{spanned::Spanned, Data, DeriveInput, Error, Fields, LitInt, LitStr, Result, Token};

pub(crate) fn impl_derive_eip712(input: &DeriveInput) -> Result<TokenStream> {
    // Primary type should match the type in the ethereum verifying contract;
    let primary_type = &input.ident;

    // Instantiate domain from parsed attributes
    let domain = parse_attributes(input)?;

    let domain_separator = into_tokens(domain.separator());

    let domain_str = serde_json
    
fn parse_fields(input: &DeriveInput) -> Result<Vec<(String, ParamType)>> {
    let data = match &input.data {
        Data::Struct(s) => s,
        Data::Enum(e) => {
            return Err(Error::new(e.enum_token.span, "Eip712 is not derivable for enums"))
        }
        Data::Union(u) => {
            return Err(Error::new(u.union_token.span, "Eip712 is not derivable for unions"))
        }
    };

    let named_fields = match &data.fields {
        Fields::Named(fields) => fields,
        _ => return Err(Error::new(input.span(), "unnamed fields are not supported")),
    };

    let mut fields = Vec::with_capacity(named_fields.named.len());
    for f in named_fields.named.iter() {
        // strip the raw identifier prefix
        let name = f.ident.as_ref().unwrap().to_string();
        let s = name.strip_prefix("r#").unwrap_or(&name);
        let name = s.to_camel_case();

        let ty =
            match f.attrs.iter().find(|a| a.path().segments.iter().any(|s| s.ident == "eip712")) {
                // Found nested Eip712 Struct
                // TODO: Implement custom
                Some(a) => {
                    return Err(Error::new(a.span(), "nested Eip712 struct are not yet supported"))
                }
                // Not a nested eip712 struct, return the field param type;
                None => crate::utils::find_parameter_type(&f.ty)?,
            };

        fields.push((name, ty));
    }

    Ok(fields)
}