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: loader.rs
    path of file: ./repos/CYFS/src/component/cyfs-backup/src/archive
    
    the code of the file until where you have to start completion: use super::ObjectArchiveIndexHelper;
use super::file_meta::ArchiveInnerFileMeta;
use super::verifier::*;
use crate::crypto::*;
use crate::object_pack::*;
use cyfs_backup_lib::*;
use cyfs_base::*;

use std::path::PathBuf;

pub type ObjectArchiveInnerFileData = ObjectPackInnerFileData;

pub struct ObjectArchiveInnerFile {
    pub data: ObjectArchiveInnerFileData,
    pub meta: Option<ArchiveInnerFileMeta>,
}

pub struct ObjectArchiveSerializeLoader {
    root: PathBuf,
    index: ObjectArchiveIndex,

    object_reader: ObjectPackSerializeReader,
    chunk_reader: ObjectPackSerializeReader,
}

impl ObjectArchiveSerializeLoader {
    pub async fn load(
        root: PathBuf,
        index: ObjectArchiveIndex,
        crypto: Option<AesKey>,
    ) -> BuckyResult<Self> {
        if !root.is_dir() {
            let msg = format!("invalid object archive root dir: {}", root.display());
            error!("{}", msg);
            return Err(BuckyError::new(BuckyErrorCode::NotFound, msg));
        }

        let data_dir = match &index.data_folder {
            Some(data) => {
                root.join(data)
            }
            None => root.clone()
        };

        let object_reader = ObjectPackSerializeReader::new(
            index.format,
            data_dir.clone(),
            index.object_files.clone(),
            crypto.clone(),
        );
        let chunk_reader = ObjectPackSerializeReader::new(
            index.format,
            data_dir,
            index.chunk_files.clone(),
            crypto,
        );

        let ret = Self {
            root,
            index,
            object_reader,
            chunk_reader,
        };

        Ok(ret)
    }

    pub fn index(&self) -> &Obje
    
    pub async fn load(root: PathBuf, password: Option<ProtectedPassword>) -> BuckyResult<Self> {
        // First load index into meta
        let index = ObjectArchiveIndexHelper::load(&root).await?;

        // Check if need password and verify the password
        let crypto = match index.crypto {
            CryptoMode::AES => {
                if password.is_none() {
                    let msg = format!("password required! crypto mode={:?}", index.crypto);
                    error!("{}", msg);
                    return Err(BuckyError::new(BuckyErrorCode::InvalidParam, msg));
                }

                if index.en_device_id.is_none() {
                    let msg = format!("password required but en_device_id field is none!");
                    error!("{}", msg);
                    return Err(BuckyError::new(BuckyErrorCode::InvalidData, msg));
                }

                let aes_key = AesKeyHelper::gen(password.as_ref().unwrap(), &index.device_id);
                AesKeyHelper::verify_device_id(
                    &aes_key,
                    &index.device_id,
                    index.en_device_id.as_ref().unwrap(),
                )?;
                Some(aes_key)
            }
            CryptoMode::None => None,
        };

        let random_loader =
            ObjectArchiveRandomLoader::load(root.clone(), index.clone(), crypto.clone()).await?;
        let serialize_loader =
            ObjectArchiveSerializeLoader::load(root.clone(), index, crypto).await?;

        random_loader.verify().await.map_err(|e| {
            let msg = format!(
                "verify object archive but failed! root={}, {}",
                root.display(),
                e
            );
            error!("{}", msg);
            BuckyError::new(e.code(), msg)
        })?;

        let ret = Self {
            root,
            random_loader,
            serialize_loader,
        };

        Ok(ret)
    }