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: state.rs
    path of file: ./repos/ockam/implementations/rust/ockam/ockam_app_lib/src/invitations
    
    the code of the file until where you have to start completion: use serde::{Deserialize, Serialize};
use tracing::debug;

use ockam_api::cloud::share::{
    InvitationList, InvitationWithAccess, ReceivedInvitation, SentInvitation,
};

#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct InvitationState {
    #[serde(default)]
    pub(crate) sent: Vec<SentInvitation>,
    #[serde(default)]
    pub(crate) received: ReceivedInvitations,
    #[serde(default)]
    pub(crate) accepted: AcceptedInvitations,
}

pub struct InvitationUpdateStatus {
    pub changed: bool,
    pub new_received_invitation: bool,
}

impl InvitationState {
    pub fn replace_by(&mut self, list: InvitationList) -> InvitationUpdateStatus {
        debug!("Updating invitations state");
        let mut status = InvitationUpdateStatus {
            changed: false,
            new_received_invitation: false,
        };

        let new_sent = list.sent.unwrap_or_default();
        if self.sent != new_sent {
            self.sent = new_sent;
            status.changed = true;
        }
        let new_received = list
            .received
            .unwrap_or_default()
            .into_iter()
            .filter(|i| !i.ignored)
            .filter(|i| !i.is_expired().unwrap_or(true))
            .collect::<Vec<_>>();
        if self.received.invitations != new_received {
            status.new_received_invitation = new_received
                .iter()
                .any(|new| !self.received.invitations.iter().any(|old| old.id == new.id));
            self.received.invitations = new_received;
            status.changed = true;
        }
        let new_accepted = list
            .accepted
            .unwrap_or_default()
            .into_iter()
            .filter(|i| !i.invitation.ignored)
            .collect::<Vec<_>>();
        if self.accepted.invitations != new_accepted {
            self.accepted.invitations = new_accepted;
            status.changed = true;
        }

        status
    }
}

#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct ReceivedInvitations {
    pub(crate) invitations: Vec<ReceivedInvitation>,

    /// Status of accepted invitations, keyed by invitation id.
    pub(crate) status: Vec<(String, ReceivedInvitationStatus)>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub enum ReceivedInvitationStatus {
    Accepting,
    Accepted,
    Ignoring,
    Ignored,
}

#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct AcceptedInvitations {
    #[serde(default)]
    pub(crate) invitations: Vec<InvitationWithAccess>,
}

#[cfg(test)]
mod tests {
    use super::*;
    use ockam_api::cloud::share::{RoleInShare, ShareScope};

    #[test]
    fn test_replace_by() {
        let mut state = InvitationState::default();
        assert!(state.sent.is_empty());
        assert!(state.received.invitations.is_empty());
        assert!(state.accepted.invitations.is_empty());
        let list = InvitationList {
            sent: Some(vec![SentInvitation {
        
    
    fn test_replace_by() {
        let mut state = InvitationState::default();
        assert!(state.sent.is_empty());
        assert!(state.received.invitations.is_empty());
        assert!(state.accepted.invitations.is_empty());
        let list = InvitationList {
            sent: Some(vec![SentInvitation {
                id: "id".to_string(),
                expires_at: "expires_at".to_string(),
                grant_role: RoleInShare::Admin,
                owner_id: 0,
                recipient_email: "no_email@none".try_into().unwrap(),
                remaining_uses: 0,
                scope: ShareScope::Project,
                target_id: "target_id".to_string(),
                recipient_id: 0,
                access_details: None,
            }]),
            received: Some(vec![
                ReceivedInvitation {
                    id: "id1".to_string(),
                    expires_at: "2100-09-12T15:07:14.00".to_string(),
                    grant_role: RoleInShare::Admin,
                    owner_email: "owner@email".try_into().unwrap(),
                    scope: ShareScope::Project,
                    target_id: "target_id".to_string(),
                    ignored: false,
                },
                ReceivedInvitation {
                    id: "id2".to_string(),
                    expires_at: "2100-09-12T15:07:14.00".to_string(),
                    grant_role: RoleInShare::Admin,
                    owner_email: "owner@email".try_into().unwrap(),
                    scope: ShareScope::Project,
                    target_id: "target_id".to_string(),
                    ignored: true,
                },
            ]),
            accepted: Some(vec![
                InvitationWithAccess {
                    invitation: ReceivedInvitation {
                        id: "id1".to_string(),
                        expires_at: "expires_at".to_string(),
                        grant_role: RoleInShare::Admin,
                        owner_email: "owner@email".try_into().unwrap(),
                        scope: ShareScope::Project,
                        target_id: "target_id".to_string(),
                        ignored: false,
                    },
                    service_access_details: None,
                },
                InvitationWithAccess {
                    invitation: ReceivedInvitation {
                        id: "id2".to_string(),
                        expires_at: "expires_at".to_string(),
                        grant_role: RoleInShare::Admin,
                        owner_email: "owner@email".try_into().unwrap(),
                        scope: ShareScope::Project,
                        target_id: "target_id".to_string(),
                        ignored: true,
                    },
                    service_access_details: None,
                },
            ]),
        };
        assert!(state.replace_by(list.clone()).changed);
        assert!(!state.replace_by(list).changed);
        assert_eq!(state.sent.len(), 1);
        assert_eq!(state.received.invitations.len(), 1);
        assert_eq!(state.accepted.invitations.len(), 1);
    }