Control: tags -1 + patch

Hi Peter,

On Tue, 2026-08-04 at 08:47 +0100, Peter Green wrote:
> Package: rust-dtui
> Version: 3.0.0-3
> Severity: serious
> Tags: ftbfs
> x-debbugs-cc: [email protected]
> 
> rust-chumsky was recently updated to 0.13, leaving the build-depends
> of rust-dtui unsatisfiable.
> 
> I've looked at updating but it looks non-trivial, the upstream changelog
> says that 0.10 was a rewrite and bumping the dependency results in a wall
> of errors.
> 
> I've also filed an upstream issue at 
> https://github.com/Troels51/dtui/issues/14
> 
> Maybe we have to introduce a semver-suffix package here.

Please find attached a patch which allows dtui to use the new 0.13 API.

It builds locally with cargo and the upstream repo; but I didn't have time to 
integrate into debcargo-config.


Cheers!

Chris
From 0e6a9f49fff42aa6ea43e9e5b726584c5e48bfd9 Mon Sep 17 00:00:00 2001
From: Christopher Obbard <[email protected]>
Date: Tue, 4 Aug 2026 15:59:54 +0100
Subject: [PATCH] bump chumsky to 0.13

Closes: #1143559
Signed-off-by: Christopher Obbard <[email protected]>
---
 Cargo.toml                           |   2 +-
 src/bin/dtui/components/call_view.rs |  35 +--
 src/bin/dtui/messages.rs             |   1 -
 src/bin/dtui/parser.rs               | 310 ++++++++++++---------------
 4 files changed, 159 insertions(+), 189 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index d194eb2..25f4f02 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -28,7 +28,7 @@ tracing = "0.1.41"
 tracing-subscriber = { version = "0.3.20", features = ["env-filter", "json", "fmt"] }
 tracing-journald = "0.3.1"
 tui-textarea = "0.7"
-chumsky = "0.9.3"
+chumsky = "0.13"
 zbus = {version = "5.11.0", features = ["tokio", "serde_bytes"]}
 zbus_names = "4.2.0"
 zbus_xml = "5.0.2"
diff --git a/src/bin/dtui/components/call_view.rs b/src/bin/dtui/components/call_view.rs
index c833210..c4bcf30 100644
--- a/src/bin/dtui/components/call_view.rs
+++ b/src/bin/dtui/components/call_view.rs
@@ -24,10 +24,19 @@ use crate::{
 
 pub struct MethodArgVisual {
     pub text_area: tui_textarea::TextArea<'static>,
-    pub parser:
-        Box<dyn Parser<char, zbus::zvariant::Value<'static>, Error = chumsky::error::Simple<char>>>,
+    // chumsky parsers borrow from the input they parse, so we keep the signature around and
+    // build a parser on demand instead of storing one.
+    pub signature: zbus::zvariant::Signature,
     pub is_input: bool, // Is this Arg an input or output
 }
+
+impl MethodArgVisual {
+    fn parse(&self) -> Result<zbus::zvariant::Value<'static>, Vec<chumsky::error::Rich<'_, char>>> {
+        get_parser(self.signature.clone())
+            .parse(self.text_area.lines()[0].as_str())
+            .into_result()
+    }
+}
 // Encapsulates the information about the ongoing call
 struct OngoingCallInfo {
     invocation: Invocation,
@@ -63,17 +72,16 @@ impl OngoingCallInfo {
                             .title(format!("name: {} | {}", arg.name().unwrap(), inout))
                             .title_bottom(format!("type: {}", arg.ty().to_string())),
                     );
-                    let parser = get_parser(
+                    let signature =
                         zbus::zvariant::Signature::from_str(arg.ty().to_string().as_str())
-                            .expect("The type description for the method we got was not good"),
-                    );
+                            .expect("The type description for the method we got was not good");
                     let input = match arg.direction().unwrap_or(zbus_xml::ArgDirection::In) {
                         zbus_xml::ArgDirection::In => true,
                         zbus_xml::ArgDirection::Out => false,
                     };
                     call_info.method_arg_vis.push(MethodArgVisual {
                         text_area,
-                        parser: Box::new(parser),
+                        signature,
                         is_input: input,
                     });
                 }
@@ -90,13 +98,12 @@ impl OngoingCallInfo {
                         .title(format!("name: {} | {}", property.name(), "input"))
                         .title_bottom(format!("type: {}", property.ty().to_string())),
                 );
-                let parser = Box::new(get_parser(
+                let signature =
                     zbus::zvariant::Signature::from_str(property.ty().to_string().as_str())
-                        .expect("The type description for the method we got was not good"),
-                ));
+                        .expect("The type description for the method we got was not good");
                 call_info.method_arg_vis.push(MethodArgVisual {
                     text_area,
-                    parser,
+                    signature,
                     is_input: true,
                 });
 
@@ -161,9 +168,7 @@ impl CallView {
         let segments = single_line_layout.split(area);
         for (i, input) in ongoing.method_arg_vis.iter_mut().enumerate() {
             let emphasis = if i == ongoing.selected && active {
-                let method_arg: String = input.text_area.lines()[0].clone();
-                let parsed = input.parser.parse(method_arg);
-                match parsed {
+                match input.parse() {
                     Ok(_) => Style::default().fg(Color::Green),
                     Err(_) => Style::default().fg(Color::Red),
                 }
@@ -230,11 +235,11 @@ impl Component for CallView {
                             .method_arg_vis
                             .iter()
                             .filter(|input| input.is_input)
-                            .map(|input| input.parser.parse(input.text_area.lines()[0].clone()));
+                            .map(|input| input.parse());
                         if parses.clone().all(
                             |result: Result<
                                 zbus::zvariant::Value<'static>,
-                                Vec<chumsky::error::Simple<char>>,
+                                Vec<chumsky::error::Rich<'_, char>>,
                             >| Result::is_ok(&result),
                         ) {
                             let values: Vec<zbus::zvariant::OwnedValue> = parses
diff --git a/src/bin/dtui/messages.rs b/src/bin/dtui/messages.rs
index 684331c..85bf0d0 100644
--- a/src/bin/dtui/messages.rs
+++ b/src/bin/dtui/messages.rs
@@ -1,6 +1,5 @@
 use std::collections::HashMap;
 
-use chumsky::chain::Chain;
 use zbus::{
     names::{OwnedBusName, OwnedInterfaceName, OwnedMemberName},
     zvariant::{OwnedObjectPath, OwnedValue},
diff --git a/src/bin/dtui/parser.rs b/src/bin/dtui/parser.rs
index 205974f..b098139 100644
--- a/src/bin/dtui/parser.rs
+++ b/src/bin/dtui/parser.rs
@@ -1,7 +1,13 @@
+use chumsky::input::InputRef;
 use chumsky::prelude::*;
 use std::{collections::HashMap, str::FromStr, u32};
 use zbus::zvariant::{self, ObjectPath, Signature, StructureBuilder};
 
+/// The extra parser state used by every parser in this module.
+type Extra<'src> = extra::Err<Rich<'src, char>>;
+/// A boxed parser over a string input, producing a dbus value.
+type ValueParser<'src> = Boxed<'src, 'src, &'src str, zvariant::Value<'static>, Extra<'src>>;
+
 /// Create a parser from a Signature.
 /// The language that this parses is a human readable version of the dbus format.
 /// Arrays are delimited by [], with values seperated by ","
@@ -14,12 +20,10 @@ use zbus::zvariant::{self, ObjectPath, Signature, StructureBuilder};
 ///
 /// ```
 /// let signature = Signature::from_str("as").unwrap();
-/// let result = get_parser(signature).parse("[\"first\", \"second\"]");
+/// let result = get_parser(signature).parse("[\"first\", \"second\"]").into_result();
 /// assert_eq!(result, Ok(zvariant::Value::Array(vec!["first", "second"].into())));
 /// ```
-pub fn get_parser(
-    signature: Signature,
-) -> impl Parser<char, zvariant::Value<'static>, Error = Simple<char>> {
+pub fn get_parser<'src>(signature: Signature) -> ValueParser<'src> {
     match signature {
         zvariant::Signature::Unit => todo!(),
         zvariant::Signature::U8 => parser_u8().boxed(),
@@ -34,7 +38,7 @@ pub fn get_parser(
         zvariant::Signature::Str => parser_string().boxed(),
         zvariant::Signature::Signature => parser_signature().boxed(),
         zvariant::Signature::ObjectPath => parser_object_path().boxed(),
-        zvariant::Signature::Variant => parser_variant().boxed(),
+        zvariant::Signature::Variant => parser_variant(),
         zvariant::Signature::Fd => parser_fd().boxed(),
         zvariant::Signature::Array(child) => parser_array(child.signature().clone()).boxed(),
         zvariant::Signature::Dict { key, value } => {
@@ -44,33 +48,45 @@ pub fn get_parser(
     }
 }
 
-fn parser_variant<'a>() -> impl Parser<char, zvariant::Value<'static>, Error = Simple<char>> {
-    parser_signature()
-        .boxed()
-        .then_ignore(just("->"))
-        .then_with(|s| match s {
-            zvariant::Value::Signature(signature) => {
-                get_parser(signature).map(|variant| zvariant::Value::Value(Box::new(variant)))
-            }
+/// The inner parser of a variant depends on the signature that precedes it, so it can only be
+/// built once that signature has been parsed. `custom` gives us access to the input so we can
+/// run a parser that is constructed on the fly.
+fn parser_variant<'src>() -> ValueParser<'src> {
+    custom::<_, &'src str, _, Extra<'src>>(|input: &mut InputRef<'src, '_, _, _>| {
+        let signature = match input.parse(parser_signature())? {
+            zvariant::Value::Signature(signature) => signature,
             _ => unreachable!(),
-        })
+        };
+        input.parse(just("->"))?;
+        let value = input.parse(get_parser(signature))?;
+        Ok(zvariant::Value::Value(Box::new(value)))
+    })
+    .boxed()
 }
 //
-fn parser_struct<'a>(
+fn parser_struct<'src>(
     structure: zvariant::signature::Fields,
-) -> impl Parser<char, zvariant::Value<'a>, Error = Simple<char>> {
+) -> impl Parser<'src, &'src str, zvariant::Value<'static>, Extra<'src>> + Clone {
     let mut element_parsers = structure
         .iter()
         .map(|signature: &zbus::zvariant::Signature| get_parser(signature.clone()));
-    let mut full_parser = just('(').map(|_| Vec::<zvariant::Value<'_>>::new()).boxed(); // The map is there to get types to match as the chain in the loop needs the parser to output a Vec
-    full_parser = full_parser.chain(element_parsers.next().unwrap()).boxed(); // The first doesnt get a ',' the rest do
+    // The first element doesn't get a ',' the rest do
+    let mut full_parser = element_parsers
+        .next()
+        .unwrap()
+        .map(|value| vec![value])
+        .boxed();
     for element_parser in element_parsers {
         full_parser = full_parser
             .then_ignore(just(",").padded())
-            .chain(element_parser)
+            .then(element_parser)
+            .map(|(mut fields, field)| {
+                fields.push(field);
+                fields
+            })
             .boxed();
     }
-    full_parser = full_parser.then_ignore(just(')').padded()).boxed();
+    let full_parser = full_parser.delimited_by(just('(').padded(), just(')').padded());
 
     full_parser.map(|fields| {
         let mut builder = StructureBuilder::new();
@@ -80,10 +96,10 @@ fn parser_struct<'a>(
         zvariant::Value::Structure(builder.build().unwrap())
     })
 }
-fn parser_dict<'a>(
+fn parser_dict<'src>(
     key_type: Signature,
     value_type: Signature,
-) -> impl Parser<char, zvariant::Value<'a>, Error = Simple<char>> {
+) -> impl Parser<'src, &'src str, zvariant::Value<'static>, Extra<'src>> + Clone {
     let key_parser = get_parser(key_type.clone());
     let value_parser = get_parser(value_type.clone());
     let member_parser = key_parser
@@ -91,12 +107,9 @@ fn parser_dict<'a>(
         .then(value_parser)
         .boxed();
     member_parser
-        .clone()
-        .chain(just(',').padded().ignore_then(member_parser).repeated())
-        .or_not()
-        .flatten()
+        .separated_by(just(',').padded())
+        .collect::<HashMap<zvariant::Value<'static>, zvariant::Value<'static>>>()
         .delimited_by(just('{').padded(), just('}').padded())
-        .collect::<HashMap<zvariant::Value<'_>, zvariant::Value<'_>>>()
         .map(
             move |m: HashMap<zvariant::Value<'_>, zvariant::Value<'_>>| {
                 let mut dict =
@@ -109,20 +122,13 @@ fn parser_dict<'a>(
         )
 }
 
-fn parser_array<'a>(
+fn parser_array<'src>(
     signature: Signature,
-) -> impl Parser<char, zvariant::Value<'a>, Error = Simple<char>> {
-    let element_parser = get_parser(signature.clone()).boxed();
+) -> impl Parser<'src, &'src str, zvariant::Value<'static>, Extra<'src>> + Clone {
+    let element_parser = get_parser(signature.clone());
     element_parser
-        .clone()
-        .chain(
-            just(',')
-                .padded()
-                .ignore_then(element_parser.clone())
-                .repeated(),
-        )
-        .or_not()
-        .flatten()
+        .separated_by(just(',').padded())
+        .collect::<Vec<zvariant::Value<'static>>>()
         .delimited_by(just('['), just(']'))
         .map(move |v: Vec<zvariant::Value<'_>>| {
             let mut array: zvariant::Array<'_> = zvariant::Array::new(&signature);
@@ -136,201 +142,161 @@ fn parser_array<'a>(
 }
 // TODO: Can these be made generic, not sure how as they are generic over the Value type which is enums
 // TODO: Validation on sizes of numbers
-fn parser_u8() -> impl Parser<char, zvariant::Value<'static>, Error = Simple<char>> {
+fn parser_u8<'src>() -> impl Parser<'src, &'src str, zvariant::Value<'static>, Extra<'src>> + Clone {
     text::digits(10)
+        .to_slice()
         .labelled("u8")
-        .map(|s: String| zvariant::Value::U8(s.parse().unwrap()))
+        .map(|s: &str| zvariant::Value::U8(s.parse().unwrap()))
         .padded()
 }
-fn parser_u16() -> impl Parser<char, zvariant::Value<'static>, Error = Simple<char>> {
+fn parser_u16<'src>() -> impl Parser<'src, &'src str, zvariant::Value<'static>, Extra<'src>> + Clone
+{
     text::digits(10)
+        .to_slice()
         .labelled("u16")
-        .map(|s: String| zvariant::Value::U16(s.parse().unwrap()))
+        .map(|s: &str| zvariant::Value::U16(s.parse().unwrap()))
         .padded()
 }
-fn parser_i16() -> impl Parser<char, zvariant::Value<'static>, Error = Simple<char>> {
+fn parser_i16<'src>() -> impl Parser<'src, &'src str, zvariant::Value<'static>, Extra<'src>> + Clone
+{
     just('-')
         .or_not()
-        .chain::<char, _, _>(text::digits(10))
-        .collect::<String>()
-        .map(|s: String| zvariant::Value::I16(s.parse().unwrap()))
+        .then(text::digits(10))
+        .to_slice()
+        .map(|s: &str| zvariant::Value::I16(s.parse().unwrap()))
         .labelled("i16")
         .padded()
 }
-fn parser_u32() -> impl Parser<char, zvariant::Value<'static>, Error = Simple<char>> {
+fn parser_u32<'src>() -> impl Parser<'src, &'src str, zvariant::Value<'static>, Extra<'src>> + Clone
+{
     text::digits(10)
+        .to_slice()
         .labelled("u32")
-        .map(|s: String| zvariant::Value::U32(s.parse().unwrap()))
+        .map(|s: &str| zvariant::Value::U32(s.parse().unwrap()))
         .padded()
 }
-fn parser_i32() -> impl Parser<char, zvariant::Value<'static>, Error = Simple<char>> {
+fn parser_i32<'src>() -> impl Parser<'src, &'src str, zvariant::Value<'static>, Extra<'src>> + Clone
+{
     just('-')
         .or_not()
-        .chain::<char, _, _>(text::digits(10))
-        .collect::<String>()
-        .map(|s: String| zvariant::Value::I32(s.parse().unwrap()))
+        .then(text::digits(10))
+        .to_slice()
+        .map(|s: &str| zvariant::Value::I32(s.parse().unwrap()))
         .padded()
 }
-fn parser_u64() -> impl Parser<char, zvariant::Value<'static>, Error = Simple<char>> {
+fn parser_u64<'src>() -> impl Parser<'src, &'src str, zvariant::Value<'static>, Extra<'src>> + Clone
+{
     text::digits(10)
+        .to_slice()
         .labelled("u64")
-        .map(|s: String| zvariant::Value::U64(s.parse().unwrap()))
+        .map(|s: &str| zvariant::Value::U64(s.parse().unwrap()))
         .padded()
 }
-fn parser_i64() -> impl Parser<char, zvariant::Value<'static>, Error = Simple<char>> {
+fn parser_i64<'src>() -> impl Parser<'src, &'src str, zvariant::Value<'static>, Extra<'src>> + Clone
+{
     just('-')
         .or_not()
-        .chain::<char, _, _>(text::digits(10))
-        .collect::<String>()
+        .then(text::digits(10))
+        .to_slice()
         .labelled("i64")
-        .map(|s: String| zvariant::Value::I64(s.parse().unwrap()))
+        .map(|s: &str| zvariant::Value::I64(s.parse().unwrap()))
         .padded()
 }
-fn parser_f64() -> impl Parser<char, zvariant::Value<'static>, Error = Simple<char>> {
+fn parser_f64<'src>() -> impl Parser<'src, &'src str, zvariant::Value<'static>, Extra<'src>> + Clone
+{
     just('-')
         .or_not()
-        .chain::<char, _, _>(text::digits(10))
-        .chain::<char, _, _>(just('.').chain(text::digits(10)).or_not().flatten())
-        .collect::<String>()
+        .then(text::digits(10))
+        .then(just('.').then(text::digits(10)).or_not())
+        .to_slice()
         .labelled("f64")
-        .map(|s: String| zvariant::Value::F64(s.parse().unwrap()))
+        .map(|s: &str| zvariant::Value::F64(s.parse().unwrap()))
         .padded()
 }
-fn parser_bool() -> impl Parser<char, zvariant::Value<'static>, Error = Simple<char>> {
+fn parser_bool<'src>() -> impl Parser<'src, &'src str, zvariant::Value<'static>, Extra<'src>> + Clone
+{
     just("true")
         .map(|_| zvariant::Value::Bool(true))
         .or(just("false").map(|_| zvariant::Value::Bool(false)))
         .labelled("bool")
         .padded()
 }
-fn parser_string() -> impl Parser<char, zvariant::Value<'static>, Error = Simple<char>> {
-    let escape = just('\\').ignore_then(
-        just('\\')
-            .or(just('/'))
-            .or(just('"'))
-            .or(just('b').to('\x08'))
-            .or(just('f').to('\x0C'))
-            .or(just('n').to('\n'))
-            .or(just('r').to('\r'))
-            .or(just('t').to('\t'))
-            .or(just('u').ignore_then(
-                filter(|c: &char| c.is_ascii_hexdigit())
-                    .repeated()
-                    .exactly(4)
-                    .collect::<String>()
-                    .validate(|digits, span, emit| {
-                        char::from_u32(u32::from_str_radix(&digits, 16).unwrap()).unwrap_or_else(
-                            || {
-                                emit(Simple::custom(span, "invalid unicode character"));
-                                '\u{FFFD}' // unicode replacement character
-                            },
-                        )
-                    }),
-            )),
-    );
-    let string = just('"')
-        .ignore_then(filter(|c| *c != '\\' && *c != '"').or(escape).repeated())
+
+/// The quoted string literal that is shared by the string, signature and object path parsers.
+fn quoted_string<'src>() -> impl Parser<'src, &'src str, String, Extra<'src>> + Clone {
+    let escape = just('\\').ignore_then(choice((
+        just('\\'),
+        just('/'),
+        just('"'),
+        just('b').to('\x08'),
+        just('f').to('\x0C'),
+        just('n').to('\n'),
+        just('r').to('\r'),
+        just('t').to('\t'),
+        just('u').ignore_then(
+            any()
+                .filter(|c: &char| c.is_ascii_hexdigit())
+                .repeated()
+                .exactly(4)
+                .to_slice()
+                .validate(|digits: &str, extra, emitter| {
+                    char::from_u32(u32::from_str_radix(digits, 16).unwrap()).unwrap_or_else(|| {
+                        emitter.emit(Rich::custom(extra.span(), "invalid unicode character"));
+                        '\u{FFFD}' // unicode replacement character
+                    })
+                }),
+        ),
+    )));
+    just('"')
+        .ignore_then(none_of("\\\"").or(escape).repeated().collect::<String>())
         .then_ignore(just('"'))
-        .collect::<String>()
+}
+
+fn parser_string<'src>()
+-> impl Parser<'src, &'src str, zvariant::Value<'static>, Extra<'src>> + Clone {
+    quoted_string()
         .map(|s| zvariant::Value::Str(s.into()))
-        .labelled("string");
-    string
-        .recover_with(skip_then_retry_until(['}', ']']))
+        .labelled("string")
+        .recover_with(skip_then_retry_until(any().ignored(), one_of("}]").ignored()))
         .padded()
 }
-fn parser_signature() -> impl Parser<char, zvariant::Value<'static>, Error = Simple<char>> {
-    let escape = just('\\').ignore_then(
-        just('\\')
-            .or(just('/'))
-            .or(just('"'))
-            .or(just('b').to('\x08'))
-            .or(just('f').to('\x0C'))
-            .or(just('n').to('\n'))
-            .or(just('r').to('\r'))
-            .or(just('t').to('\t'))
-            .or(just('u').ignore_then(
-                filter(|c: &char| c.is_ascii_hexdigit())
-                    .repeated()
-                    .exactly(4)
-                    .collect::<String>()
-                    .validate(|digits, span, emit| {
-                        char::from_u32(u32::from_str_radix(&digits, 16).unwrap()).unwrap_or_else(
-                            || {
-                                emit(Simple::custom(span, "invalid unicode character"));
-                                '\u{FFFD}' // unicode replacement character
-                            },
-                        )
-                    }),
-            )),
-    );
-    let string = just('"')
-        .ignore_then(filter(|c| *c != '\\' && *c != '"').or(escape).repeated())
-        .then_ignore(just('"'))
-        .collect::<String>()
-        .try_map(|digits, span| {
+fn parser_signature<'src>()
+-> impl Parser<'src, &'src str, zvariant::Value<'static>, Extra<'src>> + Clone {
+    quoted_string()
+        .try_map(|digits: String, span| {
             if let Ok(signature) = Signature::from_str(digits.as_str()) {
                 Ok(zvariant::Value::Signature(signature))
             } else {
-                Err(Simple::custom(
+                Err(Rich::custom(
                     span,
                     "Could not parse signature from string value",
                 ))
             }
         })
-        .labelled("signature");
-
-    string
-        .recover_with(skip_then_retry_until(['}', ']']))
+        .labelled("signature")
+        .recover_with(skip_then_retry_until(any().ignored(), one_of("}]").ignored()))
         .padded()
 }
-fn parser_object_path() -> impl Parser<char, zvariant::Value<'static>, Error = Simple<char>> {
-    let escape = just('\\').ignore_then(
-        just('\\')
-            .or(just('/'))
-            .or(just('"'))
-            .or(just('b').to('\x08'))
-            .or(just('f').to('\x0C'))
-            .or(just('n').to('\n'))
-            .or(just('r').to('\r'))
-            .or(just('t').to('\t'))
-            .or(just('u').ignore_then(
-                filter(|c: &char| c.is_ascii_hexdigit())
-                    .repeated()
-                    .exactly(4)
-                    .collect::<String>()
-                    .validate(|digits, span, emit| {
-                        char::from_u32(u32::from_str_radix(&digits, 16).unwrap()).unwrap_or_else(
-                            || {
-                                emit(Simple::custom(span, "invalid unicode character"));
-                                '\u{FFFD}' // unicode replacement character
-                            },
-                        )
-                    }),
-            )),
-    );
-    let string = just('"')
-        .ignore_then(filter(|c| *c != '\\' && *c != '"').or(escape).repeated())
-        .then_ignore(just('"'))
-        .collect::<String>()
-        .try_map(|digits, span| {
+fn parser_object_path<'src>()
+-> impl Parser<'src, &'src str, zvariant::Value<'static>, Extra<'src>> + Clone {
+    quoted_string()
+        .try_map(|digits: String, span| {
             if let Ok(path) = ObjectPath::try_from(digits) {
                 Ok(zvariant::Value::ObjectPath(path))
             } else {
-                Err(Simple::custom(
+                Err(Rich::custom(
                     span,
                     "Could not parse object path from string value",
                 ))
             }
         })
-        .labelled("object_path");
-
-    string
-        .recover_with(skip_then_retry_until(['}', ']']))
+        .labelled("object_path")
+        .recover_with(skip_then_retry_until(any().ignored(), one_of("}]").ignored()))
         .padded()
 }
 
-fn parser_fd() -> impl Parser<char, zvariant::Value<'static>, Error = Simple<char>> {
-    empty().try_map(|(), span| Err(Simple::custom(span, "Cannot parse file descriptors")))
+fn parser_fd<'src>() -> impl Parser<'src, &'src str, zvariant::Value<'static>, Extra<'src>> + Clone {
+    empty().try_map(|(), span| Err(Rich::custom(span, "Cannot parse file descriptors")))
 }
 
 #[cfg(test)]
@@ -339,7 +305,7 @@ fn test_generic_signature(src: &'static str, signature: &'static str, value: zva
 
     let signature = Signature::from_str(signature).unwrap();
     println!("{}", signature);
-    let result = get_parser(signature).parse(src.trim());
+    let result = get_parser(signature).parse(src.trim()).into_result();
     dbg!(&result);
     dbg!(&value);
     assert_eq!(result, Ok(value));
@@ -386,7 +352,7 @@ fn test_signature() {
     );
     use std::str::FromStr;
     let signature = Signature::from_str("g").unwrap();
-    let result = get_parser(signature).parse("k"); // k is not a valid signature
+    let result = get_parser(signature).parse("k").into_result(); // k is not a valid signature
     assert!(result.is_err());
 }
 
@@ -410,10 +376,10 @@ fn test_object_path() {
     use std::str::FromStr;
 
     let signature = Signature::from_str("o").unwrap();
-    let result = get_parser(signature).parse("k"); // k is not a valid object path
+    let result = get_parser(signature).parse("k").into_result(); // k is not a valid object path
     assert!(result.is_err());
     let signature = Signature::from_str("o").unwrap();
-    let result = get_parser(signature).parse("//"); // // is not a valid object path
+    let result = get_parser(signature).parse("//").into_result(); // // is not a valid object path
     assert!(result.is_err());
 }
 
-- 
2.55.0

Reply via email to