#![allow(
    clippy::type_complexity,
    clippy::too_many_arguments,
    clippy::large_enum_variant
)]

use mpstthree::binary::struct_trait::end::End;
use mpstthree::binary::struct_trait::session::Session;
use mpstthree::binary_atmp::struct_trait::{recv::RecvTimed, send::SendTimed};
use mpstthree::generate_atmp;
use mpstthree::role::broadcast::RoleBroadcast;
use mpstthree::role::end::RoleEnd;

use rand::{thread_rng, Rng};

use std::collections::HashMap;
use std::error::Error;
use std::time::Instant;

// See the folder scribble_protocols for the related Scribble protocol

// Create the new MeshedChannels for three participants and the close and fork functions
generate_atmp!(MeshedChannels, C, S);

// Stacks
// C
type ThreeRoleC = RoleC<RoleC<RoleC<RoleEnd>>>;
type FiveRoleC = RoleC<RoleC<RoleC<RoleC<RoleC<RoleEnd>>>>>;

// S
type TwoRoleS = RoleS<RoleS<RoleEnd>>;

// Types
// Step 0
// C
type Choose0fromCtoS = SendTimed<Branching0fromCtoS, 'a', 0, true, 10, true, ' ', End>;
type EndpointC0 = MeshedChannels<
    RecvTimed<(), 'a', 0, true, 10, true, ' ', Choose0fromCtoS>,
    RoleS<RoleBroadcast>,
    NameC,
>;

// S
enum Branching0fromCtoS {
    Continue(
        MeshedChannels<
            RecvTimed<(), 'a', 0, true, 10, true, ' ', Choose1fromStoC>,
            RoleC<RoleBroadcast>,
            NameS,
        >,
    ),
    Quit(MeshedChannels<RecvTimed<(), 'a', 0, true, 10, true, ' ', End>, RoleC<RoleEnd>, NameS>),
}
type Offer0fromCtoS = <Choose0fromCtoS as Session>::Dual;
type EndpointS0 = MeshedChannels<
    SendTimed<(), 'a', 0, true, 10, true, ' ', Offer0fromCtoS>,
    RoleC<RoleC<RoleEnd>>,
    NameS,
>;

// Step 1
// C
enum Branching1fromStoC {
    Continue(
        MeshedChannels<
            RecvTimed<(), 'a', 0, true, 10, true, ' ', Choose2fromCtoS>,
            RoleS<RoleBroadcast>,
            NameC,
        >,
    ),
    Loop(
        MeshedChannels<RecvTimed<(), 'a', 0, true, 10, true, ' ', Offer1fromStoC>, TwoRoleS, NameC>,
    ),
}
type Offer1fromStoC = <Choose1fromStoC as Session>::Dual;
type EndpointC1 = MeshedChannels<Offer1fromStoC, RoleS<RoleEnd>, NameC>;

// S
type Choose1fromStoC = SendTimed<Branching1fromStoC, 'a', 0, true, 10, true, ' ', End>;
type EndpointS1 = MeshedChannels<Choose1fromStoC, RoleBroadcast, NameS>;

// Step 2
// C
type Choose2fromCtoS = SendTimed<Branching2fromCtoS, 'a', 0, true, 10, true, ' ', End>;
type EndpointC2 = MeshedChannels<Choose2fromCtoS, RoleBroadcast, NameC>;

// S
enum Branching2fromCtoS {
    Continue(
        MeshedChannels<
            RecvTimed<
                (),
                'a',
                0,
                true,
                10,
                true,
                ' ',
                SendTimed<(), 'a', 0, true, 10, true, ' ', Offer3fromCtoS>,
            >,
            ThreeRoleC,
            NameS,
        >,
    ),
    Quit(MeshedChannels<RecvTimed<(), 'a', 0, true, 10, true, ' ', End>, RoleC<RoleEnd>, NameS>),
}
type Offer2fromCtoS = <Choose2fromCtoS as Session>::Dual;
type EndpointS2 = MeshedChannels<Offer2fromCtoS, RoleC<RoleEnd>, NameS>;

// Step 3
// C
type Choose3fromCtoS = SendTimed<Branching3fromCtoS, 'a', 0, true, 10, true, ' ', End>;
type EndpointC3 = MeshedChannels<Choose3fromCtoS, RoleBroadcast, NameC>;

// S
enum Branching3fromCtoS {
    Continue(
        MeshedChannels<
            RecvTimed<(), 'a', 0, true, 10, true, ' ', Choose4fromStoC>,
            RoleC<RoleBroadcast>,
            NameS,
        >,
    ),
    Quit(MeshedChannels<RecvTimed<(), 'a', 0, true, 10, true, ' ', End>, RoleC<RoleEnd>, NameS>),
}
type Offer3fromCtoS = <Choose3fromCtoS as Session>::Dual;
type EndpointS3 = MeshedChannels<Offer3fromCtoS, RoleC<RoleEnd>, NameS>;

// Step 4
// C
enum Branching4fromStoC {
    Continue(
        MeshedChannels<
            RecvTimed<(), 'a', 0, true, 10, true, ' ', Choose5fromCtoS>,
            RoleS<RoleBroadcast>,
            NameC,
        >,
    ),
    Loop(
        MeshedChannels<
            RecvTimed<(), 'a', 0, true, 10, true, ' ', Offer4fromStoC>,
            RoleS<RoleS<RoleEnd>>,
            NameC,
        >,
    ),
}
type Offer4fromStoC = <Choose4fromStoC as Session>::Dual;
type EndpointC4 = MeshedChannels<Offer4fromStoC, RoleS<RoleEnd>, NameC>;

// S
type Choose4fromStoC = SendTimed<Branching4fromStoC, 'a', 0, true, 10, true, ' ', End>;
type EndpointS4 = MeshedChannels<Choose4fromStoC, RoleBroadcast, NameS>;

// Step 5
// C
type Choose5fromCtoS = SendTimed<Branching5fromCtoS, 'a', 0, true, 10, true, ' ', End>;
type EndpointC5 = MeshedChannels<Choose5fromCtoS, RoleBroadcast, NameC>;

// S
enum Branching5fromCtoS {
    Continue(
        MeshedChannels<
            RecvTimed<(), 'a', 0, true, 10, true, ' ', Choose6fromStoC>,
            RoleC<RoleBroadcast>,
            NameS,
        >,
    ),
    Quit(MeshedChannels<RecvTimed<(), 'a', 0, true, 10, true, ' ', End>, RoleC<RoleEnd>, NameS>),
}
type Offer5fromCtoS = <Choose5fromCtoS as Session>::Dual;
type EndpointS5 = MeshedChannels<Offer5fromCtoS, RoleC<RoleEnd>, NameS>;

// Step 6
// C
enum Branching6fromStoC {
    Continue(
        MeshedChannels<
            RecvTimed<(), 'a', 0, true, 10, true, ' ', Choose7fromCtoS>,
            RoleS<RoleBroadcast>,
            NameC,
        >,
    ),
    Loop(
        MeshedChannels<
            RecvTimed<(), 'a', 0, true, 10, true, ' ', Offer6fromStoC>,
            RoleS<RoleS<RoleEnd>>,
            NameC,
        >,
    ),
}
type Offer6fromStoC = <Choose6fromStoC as Session>::Dual;
type EndpointC6 = MeshedChannels<Offer6fromStoC, RoleS<RoleEnd>, NameC>;

// S
type Choose6fromStoC = SendTimed<Branching6fromStoC, 'a', 0, true, 10, true, ' ', End>;
type EndpointS6 = MeshedChannels<Choose6fromStoC, RoleBroadcast, NameS>;

// Step 7
// C
type Choose7fromCtoS = SendTimed<Branching7fromCtoS, 'a', 0, true, 10, true, ' ', End>;
type EndpointC7 = MeshedChannels<Choose7fromCtoS, RoleBroadcast, NameC>;

// S
enum Branching7fromCtoS {
    Continue(
        MeshedChannels<
            RecvTimed<(), 'a', 0, true, 10, true, ' ', Choose8fromStoC>,
            RoleC<RoleBroadcast>,
            NameS,
        >,
    ),
    Quit(MeshedChannels<RecvTimed<(), 'a', 0, true, 10, true, ' ', End>, RoleC<RoleEnd>, NameS>),
}
type Offer7fromCtoS = <Choose7fromCtoS as Session>::Dual;
type EndpointS7 = MeshedChannels<Offer7fromCtoS, RoleC<RoleEnd>, NameS>;

// Step 8
// C
enum Branching8fromStoC {
    Continue(
        MeshedChannels<
            RecvTimed<(), 'a', 0, true, 10, true, ' ', Choose9fromCtoS>,
            RoleS<RoleBroadcast>,
            NameC,
        >,
    ),
    Loop(
        MeshedChannels<
            RecvTimed<(), 'a', 0, true, 10, true, ' ', Choose7fromCtoS>,
            RoleS<RoleBroadcast>,
            NameC,
        >,
    ),
}
type Offer8fromStoC = <Choose8fromStoC as Session>::Dual;
type EndpointC8 = MeshedChannels<Offer8fromStoC, RoleS<RoleEnd>, NameC>;

// S
type Choose8fromStoC = SendTimed<Branching8fromStoC, 'a', 0, true, 10, true, ' ', End>;
type EndpointS8 = MeshedChannels<Choose8fromStoC, RoleBroadcast, NameS>;

// Step 9
// C
type Choose9fromCtoS = SendTimed<Branching9fromCtoS, 'a', 0, true, 10, true, ' ', End>;
type EndpointC9 = MeshedChannels<Choose9fromCtoS, RoleBroadcast, NameC>;

// S
enum Branching9fromCtoS {
    Continue(MeshedChannels<FullOffer10fromCtoS, FiveRoleC, NameS>),
    Loop(
        MeshedChannels<
            RecvTimed<
                (),
                'a',
                0,
                true,
                10,
                true,
                ' ',
                SendTimed<(), 'a', 0, true, 10, true, ' ', Offer9fromCtoS>,
            >,
            ThreeRoleC,
            NameS,
        >,
    ),
}
type FullOffer10fromCtoS = RecvTimed<
    (),
    'a',
    0,
    true,
    10,
    true,
    ' ',
    SendTimed<
        (),
        'a',
        0,
        true,
        10,
        true,
        ' ',
        RecvTimed<
            (),
            'a',
            0,
            true,
            10,
            true,
            ' ',
            RecvTimed<(), 'a', 0, true, 10, true, ' ', Offer10fromCtoS>,
        >,
    >,
>;
type Offer9fromCtoS = <Choose9fromCtoS as Session>::Dual;
type EndpointS9 = MeshedChannels<Offer9fromCtoS, RoleC<RoleEnd>, NameS>;

// Step 10
// C
type Choose10fromCtoS = SendTimed<Branching10fromCtoS, 'a', 0, true, 10, true, ' ', End>;
type EndpointC10 = MeshedChannels<Choose10fromCtoS, RoleBroadcast, NameC>;

// S
enum Branching10fromCtoS {
    Data(
        MeshedChannels<
            RecvTimed<
                (),
                'a',
                0,
                true,
                10,
                true,
                ' ',
                RecvTimed<(), 'a', 0, true, 10, true, ' ', Offer10fromCtoS>,
            >,
            ThreeRoleC,
            NameS,
        >,
    ),
    Subject(
        MeshedChannels<
            RecvTimed<
                (),
                'a',
                0,
                true,
                10,
                true,
                ' ',
                RecvTimed<(), 'a', 0, true, 10, true, ' ', Offer10fromCtoS>,
            >,
            ThreeRoleC,
            NameS,
        >,
    ),
    End(
        MeshedChannels<
            RecvTimed<
                (),
                'a',
                0,
                true,
                10,
                true,
                ' ',
                SendTimed<(), 'a', 0, true, 10, true, ' ', Offer7fromCtoS>,
            >,
            ThreeRoleC,
            NameS,
        >,
    ),
}
type Offer10fromCtoS = <Choose10fromCtoS as Session>::Dual;
type EndpointS10 = MeshedChannels<Offer10fromCtoS, RoleC<RoleEnd>, NameS>;

// Functions
fn endpoint_c_0(
    s: EndpointC0,
    all_clocks: &mut HashMap<char, Instant>,
) -> Result<(), Box<dyn Error>> {
    all_clocks.insert('a', Instant::now());

    let (_, s) = s.recv(all_clocks)?;

    let expected: i32 = thread_rng().gen_range(1..=2);

    if expected == 1 {
        let s = choose_mpst_c_to_all!(s, all_clocks, Branching0fromCtoS::Continue);

        let s = s.send((), all_clocks)?;

        endpoint_c_1(s, all_clocks)
    } else {
        let s = choose_mpst_c_to_all!(s, all_clocks, Branching0fromCtoS::Quit);

        let s = s.send((), all_clocks)?;

        s.close()
    }
}

fn endpoint_c_1(
    s: EndpointC1,
    all_clocks: &mut HashMap<char, Instant>,
) -> Result<(), Box<dyn Error>> {
    offer_mpst!(s, all_clocks, {
        Branching1fromStoC::Continue(s) => {
            let (_, s) = s.recv(all_clocks)?;

            endpoint_c_2(s, all_clocks)
        },
        Branching1fromStoC::Loop(s) => {
            let (_, s) = s.recv(all_clocks)?;

            endpoint_c_1(s, all_clocks)
        },
    })
}

fn endpoint_c_2(
    s: EndpointC2,
    all_clocks: &mut HashMap<char, Instant>,
) -> Result<(), Box<dyn Error>> {
    let expected: i32 = thread_rng().gen_range(1..=2);

    if expected == 1 {
        let s = choose_mpst_c_to_all!(s, all_clocks, Branching2fromCtoS::Continue);

        let s = s.send((), all_clocks)?;
        let (_, s) = s.recv(all_clocks)?;

        endpoint_c_3(s, all_clocks)
    } else {
        let s = choose_mpst_c_to_all!(s, all_clocks, Branching2fromCtoS::Quit);

        let s = s.send((), all_clocks)?;

        s.close()
    }
}

fn endpoint_c_3(
    s: EndpointC3,
    all_clocks: &mut HashMap<char, Instant>,
) -> Result<(), Box<dyn Error>> {
    let expected: i32 = thread_rng().gen_range(1..=2);

    if expected == 1 {
        let s = choose_mpst_c_to_all!(s, all_clocks, Branching3fromCtoS::Continue);

        let s = s.send((), all_clocks)?;

        endpoint_c_4(s, all_clocks)
    } else {
        let s = choose_mpst_c_to_all!(s, all_clocks, Branching3fromCtoS::Quit);

        let s = s.send((), all_clocks)?;

        s.close()
    }
}

fn endpoint_c_4(
    s: EndpointC4,
    all_clocks: &mut HashMap<char, Instant>,
) -> Result<(), Box<dyn Error>> {
    offer_mpst!(s, all_clocks, {
        Branching4fromStoC::Continue(s) => {
            let (_, s) = s.recv(all_clocks)?;

            endpoint_c_5(s, all_clocks)
        },
        Branching4fromStoC::Loop(s) => {
            let (_, s) = s.recv(all_clocks)?;

            endpoint_c_4(s, all_clocks)
        },
    })
}

fn endpoint_c_5(
    s: EndpointC5,
    all_clocks: &mut HashMap<char, Instant>,
) -> Result<(), Box<dyn Error>> {
    let expected: i32 = thread_rng().gen_range(1..=2);

    if expected == 1 {
        let s = choose_mpst_c_to_all!(s, all_clocks, Branching5fromCtoS::Continue);

        let s = s.send((), all_clocks)?;

        endpoint_c_6(s, all_clocks)
    } else {
        let s = choose_mpst_c_to_all!(s, all_clocks, Branching5fromCtoS::Quit);

        let s = s.send((), all_clocks)?;

        s.close()
    }
}

fn endpoint_c_6(
    s: EndpointC6,
    all_clocks: &mut HashMap<char, Instant>,
) -> Result<(), Box<dyn Error>> {
    offer_mpst!(s, all_clocks, {
        Branching6fromStoC::Continue(s) => {
            let (_, s) = s.recv(all_clocks)?;

            endpoint_c_7(s, all_clocks)
        },
        Branching6fromStoC::Loop(s) => {
            let (_, s) = s.recv(all_clocks)?;

            endpoint_c_6(s, all_clocks)
        },
    })
}

fn endpoint_c_7(
    s: EndpointC7,
    all_clocks: &mut HashMap<char, Instant>,
) -> Result<(), Box<dyn Error>> {
    let expected: i32 = thread_rng().gen_range(1..=2);

    if expected == 1 {
        let s = choose_mpst_c_to_all!(s, all_clocks, Branching7fromCtoS::Continue);

        let s = s.send((), all_clocks)?;

        endpoint_c_8(s, all_clocks)
    } else {
        let s = choose_mpst_c_to_all!(s, all_clocks, Branching7fromCtoS::Quit);

        let s = s.send((), all_clocks)?;

        s.close()
    }
}

fn endpoint_c_8(
    s: EndpointC8,
    all_clocks: &mut HashMap<char, Instant>,
) -> Result<(), Box<dyn Error>> {
    offer_mpst!(s, all_clocks, {
        Branching8fromStoC::Continue(s) => {
            let (_, s) = s.recv(all_clocks)?;

            endpoint_c_9(s, all_clocks)
        },
        Branching8fromStoC::Loop(s) => {
            let (_, s) = s.recv(all_clocks)?;

            endpoint_c_7(s, all_clocks)
        },
    })
}

fn endpoint_c_9(
    s: EndpointC9,
    all_clocks: &mut HashMap<char, Instant>,
) -> Result<(), Box<dyn Error>> {
    let expected: i32 = thread_rng().gen_range(1..=2);

    if expected == 1 {
        let s = choose_mpst_c_to_all!(s, all_clocks, Branching9fromCtoS::Continue);

        let s = s.send((), all_clocks)?;
        let (_, s) = s.recv(all_clocks)?;
        let s = s.send((), all_clocks)?;
        let s = s.send((), all_clocks)?;

        endpoint_c_10(s, all_clocks)
    } else {
        let s = choose_mpst_c_to_all!(s, all_clocks, Branching9fromCtoS::Loop);

        let s = s.send((), all_clocks)?;
        let (_, s) = s.recv(all_clocks)?;

        endpoint_c_9(s, all_clocks)
    }
}

fn endpoint_c_10(
    s: EndpointC10,
    all_clocks: &mut HashMap<char, Instant>,
) -> Result<(), Box<dyn Error>> {
    let expected: i32 = thread_rng().gen_range(1..=3);

    if expected == 1 {
        let s = choose_mpst_c_to_all!(s, all_clocks, Branching10fromCtoS::Data);

        let s = s.send((), all_clocks)?;
        let s = s.send((), all_clocks)?;

        endpoint_c_10(s, all_clocks)
    } else if expected == 2 {
        let s = choose_mpst_c_to_all!(s, all_clocks, Branching10fromCtoS::Subject);

        let s = s.send((), all_clocks)?;
        let s = s.send((), all_clocks)?;

        endpoint_c_10(s, all_clocks)
    } else {
        let s = choose_mpst_c_to_all!(s, all_clocks, Branching10fromCtoS::End);

        let s = s.send((), all_clocks)?;
        let (_, s) = s.recv(all_clocks)?;

        endpoint_c_7(s, all_clocks)
    }
}

///

fn endpoint_s_0(
    s: EndpointS0,
    all_clocks: &mut HashMap<char, Instant>,
) -> Result<(), Box<dyn Error>> {
    all_clocks.insert('a', Instant::now());

    let s = s.send((), all_clocks)?;

    offer_mpst!(s, all_clocks, {
        Branching0fromCtoS::Quit(s) => {
            let (_, s) = s.recv(all_clocks)?;

            s.close()
        },
        Branching0fromCtoS::Continue(s) => {
            let (_, s) = s.recv(all_clocks)?;

            endpoint_s_1(s, all_clocks)
        },
    })
}

fn endpoint_s_1(
    s: EndpointS1,
    all_clocks: &mut HashMap<char, Instant>,
) -> Result<(), Box<dyn Error>> {
    let expected: i32 = thread_rng().gen_range(1..=2);

    if expected == 1 {
        let s = choose_mpst_s_to_all!(s, all_clocks, Branching1fromStoC::Continue);

        let s = s.send((), all_clocks)?;

        endpoint_s_2(s, all_clocks)
    } else {
        let s = choose_mpst_s_to_all!(s, all_clocks, Branching1fromStoC::Loop);

        let s = s.send((), all_clocks)?;

        endpoint_s_1(s, all_clocks)
    }
}

fn endpoint_s_2(
    s: EndpointS2,
    all_clocks: &mut HashMap<char, Instant>,
) -> Result<(), Box<dyn Error>> {
    offer_mpst!(s, all_clocks, {
        Branching2fromCtoS::Quit(s) => {
            let (_, s) = s.recv(all_clocks)?;

            s.close()
        },
        Branching2fromCtoS::Continue(s) => {
            let (_, s) = s.recv(all_clocks)?;
            let s = s.send((), all_clocks)?;

            endpoint_s_3(s, all_clocks)
        },
    })
}

fn endpoint_s_3(
    s: EndpointS3,
    all_clocks: &mut HashMap<char, Instant>,
) -> Result<(), Box<dyn Error>> {
    offer_mpst!(s, all_clocks, {
        Branching3fromCtoS::Quit(s) => {
            let (_, s) = s.recv(all_clocks)?;

            s.close()
        },
        Branching3fromCtoS::Continue(s) => {
            let (_, s) = s.recv(all_clocks)?;

            endpoint_s_4(s, all_clocks)
        },
    })
}

fn endpoint_s_4(
    s: EndpointS4,
    all_clocks: &mut HashMap<char, Instant>,
) -> Result<(), Box<dyn Error>> {
    let expected: i32 = thread_rng().gen_range(1..=2);

    if expected == 1 {
        let s = choose_mpst_s_to_all!(s, all_clocks, Branching4fromStoC::Continue);

        let s = s.send((), all_clocks)?;

        endpoint_s_5(s, all_clocks)
    } else {
        let s = choose_mpst_s_to_all!(s, all_clocks, Branching4fromStoC::Loop);

        let s = s.send((), all_clocks)?;

        endpoint_s_4(s, all_clocks)
    }
}

fn endpoint_s_5(
    s: EndpointS5,
    all_clocks: &mut HashMap<char, Instant>,
) -> Result<(), Box<dyn Error>> {
    offer_mpst!(s, all_clocks, {
        Branching5fromCtoS::Quit(s) => {
            let (_, s) = s.recv(all_clocks)?;

            s.close()
        },
        Branching5fromCtoS::Continue(s) => {
            let (_, s) = s.recv(all_clocks)?;

            endpoint_s_6(s, all_clocks)
        },
    })
}

fn endpoint_s_6(
    s: EndpointS6,
    all_clocks: &mut HashMap<char, Instant>,
) -> Result<(), Box<dyn Error>> {
    let expected: i32 = thread_rng().gen_range(1..=2);

    if expected == 1 {
        let s = choose_mpst_s_to_all!(s, all_clocks, Branching6fromStoC::Continue);

        let s = s.send((), all_clocks)?;

        endpoint_s_7(s, all_clocks)
    } else {
        let s = choose_mpst_s_to_all!(s, all_clocks, Branching6fromStoC::Loop);

        let s = s.send((), all_clocks)?;

        endpoint_s_6(s, all_clocks)
    }
}

fn endpoint_s_7(
    s: EndpointS7,
    all_clocks: &mut HashMap<char, Instant>,
) -> Result<(), Box<dyn Error>> {
    offer_mpst!(s, all_clocks, {
        Branching7fromCtoS::Quit(s) => {
            let (_, s) = s.recv(all_clocks)?;

            s.close()
        },
        Branching7fromCtoS::Continue(s) => {
            let (_, s) = s.recv(all_clocks)?;

            endpoint_s_8(s, all_clocks)
        },
    })
}

fn endpoint_s_8(
    s: EndpointS8,
    all_clocks: &mut HashMap<char, Instant>,
) -> Result<(), Box<dyn Error>> {
    let expected: i32 = thread_rng().gen_range(1..=2);

    if expected == 1 {
        let s = choose_mpst_s_to_all!(s, all_clocks, Branching8fromStoC::Continue);

        let s = s.send((), all_clocks)?;

        endpoint_s_9(s, all_clocks)
    } else {
        let s = choose_mpst_s_to_all!(s, all_clocks, Branching8fromStoC::Loop);

        let s = s.send((), all_clocks)?;

        endpoint_s_7(s, all_clocks)
    }
}

fn endpoint_s_9(
    s: EndpointS9,
    all_clocks: &mut HashMap<char, Instant>,
) -> Result<(), Box<dyn Error>> {
    offer_mpst!(s, all_clocks, {
        Branching9fromCtoS::Loop(s) => {
            let (_, s) = s.recv(all_clocks)?;
            let s = s.send((), all_clocks)?;

            endpoint_s_9(s, all_clocks)
        },
        Branching9fromCtoS::Continue(s) => {
            let (_, s) = s.recv(all_clocks)?;
            let s = s.send((), all_clocks)?;
            let (_, s) = s.recv(all_clocks)?;
            let (_, s) = s.recv(all_clocks)?;

            endpoint_s_10(s, all_clocks)
        },
    })
}

fn endpoint_s_10(
    s: EndpointS10,
    all_clocks: &mut HashMap<char, Instant>,
) -> Result<(), Box<dyn Error>> {
    offer_mpst!(s, all_clocks, {
        Branching10fromCtoS::Data(s) => {
            let (_, s) = s.recv(all_clocks)?;
            let (_, s) = s.recv(all_clocks)?;

            endpoint_s_10(s, all_clocks)
        },
        Branching10fromCtoS::Subject(s) => {
            let (_, s) = s.recv(all_clocks)?;
            let (_, s) = s.recv(all_clocks)?;

            endpoint_s_10(s, all_clocks)
        },
        Branching10fromCtoS::End(s) => {
            let (_, s) = s.recv(all_clocks)?;
            let s = s.send((), all_clocks)?;

            endpoint_s_7(s, all_clocks)
        },
    })
}

///

fn main() {
    let (thread_c, thread_s) = fork_mpst(endpoint_c_0, endpoint_s_0);

    thread_c.join().unwrap();
    thread_s.join().unwrap();
}