use std::borrow::Cow;
use std::marker::PhantomData;
#[cfg(feature = "rand")]
use std::sync::Arc;
use serde::de::DeserializeSeed;
#[cfg(doc)]
use serde::de::{Deserializer, EnumAccess, MapAccess, Visitor};
use serde::Deserialize;
pub use crate::error::Error;
use crate::error::InternalError;
use crate::fallback::{DefaultFallbacks, Fallbacks};
pub use crate::random_trailer::RandomTrailer;
use crate::random_trailer::{InputPlusTrailer, NoopRandomTrailer, StringLike};
use crate::state::AttemptState;
use crate::unstable::{DefaultReporter, ExtraOptionsIsUnstable};
use crate::Source;
const DEFAULT_MAX_BACKTRACKS: Option<usize> = Some(10);
#[cfg(feature = "rand")]
const RANDOM_TAG_LEN: usize = 8;
#[derive(Clone, Debug)]
pub struct Options<Extra: ExtraOptions = DefaultExtraOptions> {
#[cfg(feature = "rand")]
random_tag: Option<Arc<str>>,
pub(crate) max_n_backtracks: Option<usize>,
pub(crate) behavior: UnstableCustomBehavior,
pub(crate) extra: Extra,
}
impl Options {
#[cfg(all(feature = "rand", feature = "serde_json"))]
pub fn new_json() -> Options<JsonExtraOptions> {
let base = Options {
..Options::new_nonce()
};
base.set_random_trailer(crate::random_trailer::json::JsonRandomTrailer)
}
#[cfg(all(feature = "rand", feature = "serde_yaml"))]
pub fn new_yaml() -> Options<YamlExtraOptions> {
let base = Options {
..Options::new_nonce()
};
base.set_random_trailer(crate::random_trailer::yaml::YamlRandomTrailer)
}
#[cfg(feature = "rand")]
pub fn new_nonce() -> Options<DefaultExtraOptions> {
use rand::distributions::{Alphanumeric, DistString};
use rand::thread_rng;
let tag = Alphanumeric.sample_string(&mut thread_rng(), RANDOM_TAG_LEN);
Options {
random_tag: Some(tag.into()),
..Options::new_no_nonce()
}
}
pub fn new_no_nonce() -> Options<DefaultExtraOptions> {
Options {
#[cfg(feature = "rand")]
random_tag: None,
max_n_backtracks: DEFAULT_MAX_BACKTRACKS,
behavior: UnstableCustomBehavior::default(),
extra: DefaultExtraOptions::default(),
}
}
}
impl<Extra: ExtraOptions> Options<Extra> {
pub fn with_max_n_backtracks(mut self, max_n_backtracks: Option<usize>) -> Self {
self.max_n_backtracks = max_n_backtracks;
self
}
#[cfg(all(feature = "rand", feature = "serde_json"))]
pub fn deserialize_from_json_str<T>(self, json: Cow<str>) -> Result<T, Error<serde_json::Error>>
where
T: for<'de> serde::de::Deserialize<'de>,
{
let prepared = self.prepare_str_for_borrowed_deserialization(json);
self.deserialize_from_json_str_borrowed(&prepared)
}
#[cfg(all(feature = "rand", feature = "serde_json"))]
pub fn deserialize_from_json_slice<T>(
self,
json: Cow<[u8]>,
) -> Result<T, Error<serde_json::Error>>
where
T: for<'de> serde::de::Deserialize<'de>,
{
let prepared = self.prepare_slice_for_borrowed_deserialization(json);
self.deserialize_from_json_slice_borrowed(&prepared)
}
#[cfg(all(feature = "rand", feature = "serde_yaml"))]
pub fn deserialize_from_yaml_str<T>(self, yaml: Cow<str>) -> Result<T, Error<serde_yaml::Error>>
where
T: for<'de> serde::de::Deserialize<'de>,
{
let prepared = self.prepare_str_for_borrowed_deserialization(yaml);
self.deserialize_from_yaml_str_borrowed(&prepared)
}
#[cfg(all(feature = "rand", feature = "serde_yaml"))]
pub fn deserialize_from_yaml_slice<T>(
self,
yaml: Cow<[u8]>,
) -> Result<T, Error<serde_yaml::Error>>
where
T: for<'de> serde::de::Deserialize<'de>,
{
let prepared = self.prepare_slice_for_borrowed_deserialization(yaml);
self.deserialize_from_yaml_slice_borrowed(&prepared)
}
#[cfg(feature = "serde_json")]
pub fn deserialize_from_json_slice_plain_return_borrowed<'de, T>(
self,
json: &'de impl AsRef<[u8]>,
) -> Result<T, Error<serde_json::Error>>
where
T: serde::de::Deserialize<'de>,
{
self.deserialize_source(crate::source::JsonBytes(json.as_ref()))
}
#[cfg(feature = "serde_json")]
pub fn deserialize_from_json_str_borrowed<'de, T>(
self,
InputPlusTrailer(prepared_json): &'de InputPlusTrailer<impl AsRef<str>>,
) -> Result<T, Error<serde_json::Error>>
where
T: serde::de::Deserialize<'de>,
{
self.deserialize_source(crate::source::JsonStr(prepared_json.as_ref()))
}
#[cfg(feature = "serde_json")]
pub fn deserialize_from_json_slice_borrowed<'de, T>(
self,
InputPlusTrailer(prepared_json): &'de InputPlusTrailer<impl AsRef<[u8]>>,
) -> Result<T, Error<serde_json::Error>>
where
T: serde::de::Deserialize<'de>,
{
self.deserialize_source(crate::source::JsonBytes(prepared_json.as_ref()))
}
#[cfg(feature = "serde_yaml")]
pub fn deserialize_from_yaml_str_borrowed<'de, T>(
self,
InputPlusTrailer(prepared_yaml): &'de InputPlusTrailer<impl AsRef<str>>,
) -> Result<T, Error<serde_yaml::Error>>
where
T: serde::de::Deserialize<'de>,
{
self.deserialize_source(crate::source::YamlStr(prepared_yaml.as_ref()))
}
#[cfg(feature = "serde_yaml")]
pub fn deserialize_from_yaml_slice_borrowed<'de, T>(
self,
InputPlusTrailer(prepared_yaml): &'de InputPlusTrailer<impl AsRef<[u8]>>,
) -> Result<T, Error<serde_yaml::Error>>
where
T: serde::de::Deserialize<'de>,
{
self.deserialize_source(crate::source::YamlBytes(prepared_yaml.as_ref()))
}
#[cfg(feature = "rand")]
pub fn prepare_str_for_borrowed_deserialization<'a>(
&self,
mut input: Cow<'a, str>,
) -> InputPlusTrailer<Cow<'a, str>> {
use RandomTrailer as _;
#[cfg(feature = "rand")]
if let Some(tag) = self.random_tag.as_ref() {
self.extra
.get_random_trailer()
.prepare_string_with_tag(Cow::to_mut(&mut input), tag);
}
InputPlusTrailer(input)
}
#[cfg(feature = "rand")]
pub fn prepare_slice_for_borrowed_deserialization<'a>(
&self,
mut input: Cow<'a, [u8]>,
) -> InputPlusTrailer<Cow<'a, [u8]>> {
use RandomTrailer as _;
#[cfg(feature = "rand")]
if let Some(tag) = self.random_tag.as_ref() {
self.extra
.get_random_trailer()
.prepare_vec_with_tag(Cow::to_mut(&mut input), tag);
}
InputPlusTrailer(input)
}
#[cfg(feature = "unstable")]
pub fn custom_behavior(self, behavior: UnstableCustomBehavior) -> Self {
Options { behavior, ..self }
}
#[cfg(feature = "rand")]
pub fn disable_random_tag(mut self) -> Self {
self.random_tag = None;
self
}
}
#[cfg(feature = "rand")]
impl<R, F, RT> Options<ExtraOptionsStruct<R, F, RT>>
where
R: MakeReporter,
F: MakeFallbackProvider,
RT: RandomTrailer,
{
pub fn set_random_trailer<RT2>(
self,
random_trailer: RT2,
) -> Options<ExtraOptionsStruct<R, F, RT2>>
where
RT2: RandomTrailer,
{
let Options {
random_tag,
max_n_backtracks,
behavior,
extra,
} = self;
Options {
random_tag,
max_n_backtracks,
behavior,
extra: ExtraOptionsStruct {
make_reporter: extra.make_reporter,
make_fallback_provider: extra.make_fallback_provider,
random_trailer,
},
}
}
#[cfg(feature = "unstable")]
pub fn set_reporter<R2>(
self,
reporter: R2,
) -> Options<ExtraOptionsStruct<CustomReporter<R2>, F, RT>>
where
R2: crate::reporter::Reporter + Clone,
{
let Options {
random_tag,
max_n_backtracks,
behavior,
extra,
} = self;
Options {
random_tag,
max_n_backtracks,
behavior,
extra: ExtraOptionsStruct {
make_reporter: CustomReporter(reporter),
make_fallback_provider: extra.make_fallback_provider,
random_trailer: extra.random_trailer,
},
}
}
#[doc(hidden)]
#[cfg(feature = "unstable")]
pub fn set_fallback_provider<F2>(
self,
fallback_provider: F2,
) -> Options<ExtraOptionsStruct<R, CustomFallbackProvider<F2>, RT>>
where
F2: Fallbacks + Clone,
{
let Options {
random_tag,
max_n_backtracks,
behavior,
extra,
} = self;
Options {
random_tag,
max_n_backtracks,
behavior,
extra: ExtraOptionsStruct {
make_reporter: extra.make_reporter,
make_fallback_provider: CustomFallbackProvider(fallback_provider),
random_trailer: extra.random_trailer,
},
}
}
}
impl<Extra: ExtraOptions> Options<Extra> {
#[must_use]
pub(crate) fn remove_tag_from_stringlike(&self, stringy: &mut impl StringLike) -> bool {
#![cfg_attr(not(feature = "rand"), allow(unused_variables))]
#[cfg(feature = "rand")]
{
if let Some(tag) = self.random_tag.as_ref() {
return self.extra.get_random_trailer().remove_trailer(stringy, tag);
}
}
false
}
}
#[doc(hidden)]
#[allow(private_bounds)]
pub trait ExtraOptions: ExtraOptionsIsUnstable {
fn make_reporter(&mut self) -> Self::Reporter;
type Reporter: crate::reporter::Reporter;
fn make_fallback_provider(
&mut self,
behavior: &UnstableCustomBehavior,
) -> Self::FallbackProvider;
type FallbackProvider: Fallbacks;
fn get_random_trailer(&self) -> &Self::RandomTrailer;
type RandomTrailer: RandomTrailer;
}
pub type DefaultExtraOptions =
ExtraOptionsStruct<MakeDefaultReporter, MakeDefaultFallbacks, NoopRandomTrailer>;
#[cfg(all(feature = "rand", feature = "serde_json"))]
pub type JsonExtraOptions = ExtraOptionsStruct<
MakeDefaultReporter,
MakeDefaultFallbacks,
crate::random_trailer::json::JsonRandomTrailer,
>;
#[cfg(all(feature = "rand", feature = "serde_yaml"))]
pub type YamlExtraOptions = ExtraOptionsStruct<
MakeDefaultReporter,
MakeDefaultFallbacks,
crate::random_trailer::yaml::YamlRandomTrailer,
>;
#[doc(hidden)]
#[derive(Debug, Clone, Default)]
pub struct ExtraOptionsStruct<MakeReporter, MakeFallbackProvider, RandomTrailer> {
pub(crate) make_reporter: MakeReporter,
pub(crate) make_fallback_provider: MakeFallbackProvider,
pub(crate) random_trailer: RandomTrailer,
}
#[doc(hidden)]
pub trait MakeReporter {
type Reporter: crate::reporter::Reporter;
fn make_reporter(&mut self) -> Self::Reporter;
}
#[doc(hidden)]
pub trait MakeFallbackProvider {
type FallbackProvider: Fallbacks;
fn make_fallback_provider(
&mut self,
behavior: &UnstableCustomBehavior,
) -> Self::FallbackProvider;
}
#[doc(hidden)]
#[derive(Debug, Clone, Default)]
pub struct MakeDefaultReporter;
impl MakeReporter for MakeDefaultReporter {
type Reporter = DefaultReporter;
fn make_reporter(&mut self) -> Self::Reporter {
DefaultReporter::new()
}
}
#[doc(hidden)]
#[derive(Debug, Clone, Default)]
pub struct MakeDefaultFallbacks;
impl MakeFallbackProvider for MakeDefaultFallbacks {
type FallbackProvider = DefaultFallbacks;
fn make_fallback_provider(
&mut self,
behavior: &UnstableCustomBehavior,
) -> Self::FallbackProvider {
DefaultFallbacks {
behavior: behavior.clone(),
}
}
}
#[derive(Debug, Clone)]
pub struct CustomReporter<T>(T);
impl<T: crate::reporter::Reporter + Clone> MakeReporter for CustomReporter<T> {
type Reporter = T;
fn make_reporter(&mut self) -> Self::Reporter {
self.0.clone()
}
}
#[derive(Debug, Clone)]
pub struct CustomFallbackProvider<T>(T);
impl<T: Fallbacks + Clone> MakeFallbackProvider for CustomFallbackProvider<T> {
type FallbackProvider = T;
fn make_fallback_provider(
&mut self,
_behavior: &UnstableCustomBehavior,
) -> Self::FallbackProvider {
self.0.clone()
}
}
impl<R, F, RT> ExtraOptions for ExtraOptionsStruct<R, F, RT>
where
R: MakeReporter,
F: MakeFallbackProvider,
RT: RandomTrailer,
{
fn make_reporter(&mut self) -> Self::Reporter {
self.make_reporter.make_reporter()
}
type Reporter = R::Reporter;
fn make_fallback_provider(
&mut self,
behavior: &UnstableCustomBehavior,
) -> Self::FallbackProvider {
self.make_fallback_provider.make_fallback_provider(behavior)
}
type FallbackProvider = F::FallbackProvider;
fn get_random_trailer(&self) -> &RT {
&self.random_trailer
}
type RandomTrailer = RT;
}
impl<R, F, RT> ExtraOptionsIsUnstable for ExtraOptionsStruct<R, F, RT> {}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct UnstableCustomBehavior {
pub tolerate_deserializer_fail_after_visit_success: bool,
pub fallback_any_as_none: bool,
pub fallback_ignored_any_as_none: bool,
pub fallback_default_bool: Option<bool>,
pub fallback_int_zero: bool,
pub fallback_default_float: Option<f32>,
pub fallback_default_char: Option<char>,
pub fallback_default_str: Option<&'static str>,
pub fallback_bytes_empty: bool,
pub fallback_none: bool,
pub fallback_none_at_mandatory: bool,
pub fallback_unit: bool,
pub fallback_unit_at_mandatory: bool,
pub fallback_unit_struct: bool,
pub fallback_unit_struct_at_mandatory: bool,
pub fallback_seq_empty: bool,
pub fallback_seq_empty_at_root: bool,
pub backtrack_seq_empty_for_value: bool,
pub fallback_seq_skip_item: bool,
pub backtrack_seq_skip_item: bool,
pub fallback_tuple_empty: bool,
pub fallback_tuple_skip_item: bool,
pub backtrack_tuple_skip_item: bool,
pub fallback_tuple_struct_empty: bool,
pub fallback_tuple_struct_skip_item: bool,
pub backtrack_tuple_struct_skip_item: bool,
pub fallback_map_empty: bool,
pub fallback_map_empty_at_root: bool,
pub backtrack_map_empty_for_value: bool,
pub fallback_map_skip_item: bool,
pub backtrack_map_skip_item: bool,
pub fallback_struct_empty: bool,
pub fallback_struct_empty_at_root: bool,
pub backtrack_struct_empty_for_value: bool,
pub fallback_struct_skip_field: bool,
pub backtrack_struct_skip_field: bool,
pub fallback_unit_variant: bool,
pub fallback_other_skip_item: bool,
pub backtrack_other_skip_item: bool,
pub allow_incomplete_string_in_key_or_variant: bool,
}
impl Default for UnstableCustomBehavior {
fn default() -> Self {
Self {
tolerate_deserializer_fail_after_visit_success: true,
fallback_any_as_none: false,
fallback_ignored_any_as_none: false,
fallback_default_bool: None,
fallback_int_zero: false,
fallback_default_float: None,
fallback_default_char: None,
fallback_default_str: None,
fallback_bytes_empty: false,
fallback_none: true,
fallback_none_at_mandatory: true,
fallback_unit: false,
fallback_unit_at_mandatory: true,
fallback_unit_struct: false,
fallback_unit_struct_at_mandatory: true,
fallback_seq_empty: false,
fallback_seq_empty_at_root: true,
backtrack_seq_empty_for_value: true,
fallback_seq_skip_item: false,
backtrack_seq_skip_item: true,
fallback_tuple_empty: false,
fallback_tuple_skip_item: false,
backtrack_tuple_skip_item: true,
fallback_tuple_struct_empty: false,
fallback_tuple_struct_skip_item: false,
backtrack_tuple_struct_skip_item: true,
fallback_map_empty: false,
fallback_map_empty_at_root: true,
backtrack_map_empty_for_value: true,
fallback_map_skip_item: false,
backtrack_map_skip_item: true,
fallback_struct_empty: false,
fallback_struct_empty_at_root: true,
backtrack_struct_empty_for_value: true,
fallback_struct_skip_field: true,
backtrack_struct_skip_field: true,
fallback_unit_variant: true,
fallback_other_skip_item: false,
backtrack_other_skip_item: true,
allow_incomplete_string_in_key_or_variant: false,
}
}
}
impl UnstableCustomBehavior {
pub fn no_fallbacks(mut self) -> Self {
let Self {
tolerate_deserializer_fail_after_visit_success: _,
fallback_any_as_none,
fallback_ignored_any_as_none,
fallback_default_bool,
fallback_int_zero,
fallback_default_float,
fallback_default_char,
fallback_default_str,
fallback_bytes_empty,
fallback_none,
fallback_none_at_mandatory,
fallback_unit,
fallback_unit_at_mandatory,
fallback_unit_struct,
fallback_unit_struct_at_mandatory,
fallback_seq_empty,
fallback_seq_empty_at_root,
backtrack_seq_empty_for_value: _,
fallback_seq_skip_item,
backtrack_seq_skip_item: _,
fallback_tuple_empty,
fallback_tuple_skip_item,
backtrack_tuple_skip_item: _,
fallback_tuple_struct_empty,
fallback_tuple_struct_skip_item: fallback_tuple_struct_skip_field,
backtrack_tuple_struct_skip_item: _,
fallback_map_empty,
fallback_map_empty_at_root,
backtrack_map_empty_for_value: _,
fallback_map_skip_item,
backtrack_map_skip_item: _,
fallback_struct_empty,
fallback_struct_empty_at_root,
backtrack_struct_empty_for_value: _,
fallback_struct_skip_field,
backtrack_struct_skip_field: _,
fallback_unit_variant,
fallback_other_skip_item,
backtrack_other_skip_item: _,
allow_incomplete_string_in_key_or_variant: allow_incomplete_string_in_key,
} = &mut self;
*fallback_any_as_none = false;
*fallback_ignored_any_as_none = false;
*fallback_default_bool = None;
*fallback_int_zero = false;
*fallback_default_float = None;
*fallback_default_char = None;
*fallback_default_str = None;
*fallback_bytes_empty = false;
*fallback_none = false;
*fallback_none_at_mandatory = false;
*fallback_unit = false;
*fallback_unit_at_mandatory = false;
*fallback_unit_struct = false;
*fallback_unit_struct_at_mandatory = false;
*fallback_seq_empty = false;
*fallback_seq_empty_at_root = false;
*fallback_seq_skip_item = false;
*fallback_tuple_empty = false;
*fallback_tuple_skip_item = false;
*fallback_tuple_struct_empty = false;
*fallback_tuple_struct_skip_field = false;
*fallback_map_empty = false;
*fallback_map_empty_at_root = false;
*fallback_map_skip_item = false;
*fallback_struct_empty = false;
*fallback_struct_empty_at_root = false;
*fallback_struct_skip_field = false;
*fallback_unit_variant = false;
*fallback_other_skip_item = false;
*allow_incomplete_string_in_key = false;
self
}
pub fn strict() -> Self {
Self {
tolerate_deserializer_fail_after_visit_success: false,
fallback_any_as_none: false,
fallback_ignored_any_as_none: false,
fallback_default_bool: None,
fallback_int_zero: false,
fallback_default_float: None,
fallback_default_char: None,
fallback_default_str: None,
fallback_bytes_empty: false,
fallback_none: false,
fallback_none_at_mandatory: false,
fallback_unit: false,
fallback_unit_at_mandatory: false,
fallback_unit_struct: false,
fallback_unit_struct_at_mandatory: false,
fallback_seq_empty: false,
fallback_seq_empty_at_root: false,
backtrack_seq_empty_for_value: false,
fallback_seq_skip_item: false,
backtrack_seq_skip_item: false,
fallback_tuple_empty: false,
fallback_tuple_skip_item: false,
backtrack_tuple_skip_item: false,
fallback_tuple_struct_skip_item: false,
backtrack_tuple_struct_skip_item: false,
fallback_tuple_struct_empty: false,
fallback_map_empty: false,
fallback_map_empty_at_root: false,
backtrack_map_empty_for_value: false,
fallback_map_skip_item: false,
backtrack_map_skip_item: false,
fallback_struct_empty: false,
fallback_struct_empty_at_root: false,
backtrack_struct_empty_for_value: false,
fallback_struct_skip_field: false,
backtrack_struct_skip_field: false,
fallback_unit_variant: false,
fallback_other_skip_item: false,
backtrack_other_skip_item: false,
allow_incomplete_string_in_key_or_variant: false,
}
}
pub fn lenient() -> Self {
Self {
tolerate_deserializer_fail_after_visit_success: true,
fallback_any_as_none: true,
fallback_ignored_any_as_none: true,
fallback_default_bool: Some(false),
fallback_int_zero: true,
fallback_default_float: Some(0.0),
fallback_default_char: Some('\0'),
fallback_default_str: Some(""),
fallback_bytes_empty: true,
fallback_none: true,
fallback_none_at_mandatory: true,
fallback_unit: true,
fallback_unit_at_mandatory: true,
fallback_unit_struct: true,
fallback_unit_struct_at_mandatory: true,
fallback_seq_empty: true,
fallback_seq_empty_at_root: true,
backtrack_seq_empty_for_value: true,
fallback_seq_skip_item: true,
backtrack_seq_skip_item: true,
fallback_tuple_empty: true,
fallback_tuple_skip_item: true,
backtrack_tuple_skip_item: true,
fallback_tuple_struct_empty: true,
fallback_tuple_struct_skip_item: true,
backtrack_tuple_struct_skip_item: true,
fallback_map_empty: true,
fallback_map_empty_at_root: true,
backtrack_map_empty_for_value: true,
fallback_map_skip_item: true,
backtrack_map_skip_item: true,
fallback_struct_empty: true,
fallback_struct_empty_at_root: true,
backtrack_struct_empty_for_value: true,
fallback_struct_skip_field: true,
backtrack_struct_skip_field: true,
fallback_unit_variant: true,
fallback_other_skip_item: true,
backtrack_other_skip_item: true,
allow_incomplete_string_in_key_or_variant: true,
}
}
}
impl<Extra: ExtraOptions> Options<Extra> {
pub fn deserialize_source<'de, T, S>(self, source: S) -> Result<T, Error<S::Error>>
where
T: Deserialize<'de>,
S: Source<'de>,
{
self.deserialize_seed(PhantomData, source)
}
pub fn deserialize_seed<'de, T, S>(
self,
seed: T,
mut source: S,
) -> Result<T::Value, Error<S::Error>>
where
T: DeserializeSeed<'de> + Clone,
S: Source<'de>,
{
let mut state = self.build();
let mut attempt = AttemptState::initial(&state);
while {
let max_n_backtracks = state.config.max_n_backtracks;
max_n_backtracks
.map(|max| state.n_backtracks <= max)
.unwrap_or(true)
} {
let mut inner_deserializer_storage = Some(source.recreate_deserializer_storage());
let inner_deserializer =
S::use_deserializer_from_storage(&mut inner_deserializer_storage);
let deserializer = crate::attempt::Deserializer {
global: &mut state,
attempt: &mut attempt,
is_at_root: true,
is_for_key_or_variant: false,
is_for_map_value: false,
inner: inner_deserializer,
};
match seed.clone().deserialize(deserializer) {
Ok(value) => return Ok(value),
Err(error) => {
debug!(attempt = state.n_backtracks, %error, "attempt failed");
}
}
attempt = match attempt.next_attempt_state_after_failure()? {
Some(new_attempt) => new_attempt,
None => {
return Err(InternalError::NoPotentialBacktrackPoint {
after_backtracks: state.n_backtracks,
}
.into());
}
};
state.n_backtracks += 1;
}
Err(InternalError::TooManyBacktracks.into())
}
}