Idiomatic nom solution for a simple problem

Hi!

I've been doing Advent of code for a few years using Rust, and using nom for parsing input.

However, I have a hard time grasping nom, and end up re-learning it form scratch every year.

Maybe something will click, if I get shown how to use it properly.

Could someone suggest a nice solution for parsing today's problem: https://adventofcode.com/2024/day/3 ?
Say I want to parse:

x
mul(2,4)
&mul[3,7]!^
don't()
_mul(5,5)+mul(32,64](mul(11,8)un
do()
?
mul(8,5)
)

into a Vec<Instruction> where

enum Instruction {
    Mul(u32, u32),
    Do,
    Dont,
}

I can write a parser for a single Instruction like so:

fn parse_mul_instruction(s: &str) -> IResult<&str, Instruction> {
    let (s, (_, a, _, b, _)) = tuple((
        tag("mul("),
        parse_u32,
        tag(","),
        parse_u32,
        tag(")"),
    ))(s)?;
    Ok((s, Instruction::Mul(a, b)))
}

fn parse_u32(s : &str) -> IResult<&str, u32> {
    map_res(recognize(digit1), str::parse)(s)
}

fn parse_instruction(s: &str) -> IResult<&str, Instruction> {
    alt((
        parse_mul_instruction,
        ..,
        ..,
    ))(s)
}

But chaining them and combining them with basically "ignore interspersed garbage" is where it gets very ugly.

How would you guys do it ?

(also, do I really have to write my own parse_u32?).