Skip to main content

deser_core/
open_enum.rs

1//! Support for open enums (`#[deser::open_enum]`).
2//!
3//! An open enum is a trait whose implementations are its variants.  The
4//! trait objects (`Box<dyn Trait>` and `Arc<dyn Trait>`) are serialized and
5//! deserialized like enums whose variants are the types that implement the
6//! trait with `#[deser::variant]`, which can be in any crate.
7//!
8//! Serializing only needs the value: the variant knows its name.  To
9//! deserialize, the variants are looked up in the [`OpenEnums`] registry
10//! of the context, where they are registered explicitly.  The macros only
11//! generate the names of the variants, the conversion into the trait object
12//! and short forwarding functions, everything else is here (generic over the
13//! trait object and the variant).
14use alloc::borrow::Cow;
15use alloc::boxed::Box;
16use alloc::collections::BTreeMap;
17use alloc::string::ToString;
18use alloc::sync::Arc;
19use alloc::vec::Vec;
20use core::any::{Any, TypeId, type_name};
21use core::fmt;
22use core::marker::PhantomData;
23
24use crate::State;
25use crate::Text;
26use crate::de::enums::{
27    AdjacentlyTaggedSink, ArenaVariant, EnumKey, ExternallyTaggedSink, InternallyTaggedSink, Tag,
28    UntaggedTry, ValueVariant, VariantBuilder, VariantNames, Variants, no_matching_variant,
29    untagged_handle_with,
30};
31use crate::de::mapped::mapped;
32use crate::de::{Deserialize, DeserializeOwned, OwnedSink, Sink, SinkHandle};
33use crate::error::{Error, ErrorKind};
34use crate::event::{Atom, ContainerShape};
35use crate::ser::enums::{EntrySer, FieldsSer, TaggedNewtype};
36use crate::ser::{
37    Describe, Emit, Serialize, SerializeHandle, SerializeRef, Variant, VariantKind, VariantRepr,
38};
39
40/// A trait whose trait objects are open enums.
41///
42/// This is implemented for the trait object of a trait marked with
43/// [`#[deser::open_enum]`](../deser/attr.open_enum.html), the
44/// implementations of the trait marked with `#[deser::variant]` are its
45/// variants (see [`OpenVariant`]).  Its members are not public API.
46pub trait OpenEnum: Send + Sync + 'static {
47    /// The configuration of the open enum.
48    #[doc(hidden)]
49    const INFO: &'static OpenEnumInfo;
50
51    /// Returns the variant of a value.
52    #[doc(hidden)]
53    fn __private_variant(value: &Self) -> VariantValue<'_>;
54}
55
56/// A type that is a variant of the open enum `O` (a trait object).
57///
58/// This is implemented by `#[deser::variant]` for the types that implement
59/// the trait.  Variants are registered in an [`OpenEnums`] registry to be
60/// deserialized.  Its members are not public API.
61pub trait OpenVariant<O: ?Sized + OpenEnum>: Serialize + DeserializeOwned + 'static {
62    /// The names of the variant.
63    #[doc(hidden)]
64    const ENTRY: &'static VariantEntry;
65
66    /// Converts the value into the trait object.
67    ///
68    /// This is the only part of the deserialization that depends on the
69    /// concrete type and the trait (the unsizing coercion), everything else
70    /// is generic.
71    #[doc(hidden)]
72    fn __private_into_box(self) -> Box<O>;
73}
74
75/// Creates the builder of a variant.
76///
77/// The marker argument implies `'de: 'a` so that functions which are
78/// generic over both lifetimes can be converted to this type.
79type MakeVariant<O> =
80    for<'a, 'de> fn(&mut State, PhantomData<&'a &'de ()>) -> ArenaVariant<'a, 'de, Box<O>>;
81
82/// Creates the builder of the variant `T` of the open enum `O`.
83fn make_variant<'a, 'de, O: ?Sized + OpenEnum, T: OpenVariant<O>>(
84    state: &mut State,
85    _: PhantomData<&'a &'de ()>,
86) -> ArenaVariant<'a, 'de, Box<O>> {
87    ValueVariant::arena(T::__private_into_box, state)
88}
89
90/// Tries the variant of an untagged open enum.
91type TryVariant<O> = for<'t, 'de> fn(&mut UntaggedTry<'t, 'de, Box<O>>);
92
93/// Tries the variant `T` of the untagged open enum `O`.
94fn try_variant<O: ?Sized + OpenEnum, T: OpenVariant<O>>(attempt: &mut UntaggedTry<'_, '_, Box<O>>) {
95    attempt.variant::<T>(T::__private_into_box);
96}
97
98/// The number of name styles of [`VariantEntry::styled`].
99const STYLES: usize = 8;
100
101/// The names of a variant of an open enum (generated by
102/// `#[deser::variant]`).
103#[doc(hidden)]
104pub struct VariantEntry {
105    /// The name of the type in all styles of `rename_all`.
106    ///
107    /// The first one is the name of the type unchanged (the default), the
108    /// order of the others is the one of `RenameAll` in deser-derive.
109    pub styled: &'static [&'static str; STYLES],
110    /// The name given with `rename`.
111    pub rename: Option<Tag<'static>>,
112    /// The aliases given with `alias`.
113    pub aliases: &'static [Tag<'static>],
114}
115
116/// How the variants of an open enum are represented.
117#[doc(hidden)]
118#[derive(Clone, Copy)]
119pub enum OpenRepr {
120    /// Externally tagged (a map with the name as key).
121    External,
122    /// Internally tagged (the name in a field of the content).
123    Internal {
124        /// The key of the tag.
125        tag: EnumKey,
126    },
127    /// Adjacently tagged (the name and the content in two fields).
128    Adjacent {
129        /// The key of the tag.
130        tag: EnumKey,
131        /// The key of the content.
132        content: EnumKey,
133        /// If keys other than the tag and the content are errors.
134        deny_unknown_fields: bool,
135    },
136    /// Untagged (the content alone, the variants are tried in the order
137    /// they are registered).
138    Untagged,
139}
140
141/// The configuration of an open enum (from `#[deser::open_enum]`).
142#[doc(hidden)]
143pub struct OpenEnumInfo {
144    /// The name of the trait (for errors and descriptions).
145    pub name: &'static str,
146    /// How the variants are represented.
147    pub repr: OpenRepr,
148    /// The style of the names of the variants (an index into
149    /// [`VariantEntry::styled`]).
150    pub rename_all: usize,
151    /// The styles in which the names of variants are accepted as well
152    /// (`alias_all`).
153    pub alias_all: &'static [usize],
154}
155
156/// The variant of a value and the value to serialize as its content.
157///
158/// This is returned by the hidden method that `#[deser::open_enum]` adds to
159/// the trait (and `#[deser::variant]` implements).
160#[doc(hidden)]
161pub struct VariantValue<'a> {
162    entry: &'static VariantEntry,
163    content: SerializeRef<'a>,
164}
165
166impl<'a> VariantValue<'a> {
167    /// Creates the variant of a value.
168    #[inline]
169    pub fn new<T: Serialize>(entry: &'static VariantEntry, value: &'a T) -> VariantValue<'a> {
170        VariantValue {
171            entry,
172            content: SerializeRef::new(value),
173        }
174    }
175}
176
177/// The names of a variant depend on the configuration of the open enum
178/// (`info`, for `rename_all` and `alias_all`).
179impl VariantEntry {
180    /// Returns the name of the variant.
181    #[inline]
182    fn name(&'static self, info: &OpenEnumInfo) -> Tag<'static> {
183        match self.rename {
184            Some(name) => name,
185            None => Tag::Str(self.styled[info.rename_all]),
186        }
187    }
188
189    /// Returns a handle to the name of the variant.
190    ///
191    /// The name is borrowed from the static entry.
192    #[inline]
193    fn name_handle(&'static self, info: &OpenEnumInfo) -> SerializeHandle<'static> {
194        match self.rename {
195            Some(Tag::Str(ref name)) => SerializeHandle::to(name),
196            Some(ref name) => SerializeHandle::to(name),
197            None => SerializeHandle::to(&self.styled[info.rename_all]),
198        }
199    }
200
201    /// Returns the name of the variant as string (if it is one).
202    #[inline]
203    fn name_str(&'static self, info: &OpenEnumInfo) -> Option<&'static str> {
204        match self.name(info) {
205            Tag::Str(name) => Some(name),
206            _ => None,
207        }
208    }
209
210    /// Returns the names the variant is deserialized from.
211    fn tags(&'static self, info: &OpenEnumInfo) -> Vec<Tag<'static>> {
212        let name = self.name(info);
213        let mut tags = Vec::from([name]);
214        let mut push = |tag: Tag<'static>| {
215            if !tags.contains(&tag) {
216                tags.push(tag);
217            }
218        };
219        for &alias in self.aliases {
220            push(alias);
221        }
222        // the names in the styles of `alias_all`
223        for &style in info.alias_all {
224            push(Tag::Str(self.styled[style]));
225        }
226        tags
227    }
228
229    /// Returns the name for messages.
230    fn display_name(&self, info: &OpenEnumInfo) -> Cow<'static, str> {
231        match self.rename {
232            Some(tag) => tag_display(tag),
233            None => Cow::Borrowed(self.styled[info.rename_all]),
234        }
235    }
236}
237
238/// Returns a tag for messages.
239fn tag_display(tag: Tag<'static>) -> Cow<'static, str> {
240    match tag {
241        Tag::Str(name) => Cow::Borrowed(name),
242        Tag::U64(value) => Cow::Owned(value.to_string()),
243        Tag::I64(value) => Cow::Owned(value.to_string()),
244        Tag::Bool(value) => Cow::Borrowed(if value { "true" } else { "false" }),
245    }
246}
247
248/// The registry of the variants of open enums.
249///
250/// Open enums (see [`#[deser::open_enum]`](../deser/attr.open_enum.html))
251/// are deserialized with the variants registered here, the registry is
252/// given to the deserialization in the [`Context`](crate::Context).  A
253/// registry holds the variants of any number of open enums.  Types are
254/// variants of an open enum if they implement the trait with
255/// `#[deser::variant]`, which [`register`](Self::register) checks:
256///
257/// ```
258/// use deser::{Context, Deserialize, OpenEnums, Serialize};
259///
260/// #[deser::open_enum(tag = "type")]
261/// pub trait Shape: Send + Sync {}
262///
263/// #[derive(Serialize, Deserialize)]
264/// pub struct Circle {
265///     radius: u32,
266/// }
267///
268/// #[deser::variant]
269/// impl Shape for Circle {}
270///
271/// let mut variants = OpenEnums::new();
272/// variants.register::<dyn Shape, Circle>().unwrap();
273/// let context = Context::with(variants);
274/// ```
275///
276/// Libraries that provide variants usually provide a function that
277/// registers them.  Only the registered variants can be deserialized,
278/// which is also a way to restrict what input can create.  Serializing
279/// does not need the registry.  The variants of untagged open enums are
280/// tried in the order they are registered.
281#[derive(Default)]
282pub struct OpenEnums {
283    enums: BTreeMap<TypeId, Registered>,
284}
285
286/// The variants of an open enum.
287struct Registered {
288    // the name of the open enum
289    name: &'static str,
290    // the names of the variants (sorted, for errors and `Debug`)
291    names: Vec<Cow<'static, str>>,
292    // the `Table<O>` of the open enum
293    table: Box<dyn Any + Send + Sync>,
294}
295
296/// The variants of an open enum by their tags.
297struct Table<O: ?Sized + 'static> {
298    // the registered variants (in the order they were registered, which is
299    // the order in which the variants of untagged open enums are tried)
300    variants: Vec<Registration<O>>,
301    // the tags with the index of their variant (sorted by tag, empty for
302    // untagged open enums)
303    tags: Vec<(Tag<'static>, usize)>,
304}
305
306/// A registered variant of an open enum.
307struct Registration<O: ?Sized + 'static> {
308    // the type of the variant
309    ty: TypeId,
310    // the name of the type in Rust (for errors)
311    type_name: &'static str,
312    // creates the builder of the variant
313    make: MakeVariant<O>,
314    // tries the variant (for untagged open enums)
315    try_untagged: TryVariant<O>,
316}
317
318impl OpenEnums {
319    /// Creates an empty registry.
320    pub fn new() -> OpenEnums {
321        OpenEnums::default()
322    }
323
324    /// Registers the type `T` as variant of the open enum `O`.
325    ///
326    /// `O` is the trait object (`dyn Trait`).  Registering a type again
327    /// does nothing.  Fails if the name of the variant (or one of its
328    /// aliases) is the one of another variant (with
329    /// [`ErrorKind::Configuration`]), unless the open enum is untagged
330    /// (where the names are only used in descriptions and errors).
331    pub fn register<O: ?Sized + OpenEnum, T: OpenVariant<O>>(
332        &mut self,
333    ) -> Result<&mut OpenEnums, Error> {
334        let entry = T::ENTRY;
335        let info = O::INFO;
336        let ty = TypeId::of::<T>();
337        let registered = self
338            .enums
339            .entry(TypeId::of::<O>())
340            .or_insert_with(|| Registered {
341                name: info.name,
342                names: Vec::new(),
343                table: Box::new(Table::<O> {
344                    variants: Vec::new(),
345                    tags: Vec::new(),
346                }),
347            });
348        let table = registered
349            .table
350            .downcast_mut::<Table<O>>()
351            .expect("the table of an open enum has the type of the open enum");
352        if table.variants.iter().any(|variant| variant.ty == ty) {
353            return Ok(self);
354        }
355        let tags = match info.repr {
356            OpenRepr::Untagged => Vec::new(),
357            _ => entry.tags(info),
358        };
359        for tag in &tags {
360            if let Ok(index) = table.tags.binary_search_by(|(other, _)| other.cmp(tag)) {
361                return Err(Error::new(
362                    ErrorKind::Configuration,
363                    alloc::format!(
364                        "duplicate variant `{}` of {}: `{}` and `{}`",
365                        tag_display(*tag),
366                        info.name,
367                        table.variants[table.tags[index].1].type_name,
368                        type_name::<T>(),
369                    ),
370                ));
371            }
372        }
373        let variant = table.variants.len();
374        table.variants.push(Registration {
375            ty,
376            type_name: type_name::<T>(),
377            make: make_variant::<O, T>,
378            try_untagged: try_variant::<O, T>,
379        });
380        for tag in tags {
381            let index = table
382                .tags
383                .binary_search_by(|(other, _)| other.cmp(&tag))
384                .unwrap_err();
385            table.tags.insert(index, (tag, variant));
386        }
387        let name = entry.display_name(info);
388        let index = registered.names.binary_search(&name).unwrap_or_else(|x| x);
389        registered.names.insert(index, name);
390        Ok(self)
391    }
392
393    /// Returns the variants of an open enum.
394    #[inline]
395    fn get<O: ?Sized + OpenEnum>(&self) -> Option<&Registered> {
396        self.enums.get(&TypeId::of::<O>())
397    }
398
399    /// Looks up the variant of an open enum by tag.
400    #[inline]
401    fn lookup<O: ?Sized + OpenEnum>(&self, tag: Tag<'_>) -> Option<MakeVariant<O>> {
402        let table = self.get::<O>()?.table.downcast_ref::<Table<O>>()?;
403        let index = table
404            .tags
405            .binary_search_by(|(other, _)| other.cmp(&tag))
406            .ok()?;
407        Some(table.variants[table.tags[index].1].make)
408    }
409
410    /// Returns the variant of an untagged open enum with the given index.
411    #[inline]
412    fn untagged<O: ?Sized + OpenEnum>(&self, index: usize) -> Option<TryVariant<O>> {
413        let table = self.get::<O>()?.table.downcast_ref::<Table<O>>()?;
414        Some(table.variants.get(index)?.try_untagged)
415    }
416}
417
418impl fmt::Debug for OpenEnums {
419    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
420        f.debug_map()
421            .entries(
422                self.enums
423                    .values()
424                    .map(|registered| (registered.name, &registered.names)),
425            )
426            .finish()
427    }
428}
429
430impl Serialize for Tag<'_> {
431    fn serialize<'a>(value: &'a Self, _state: &mut State) -> Result<Emit<'a>, Error> {
432        Ok(Emit::Atom(match *value {
433            Tag::Str(name) => Atom::Str(Text::borrowed(name)),
434            Tag::U64(value) => Atom::U64(value),
435            Tag::I64(value) => Atom::I64(value),
436            Tag::Bool(value) => Atom::Bool(value),
437        }))
438    }
439}
440
441/// Returns how a variant is described.
442fn variant_repr(repr: OpenRepr) -> VariantRepr<'static> {
443    match repr {
444        OpenRepr::External => VariantRepr::External,
445        OpenRepr::Internal { tag } => VariantRepr::Internal { tag: tag.name },
446        OpenRepr::Adjacent { tag, content, .. } => VariantRepr::Adjacent {
447            tag: tag.name,
448            content: content.name,
449        },
450        OpenRepr::Untagged => VariantRepr::Untagged,
451    }
452}
453
454/// Serializes the trait object of an open enum.
455pub fn serialize<'a, O: ?Sized + OpenEnum>(
456    value: &'a O,
457    state: &mut State,
458) -> Result<Emit<'a>, Error> {
459    let VariantValue { entry, content } = O::__private_variant(value);
460    let info = O::INFO;
461    Ok(match info.repr {
462        OpenRepr::External => match entry.name_str(info) {
463            Some(name) => {
464                FieldsSer(Vec::from([(name, SerializeHandle::from(content))])).into_emit(state)
465            }
466            None => EntrySer::new(entry.name_handle(info), SerializeHandle::from(content))
467                .into_emit(state),
468        },
469        OpenRepr::Internal { tag } => {
470            TaggedNewtype::new(tag.name, entry.name_handle(info), content).into_emit(state)
471        }
472        OpenRepr::Adjacent {
473            tag,
474            content: content_key,
475            ..
476        } => FieldsSer(Vec::from([
477            (tag.name, entry.name_handle(info)),
478            (content_key.name, SerializeHandle::from(content)),
479        ]))
480        .into_emit(state),
481        OpenRepr::Untagged => Emit::Forward(SerializeHandle::from(content)),
482    })
483}
484
485/// Describes the trait object of an open enum.
486pub fn describe<O: ?Sized + OpenEnum>(value: &O, d: &mut dyn Describe) {
487    let VariantValue { entry, content } = O::__private_variant(value);
488    let name = entry.display_name(O::INFO);
489    let repr = O::INFO.repr;
490    d.variant(&Variant::new(
491        O::INFO.name,
492        &name,
493        VariantKind::Newtype,
494        variant_repr(repr),
495    ));
496    // the fields of the content are merged with the tag, like for newtype
497    // variants of internally tagged enums, untagged variants are their
498    // content
499    if let OpenRepr::Internal { .. } | OpenRepr::Untagged = repr {
500        content.describe(d);
501    }
502}
503
504/// Returns the shape of the trait object of an open enum.
505pub fn container_shape<O: ?Sized + OpenEnum>() -> ContainerShape {
506    match O::INFO.repr {
507        OpenRepr::External => ContainerShape::with_len(1),
508        OpenRepr::Internal { .. } => ContainerShape::new(),
509        OpenRepr::Adjacent { .. } => ContainerShape::with_len(2),
510        // the content provides its own shape (the value forwards to it)
511        OpenRepr::Untagged => ContainerShape::new(),
512    }
513}
514
515/// Looks up the variant of an open enum by its tag.
516fn lookup<'a, 'de: 'a, O: ?Sized + OpenEnum>(
517    tag: Tag<'_>,
518    state: &mut State,
519) -> Option<ArenaVariant<'a, 'de, Box<O>>> {
520    let make = match state.get::<OpenEnums>() {
521        Some(registry) if registry.get::<O>().is_some() => registry.lookup::<O>(tag)?,
522        _ => return Some(ArenaVariant::new(Unregistered::<O>::new(), state)),
523    };
524    Some(make(state, PhantomData))
525}
526
527/// Tries the variant of an untagged open enum with the given index.
528///
529/// Returns `false` if there is no such variant.
530fn untagged_variants<'de, O: ?Sized + OpenEnum>(
531    index: usize,
532    attempt: &mut UntaggedTry<'_, 'de, Box<O>>,
533) -> bool {
534    let try_variant = match attempt.state().get::<OpenEnums>() {
535        Some(registry) => registry.untagged::<O>(index),
536        None => None,
537    };
538    match try_variant {
539        Some(try_variant) => {
540            try_variant(attempt);
541            true
542        }
543        None => false,
544    }
545}
546
547/// Returns the error for a value that no variant of an untagged open enum
548/// accepted.
549///
550/// Without registered variants no variant is tried, which is an error of
551/// the configuration (like for tagged open enums).
552#[cold]
553fn untagged_no_match<O: ?Sized + OpenEnum>(name: &str, state: &State) -> Error {
554    let registered = state
555        .get::<OpenEnums>()
556        .is_some_and(|registry| registry.get::<O>().is_some());
557    if !registered {
558        return Unregistered::<O>::new().error();
559    }
560    no_matching_variant(name, state)
561}
562
563/// Returns the names of the variants of an open enum for errors.
564fn names<O: ?Sized + OpenEnum>(state: &State) -> Vec<&str> {
565    match state
566        .get::<OpenEnums>()
567        .and_then(|registry| registry.get::<O>())
568    {
569        Some(registered) => registered.names.iter().map(|name| &**name).collect(),
570        None => Vec::new(),
571    }
572}
573
574/// No variant is a unit variant (the variants are given as a tag receive a
575/// null as content).
576fn no_unit<E>(_tag: Tag<'_>) -> Option<E> {
577    None
578}
579
580/// Deserializes the trait object of an open enum in a box.
581pub fn deserialize_box<'out, 'de, O: ?Sized + OpenEnum>(
582    out: &'out mut Option<Box<O>>,
583    state: &mut State,
584) -> SinkHandle<'out, 'de> {
585    let name = O::INFO.name;
586    if let OpenRepr::Untagged = O::INFO.repr {
587        return untagged_handle_with(
588            out,
589            name,
590            untagged_variants::<O>,
591            untagged_no_match::<O>,
592            state,
593        );
594    }
595    let variants = Variants {
596        lookup: lookup::<O>,
597        other: None,
598        default: None,
599        names: VariantNames::Dynamic(names::<O>),
600    };
601    match O::INFO.repr {
602        OpenRepr::External => ExternallyTaggedSink::handle(out, name, variants, no_unit, state),
603        OpenRepr::Internal { tag } => InternallyTaggedSink::handle(out, tag, name, variants, state),
604        OpenRepr::Adjacent {
605            tag,
606            content,
607            deny_unknown_fields,
608        } => AdjacentlyTaggedSink::handle(
609            out,
610            tag,
611            content,
612            name,
613            variants,
614            deny_unknown_fields,
615            state,
616        ),
617        OpenRepr::Untagged => unreachable!("untagged open enums are handled above"),
618    }
619}
620
621/// Deserializes the trait object of an open enum in an `Arc`.
622pub fn deserialize_arc<'out, 'de, O: ?Sized + OpenEnum>(
623    out: &'out mut Option<Arc<O>>,
624    state: &mut State,
625) -> SinkHandle<'out, 'de>
626where
627    Box<O>: Deserialize<'de>,
628{
629    mapped(
630        out,
631        OwnedSink::<Box<O>>::deserialize(state),
632        |value| Ok(Arc::from(value)),
633        state,
634    )
635}
636
637/// The builder of the variants of an open enum which has no registered
638/// variants: the registry is missing from the context.
639struct Unregistered<O: ?Sized>(PhantomData<fn() -> Box<O>>);
640
641impl<O: ?Sized + OpenEnum> Unregistered<O> {
642    fn new() -> Self {
643        Unregistered(PhantomData)
644    }
645
646    fn error(&self) -> Error {
647        Error::new(
648            ErrorKind::Configuration,
649            alloc::format!(
650                "no variants of {} are registered (register them in a deser::OpenEnums \
651                 that is given in the context)",
652                O::INFO.name
653            ),
654        )
655    }
656}
657
658impl<'de, O: ?Sized + OpenEnum> VariantBuilder<'de, Box<O>> for Unregistered<O> {
659    fn sink(&mut self) -> &mut dyn Sink<'de> {
660        self
661    }
662
663    fn build(&mut self) -> Option<Box<O>> {
664        None
665    }
666}
667
668impl<'de, O: ?Sized + OpenEnum> Sink<'de> for Unregistered<O> {
669    fn atom(&mut self, _atom: Atom, _state: &mut State) -> Result<(), Error> {
670        Err(self.error())
671    }
672
673    fn map(&mut self, _state: &mut State) -> Result<(), Error> {
674        Err(self.error())
675    }
676
677    fn seq(&mut self, _state: &mut State) -> Result<(), Error> {
678        Err(self.error())
679    }
680
681    fn finish(&mut self, _state: &mut State) -> Result<(), Error> {
682        Err(self.error())
683    }
684}