~thatonelutenist/actm

433f136df117b76c2857dcaa40ca2c6c50d085a1 — Nathan McCarty 1 year, 9 months ago fe0e5d9
feat: Make macros take care of completion token
M examples/grading-tests/professor.rs => examples/grading-tests/professor.rs +2 -11
@@ 69,21 69,12 @@ wrapped_event!(ProfessorOutputEvent, ProfessorOutputType);

async fn professor_event_handler(
    mut context: ProfessorContext,
    mut event: ProfessorInputEvent,
    event: ProfessorInputEvent,
) -> (ProfessorContext, Option<ProfessorOutputEvent>) {
    // Pull out the completion token, if there is any
    let token = event.token();
    // handle the event, adding the token back in
    let mut output = event
    let output = event
        .into_inner()
        .operate(&mut context)
        .map(ProfessorOutputEvent::from);
    // Reattach the token if we have one, and there is an event
    if let Some(token) = token {
        if let Some(event) = output.as_mut() {
            event.set_completion_token(token);
        }
    }
    // Finish up
    (context, output)
}

M examples/grading-tests/student.rs => examples/grading-tests/student.rs +2 -6
@@ 34,9 34,8 @@ wrapped_event!(StudentOutputEvent, StudentOutput);

async fn student_event_handler(
    context: StudentContext,
    mut event: StudentInputEvent,
    event: StudentInputEvent,
) -> (StudentContext, Option<StudentOutputEvent>) {
    let token = event.token();
    let mut rng = nanorand::tls_rng();
    let results = event
        .into_inner()


@@ 46,14 45,11 @@ async fn student_event_handler(
        .map(|x| -> bool { x > rng.generate_range(1_u32..=100) })
        .collect::<Vec<_>>();
    let name = context.name.clone();
    let mut new_event: StudentOutputEvent = StudentOutput {
    let new_event: StudentOutputEvent = StudentOutput {
        answers: Answers { answers: results },
        name,
    }
    .into();
    if let Some(token) = token {
        new_event.set_completion_token(token);
    }
    (context, Some(new_event))
}


M examples/grading-tests/university.rs => examples/grading-tests/university.rs +2 -8
@@ 2,8 2,6 @@ use std::collections::BTreeMap;

use actm::prelude::*;



// First we define the context type

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]


@@ 30,9 28,8 @@ wrapped_event!(UniveristyInputEvent, UniversityInput);

async fn university_event_handler(
    mut context: UniversityContext,
    mut event: UniveristyInputEvent,
    event: UniveristyInputEvent,
) -> (UniversityContext, Option<UniversityOutputEvent>) {
    let token = event.token();
    match event.into_inner() {
        UniversityInput::Grade(student, grade) => {
            let grades = context.students.entry(student).or_default();


@@ 40,10 37,7 @@ async fn university_event_handler(
            (context, None)
        }
        UniversityInput::Get => {
            let mut event = UniversityOutputEvent::from(UniversityOutput(context.students.clone()));
            if let Some(token) = token {
                event.set_completion_token(token);
            }
            let event = UniversityOutputEvent::from(UniversityOutput(context.students.clone()));
            (context, Some(event))
        }
    }

M src/testing_util.rs => src/testing_util.rs +29 -55
@@ 58,33 58,22 @@ wrapped_event!(OutputEvent, Output);
// Async actor definition

#[allow(clippy::unused_async)]
async fn async_math_event_handler(
    mut value: i64,
    mut math: MathEvent,
) -> (i64, Option<OutputEvent>) {
    // Pull out the completion token, if there is any
    let token = math.token();
async fn async_math_event_handler(mut value: i64, math: MathEvent) -> (i64, Option<OutputEvent>) {
    // Perform the operation
    let old_value = value;
    let math = math.into_inner();
    value = math.operate(value);
    // Check to see if there was a completion token, if so, send back an Output
    if let Some(token) = token {
        // Make our output
        let output = Output {
            before: old_value,
            after: value,
            input: math,
        };
        // Wrap it up
        let mut output = OutputEvent::from(output);
        // Attach the token
        output.set_completion_token(token);
        // Send it up
        (value, Some(output))
    } else {
        (value, None)
    }
    // Make our output
    let output = Output {
        before: old_value,
        after: value,
        input: math,
    };
    // Wrap it up
    let output = OutputEvent::from(output);
    // Send it up
    (value, Some(output))
}

async_actor!(


@@ 97,30 86,23 @@ async_actor!(

// Sync Actor Definition

fn math_event_handler(value: &mut i64, mut math: MathEvent) -> Option<OutputEvent> {
    // Pull out the completion token, if there is any
    let token = math.token();
#[allow(clippy::unnecessary_wraps)]
fn math_event_handler(value: &mut i64, math: MathEvent) -> Option<OutputEvent> {
    // Perform the operation
    let old_value = *value;
    let math = math.into_inner();
    *value = math.operate(*value);
    // Check to see if there was a completion token, if so, send back an Output
    if let Some(token) = token {
        // Make our output
        let output = Output {
            before: old_value,
            after: *value,
            input: math,
        };
        // Wrap it up
        let mut output = OutputEvent::from(output);
        // Attach the token
        output.set_completion_token(token);
        // Send it up
        Some(output)
    } else {
        None
    }
    // Make our output
    let output = Output {
        before: old_value,
        after: *value,
        input: math,
    };
    // Wrap it up
    let output = OutputEvent::from(output);
    // Send it up
    Some(output)
}

sync_actor!(


@@ 150,11 132,7 @@ mod tests {
            assert!(actor.catchup().wait().await);
            // Add some numbers to our internal count
            for i in 1..=10 {
                let mut event: MathEvent = MathEventType::Add(Add(i)).into();
                if i % 2 == 0 {
                    // Tokenize the even events for testing the event sending behavior
                    let _token = event.tokenize();
                }
                let event: MathEvent = MathEventType::Add(Add(i)).into();
                actor.inbox().accept(event).await.unwrap();
            }
            // Make sure we have the correct count


@@ 169,13 147,13 @@ mod tests {
            // Make sure our events are as expected
            let output_events = output
                .stream()
                .take(6)
                .take(11)
                .map(|x| x.into_inner().input)
                .collect::<Vec<_>>()
                .await;
            println!("Events in output: {:?}", output_events);
            assert_eq!(
                [2, 4, 6, 8, 10, 0]
                [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0]
                    .into_iter()
                    .map(|x| MathEventType::Add(Add(x)))
                    .collect::<Vec<_>>(),


@@ 200,11 178,7 @@ mod tests {
            // Add some numbers to our internal count
            for i in 1..=10 {
                println!("Sending event {i}");
                let mut event: MathEvent = MathEventType::Add(Add(i)).into();
                if i % 2 == 0 {
                    // Tokenize the even events for testing the event sending behavior
                    let _token = event.tokenize();
                }
                let event: MathEvent = MathEventType::Add(Add(i)).into();
                actor.inbox().accept_sync(event).unwrap();
                println!("Sent event {i}");
            }


@@ 221,12 195,12 @@ mod tests {
            // Make sure our events are as expected
            let output_events = output
                .iter()
                .take(6)
                .take(11)
                .map(|x| x.into_inner().input)
                .collect::<Vec<_>>();
            println!("Events in output: {:?}", output_events);
            assert_eq!(
                [2, 4, 6, 8, 10, 0]
                [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0]
                    .into_iter()
                    .map(|x| MathEventType::Add(Add(x)))
                    .collect::<Vec<_>>(),

M src/util/async_actor/newtype_macro.rs => src/util/async_actor/newtype_macro.rs +16 -1
@@ 12,7 12,22 @@ macro_rules! async_actor {
        }
        impl<X: Executor> $type_name<X> {
            pub fn new(initial_context: $context_type, bound: Option<usize>) -> Self {
                let actor = AsyncActor::spawn_async($event_method, initial_context, bound);
                let actor = AsyncActor::spawn_async(
                    |value: $context_type, mut event: $input_type| async move {
                        // Withdraw the completion token
                        let token = event.token();
                        let mut result = $event_method(value, event).await;
                        // slot the token back in if we have it
                        if let Some(token) = token {
                            if let Some(event) = result.1.as_mut() {
                                event.set_completion_token(token);
                            }
                        }
                        result
                    },
                    initial_context,
                    bound,
                );
                Self(actor)
            }
        }

M src/util/sync_actor/newtype_macro.rs => src/util/sync_actor/newtype_macro.rs +14 -1
@@ 7,7 7,20 @@ macro_rules! sync_actor {
        pub struct $type_name<X: Executor>(SyncActor<$input_type, $output_type, X>);
        impl<X: Executor> $type_name<X> {
            pub fn new(initial_context: $context_type, bound: Option<usize>) -> Self {
                let actor = SyncActor::spawn($event_method, initial_context, bound);
                let actor = SyncActor::spawn(
                    |value: &mut $context_type, mut event: $input_type| {
                        let token = event.token();
                        let mut result = $event_method(value, event);
                        if let Some(token) = token {
                            if let Some(event) = result.as_mut() {
                                event.set_completion_token(token);
                            }
                        }
                        result
                    },
                    initial_context,
                    bound,
                );
                Self(actor)
            }
        }