1use std::{
4 fmt,
5 os::unix::{
6 io::{AsRawFd, BorrowedFd, OwnedFd, RawFd},
7 net::UnixStream,
8 },
9 sync::{Arc, Condvar, Mutex, MutexGuard, Weak},
10};
11
12use crate::{
13 core_interfaces::WL_DISPLAY_INTERFACE,
14 debug,
15 protocol::{
16 check_for_signature, same_interface, same_interface_or_anonymous, AllowNull, Argument,
17 ArgumentType, Interface, Message, ObjectInfo, ProtocolError, ANONYMOUS_INTERFACE,
18 INLINE_ARGS,
19 },
20};
21use smallvec::SmallVec;
22
23use super::{
24 client::*,
25 map::{Object, ObjectMap, SERVER_ID_LIMIT},
26 socket::{BufferedSocket, Socket},
27 wire::MessageParseError,
28};
29
30#[derive(Debug, Clone)]
31struct Data {
32 client_destroyed: bool,
33 server_destroyed: bool,
34 user_data: Arc<dyn ObjectData>,
35 serial: u32,
36}
37
38#[derive(Clone)]
40pub struct InnerObjectId {
41 serial: u32,
42 id: u32,
43 interface: &'static Interface,
44}
45
46impl std::cmp::PartialEq for InnerObjectId {
47 fn eq(&self, other: &Self) -> bool {
48 self.id == other.id
49 && self.serial == other.serial
50 && same_interface(self.interface, other.interface)
51 }
52}
53
54impl std::cmp::Eq for InnerObjectId {}
55
56impl std::hash::Hash for InnerObjectId {
57 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
58 self.serial.hash(state);
59 self.id.hash(state);
60 }
61}
62
63impl fmt::Display for InnerObjectId {
64 #[cfg_attr(unstable_coverage, coverage(off))]
65 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66 write!(f, "{}@{}", self.interface.name, self.id)
67 }
68}
69
70impl fmt::Debug for InnerObjectId {
71 #[cfg_attr(unstable_coverage, coverage(off))]
72 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73 write!(f, "ObjectId({}, {})", self, self.serial)
74 }
75}
76
77impl InnerObjectId {
78 pub fn is_null(&self) -> bool {
79 self.id == 0
80 }
81
82 pub fn interface(&self) -> &'static Interface {
83 self.interface
84 }
85
86 pub fn protocol_id(&self) -> u32 {
87 self.id
88 }
89}
90
91#[derive(Debug)]
92struct ProtocolState {
93 socket: BufferedSocket,
94 map: ObjectMap<Data>,
95 last_error: Option<WaylandError>,
96 last_serial: u32,
97 debug: bool,
98}
99
100#[derive(Debug)]
101struct ReadingState {
102 prepared_reads: usize,
103 read_condvar: Arc<Condvar>,
104 read_serial: usize,
105}
106
107#[derive(Debug)]
108pub struct ConnectionState {
109 protocol: Mutex<ProtocolState>,
110 read: Mutex<ReadingState>,
111}
112
113impl ConnectionState {
114 fn lock_protocol(&self) -> MutexGuard<'_, ProtocolState> {
115 self.protocol.lock().unwrap()
116 }
117
118 fn lock_read(&self) -> MutexGuard<'_, ReadingState> {
119 self.read.lock().unwrap()
120 }
121}
122
123#[derive(Clone, Debug)]
124pub struct InnerBackend {
125 state: Arc<ConnectionState>,
126}
127
128#[derive(Clone, Debug)]
129pub struct WeakInnerBackend {
130 state: Weak<ConnectionState>,
131}
132
133impl WeakInnerBackend {
134 pub fn upgrade(&self) -> Option<InnerBackend> {
135 Weak::upgrade(&self.state).map(|state| InnerBackend { state })
136 }
137}
138
139impl PartialEq for InnerBackend {
140 fn eq(&self, rhs: &Self) -> bool {
141 Arc::ptr_eq(&self.state, &rhs.state)
142 }
143}
144
145impl Eq for InnerBackend {}
146
147impl InnerBackend {
148 pub fn downgrade(&self) -> WeakInnerBackend {
149 WeakInnerBackend { state: Arc::downgrade(&self.state) }
150 }
151
152 pub fn connect(stream: UnixStream) -> Result<Self, NoWaylandLib> {
153 let socket = BufferedSocket::new(Socket::from(stream));
154 let mut map = ObjectMap::new();
155 map.insert_at(
156 1,
157 Object {
158 interface: &WL_DISPLAY_INTERFACE,
159 version: 1,
160 data: Data {
161 client_destroyed: false,
162 server_destroyed: false,
163 user_data: Arc::new(DumbObjectData),
164 serial: 0,
165 },
166 },
167 )
168 .unwrap();
169
170 let debug = debug::has_debug_client_env();
171
172 Ok(Self {
173 state: Arc::new(ConnectionState {
174 protocol: Mutex::new(ProtocolState {
175 socket,
176 map,
177 last_error: None,
178 last_serial: 0,
179 debug,
180 }),
181 read: Mutex::new(ReadingState {
182 prepared_reads: 0,
183 read_condvar: Arc::new(Condvar::new()),
184 read_serial: 0,
185 }),
186 }),
187 })
188 }
189
190 pub fn flush(&self) -> Result<(), WaylandError> {
192 let mut guard = self.state.lock_protocol();
193 guard.no_last_error()?;
194 if let Err(e) = guard.socket.flush() {
195 return Err(guard.store_if_not_wouldblock_and_return_error(e));
196 }
197 Ok(())
198 }
199
200 pub fn poll_fd(&self) -> BorrowedFd<'_> {
201 let raw_fd = self.state.lock_protocol().socket.as_raw_fd();
202 unsafe { BorrowedFd::borrow_raw(raw_fd) }
205 }
206}
207
208#[derive(Debug)]
209pub struct InnerReadEventsGuard {
210 state: Arc<ConnectionState>,
211 done: bool,
212}
213
214impl InnerReadEventsGuard {
215 pub fn try_new(backend: InnerBackend) -> Option<Self> {
220 backend.state.lock_read().prepared_reads += 1;
221 Some(Self { state: backend.state, done: false })
222 }
223
224 pub fn connection_fd(&self) -> BorrowedFd<'_> {
226 let raw_fd = self.state.lock_protocol().socket.as_raw_fd();
227 unsafe { BorrowedFd::borrow_raw(raw_fd) }
230 }
231
232 pub fn read(mut self) -> Result<usize, WaylandError> {
242 let mut guard = self.state.lock_read();
243 guard.prepared_reads -= 1;
244 self.done = true;
245 if guard.prepared_reads == 0 {
246 let ret = dispatch_events(self.state.clone());
248 guard.read_serial = guard.read_serial.wrapping_add(1);
250 guard.read_condvar.notify_all();
251 ret
253 } else {
254 let serial = guard.read_serial;
256 let condvar = guard.read_condvar.clone();
257 let _guard =
258 condvar.wait_while(guard, |backend| serial == backend.read_serial).unwrap();
259 self.state.lock_protocol().no_last_error()?;
260 Ok(0)
261 }
262 }
263}
264
265impl Drop for InnerReadEventsGuard {
266 fn drop(&mut self) {
267 if !self.done {
268 let mut guard = self.state.lock_read();
269 guard.prepared_reads -= 1;
270 if guard.prepared_reads == 0 {
271 guard.read_serial = guard.read_serial.wrapping_add(1);
273 guard.read_condvar.notify_all();
274 }
275 }
276 }
277}
278
279impl InnerBackend {
280 pub fn display_id(&self) -> ObjectId {
281 ObjectId { id: InnerObjectId { serial: 0, id: 1, interface: &WL_DISPLAY_INTERFACE } }
282 }
283
284 pub fn last_error(&self) -> Option<WaylandError> {
285 self.state.lock_protocol().last_error.clone()
286 }
287
288 pub fn info(&self, id: ObjectId) -> Result<ObjectInfo, InvalidId> {
289 let object = self.state.lock_protocol().get_object(id.id.clone())?;
290 if object.data.client_destroyed {
291 Err(InvalidId)
292 } else {
293 Ok(ObjectInfo { id: id.id.id, interface: object.interface, version: object.version })
294 }
295 }
296
297 pub fn null_id() -> ObjectId {
298 ObjectId { id: InnerObjectId { serial: 0, id: 0, interface: &ANONYMOUS_INTERFACE } }
299 }
300
301 pub fn destroy_object(&self, id: &ObjectId) -> Result<(), InvalidId> {
302 let mut guard = self.state.lock_protocol();
303 let object = guard.get_object(id.id.clone())?;
304 guard
305 .map
306 .with(id.id.id, |obj| {
307 if obj.data.client_destroyed {
308 return Err(InvalidId);
309 }
310 obj.data.client_destroyed = true;
311 Ok(())
312 })
313 .unwrap()?;
314 object.data.user_data.destroyed(id.clone());
315 Ok(())
316 }
317
318 pub fn send_request(
319 &self,
320 Message { sender_id: ObjectId { id }, opcode, args }: Message<ObjectId, RawFd>,
321 data: Option<Arc<dyn ObjectData>>,
322 child_spec: Option<(&'static Interface, u32)>,
323 ) -> Result<ObjectId, InvalidId> {
324 let mut guard = self.state.lock_protocol();
325 let object = guard.get_object(id.clone())?;
326
327 let message_desc = match object.interface.requests.get(opcode as usize) {
328 Some(msg) => msg,
329 None => {
330 panic!("Unknown opcode {} for object {}@{}.", opcode, object.interface.name, id.id);
331 }
332 };
333
334 if object.data.client_destroyed {
335 if guard.debug {
336 debug::print_send_message(id.interface.name, id.id, message_desc.name, &args, true);
337 }
338 return Err(InvalidId);
339 }
340
341 if !check_for_signature(message_desc.signature, &args) {
342 panic!(
343 "Unexpected signature for request {}@{}.{}: expected {:?}, got {:?}.",
344 object.interface.name, id.id, message_desc.name, message_desc.signature, args
345 );
346 }
347
348 let child_spec = if message_desc
350 .signature
351 .iter()
352 .any(|arg| matches!(arg, ArgumentType::NewId))
353 {
354 if let Some((iface, version)) = child_spec {
355 if let Some(child_interface) = message_desc.child_interface {
356 if !same_interface(child_interface, iface) {
357 panic!(
358 "Error when sending request {}@{}.{}: expected interface {} but got {}",
359 object.interface.name,
360 id.id,
361 message_desc.name,
362 child_interface.name,
363 iface.name
364 );
365 }
366 if version != object.version {
367 panic!(
368 "Error when sending request {}@{}.{}: expected version {} but got {}",
369 object.interface.name,
370 id.id,
371 message_desc.name,
372 object.version,
373 version
374 );
375 }
376 }
377 Some((iface, version))
378 } else if let Some(child_interface) = message_desc.child_interface {
379 Some((child_interface, object.version))
380 } else {
381 panic!(
382 "Error when sending request {}@{}.{}: target interface must be specified for a generic constructor.",
383 object.interface.name,
384 id.id,
385 message_desc.name
386 );
387 }
388 } else {
389 None
390 };
391
392 let child = if let Some((child_interface, child_version)) = child_spec {
393 let child_serial = guard.next_serial();
394
395 let child = Object {
396 interface: child_interface,
397 version: child_version,
398 data: Data {
399 client_destroyed: false,
400 server_destroyed: false,
401 user_data: Arc::new(DumbObjectData),
402 serial: child_serial,
403 },
404 };
405
406 let child_id = guard.map.client_insert_new(child);
407
408 guard
409 .map
410 .with(child_id, |obj| {
411 obj.data.user_data = data.expect(
412 "Sending a request creating an object without providing an object data.",
413 );
414 })
415 .unwrap();
416 Some((child_id, child_serial, child_interface))
417 } else {
418 None
419 };
420
421 let args = args.into_iter().map(|arg| {
423 if let Argument::NewId(ObjectId { id: p }) = arg {
424 if p.id != 0 {
425 panic!("The newid provided when sending request {}@{}.{} is not a placeholder.", object.interface.name, id.id, message_desc.name);
426 }
427 if let Some((child_id, child_serial, child_interface)) = child {
428 Argument::NewId(ObjectId { id: InnerObjectId { id: child_id, serial: child_serial, interface: child_interface}})
429 } else {
430 unreachable!();
431 }
432 } else {
433 arg
434 }
435 }).collect::<SmallVec<[_; INLINE_ARGS]>>();
436
437 if guard.debug {
438 debug::print_send_message(
439 object.interface.name,
440 id.id,
441 message_desc.name,
442 &args,
443 false,
444 );
445 }
446 #[cfg(feature = "log")]
447 crate::log_debug!("Sending {}.{} ({})", id, message_desc.name, debug::DisplaySlice(&args));
448
449 let mut msg_args = SmallVec::with_capacity(args.len());
452 let mut arg_interfaces = message_desc.arg_interfaces.iter();
453 for (i, arg) in args.into_iter().enumerate() {
454 msg_args.push(match arg {
455 Argument::Array(a) => Argument::Array(a),
456 Argument::Int(i) => Argument::Int(i),
457 Argument::Uint(u) => Argument::Uint(u),
458 Argument::Str(s) => Argument::Str(s),
459 Argument::Fixed(f) => Argument::Fixed(f),
460 Argument::NewId(nid) => Argument::NewId(nid.id.id),
461 Argument::Fd(f) => Argument::Fd(f),
462 Argument::Object(o) => {
463 let next_interface = arg_interfaces.next().unwrap();
464 if o.id.id != 0 {
465 let arg_object = guard.get_object(o.id.clone())?;
466 if !same_interface_or_anonymous(next_interface, arg_object.interface) {
467 panic!("Request {}@{}.{} expects an argument of interface {} but {} was provided instead.", object.interface.name, id.id, message_desc.name, next_interface.name, arg_object.interface.name);
468 }
469 } else if !matches!(message_desc.signature[i], ArgumentType::Object(AllowNull::Yes)) {
470 panic!("Request {}@{}.{} expects an non-null object argument.", object.interface.name, id.id, message_desc.name);
471 }
472 Argument::Object(o.id.id)
473 }
474 });
475 }
476
477 let msg = Message { sender_id: id.id, opcode, args: msg_args };
478
479 if let Err(err) = guard.socket.write_message(&msg) {
480 guard.last_error = Some(WaylandError::Io(err));
481 }
482
483 if message_desc.is_destructor {
485 guard
486 .map
487 .with(id.id, |obj| {
488 obj.data.client_destroyed = true;
489 })
490 .unwrap();
491 object.data.user_data.destroyed(ObjectId { id });
492 }
493 if let Some((child_id, child_serial, child_interface)) = child {
494 Ok(ObjectId {
495 id: InnerObjectId {
496 id: child_id,
497 serial: child_serial,
498 interface: child_interface,
499 },
500 })
501 } else {
502 Ok(Self::null_id())
503 }
504 }
505
506 pub fn get_data(&self, id: ObjectId) -> Result<Arc<dyn ObjectData>, InvalidId> {
507 let object = self.state.lock_protocol().get_object(id.id)?;
508 Ok(object.data.user_data)
509 }
510
511 pub fn set_data(&self, id: ObjectId, data: Arc<dyn ObjectData>) -> Result<(), InvalidId> {
512 self.state
513 .lock_protocol()
514 .map
515 .with(id.id.id, move |objdata| {
516 if objdata.data.serial != id.id.serial {
517 Err(InvalidId)
518 } else {
519 objdata.data.user_data = data;
520 Ok(())
521 }
522 })
523 .unwrap_or(Err(InvalidId))
524 }
525
526 pub fn dispatch_inner_queue(&self) -> Result<usize, WaylandError> {
528 Ok(0)
529 }
530}
531
532impl ProtocolState {
533 fn next_serial(&mut self) -> u32 {
534 self.last_serial = self.last_serial.wrapping_add(1);
535 self.last_serial
536 }
537
538 #[inline]
539 fn no_last_error(&self) -> Result<(), WaylandError> {
540 if let Some(ref err) = self.last_error {
541 Err(err.clone())
542 } else {
543 Ok(())
544 }
545 }
546
547 #[inline]
548 fn store_and_return_error(&mut self, err: impl Into<WaylandError>) -> WaylandError {
549 let err = err.into();
550 crate::log_error!("{err}");
551 self.last_error = Some(err.clone());
552 err
553 }
554
555 #[inline]
556 fn store_if_not_wouldblock_and_return_error(&mut self, e: std::io::Error) -> WaylandError {
557 if e.kind() != std::io::ErrorKind::WouldBlock {
558 self.store_and_return_error(e)
559 } else {
560 e.into()
561 }
562 }
563
564 fn get_object(&self, id: InnerObjectId) -> Result<Object<Data>, InvalidId> {
565 let object = self.map.find(id.id).ok_or(InvalidId)?;
566 if object.data.serial != id.serial {
567 return Err(InvalidId);
568 }
569 Ok(object)
570 }
571
572 fn handle_display_event(&mut self, message: Message<u32, OwnedFd>) -> Result<(), WaylandError> {
573 if self.debug {
574 debug::print_dispatched_message(
575 "wl_display",
576 message.sender_id,
577 if message.opcode == 0 { "error" } else { "delete_id" },
578 &message.args,
579 );
580 }
581 match message.opcode {
582 0 => {
583 if let [Argument::Object(obj), Argument::Uint(code), Argument::Str(Some(ref message))] =
585 message.args[..]
586 {
587 let object = self.map.find(obj);
588 let err = WaylandError::Protocol(ProtocolError {
589 code,
590 object_id: obj,
591 object_interface: object
592 .map(|obj| obj.interface.name)
593 .unwrap_or("<unknown>")
594 .into(),
595 message: message.to_string_lossy().into(),
596 });
597 return Err(self.store_and_return_error(err));
598 } else {
599 unreachable!()
600 }
601 }
602 1 => {
603 if let [Argument::Uint(id)] = message.args[..] {
605 let client_destroyed = self
606 .map
607 .with(id, |obj| {
608 obj.data.server_destroyed = true;
609 obj.data.client_destroyed
610 })
611 .unwrap_or(false);
612 if client_destroyed {
613 self.map.remove(id);
614 }
615 } else {
616 unreachable!()
617 }
618 }
619 _ => unreachable!(),
620 }
621 Ok(())
622 }
623}
624
625fn dispatch_events(state: Arc<ConnectionState>) -> Result<usize, WaylandError> {
626 let backend = Backend { backend: InnerBackend { state } };
627 let mut guard = backend.backend.state.lock_protocol();
628 guard.no_last_error()?;
629 let mut dispatched = 0;
630 loop {
631 let ProtocolState { ref mut socket, ref map, .. } = *guard;
633 let message = match socket.read_one_message(|id, opcode| {
634 map.find(id)
635 .and_then(|o| o.interface.events.get(opcode as usize))
636 .map(|desc| desc.signature)
637 }) {
638 Ok(msg) => msg,
639 Err(MessageParseError::MissingData) | Err(MessageParseError::MissingFD) => {
640 if let Err(e) = guard.socket.fill_incoming_buffers() {
642 if e.kind() != std::io::ErrorKind::WouldBlock {
643 return Err(guard.store_and_return_error(e));
644 } else if dispatched == 0 {
645 return Err(e.into());
646 } else {
647 break;
648 }
649 }
650 continue;
651 }
652 Err(MessageParseError::Malformed) => {
653 let err = WaylandError::Protocol(ProtocolError {
655 code: 0,
656 object_id: 0,
657 object_interface: "".into(),
658 message: "Malformed Wayland message.".into(),
659 });
660 return Err(guard.store_and_return_error(err));
661 }
662 };
663
664 let receiver = guard.map.find(message.sender_id).unwrap();
667 let message_desc = receiver.interface.events.get(message.opcode as usize).unwrap();
668
669 if message.sender_id == 1 {
671 guard.handle_display_event(message)?;
672 continue;
673 }
674
675 let mut created_id = None;
676
677 let mut args = SmallVec::with_capacity(message.args.len());
679 let mut arg_interfaces = message_desc.arg_interfaces.iter();
680 for arg in message.args.into_iter() {
681 args.push(match arg {
682 Argument::Array(a) => Argument::Array(a),
683 Argument::Int(i) => Argument::Int(i),
684 Argument::Uint(u) => Argument::Uint(u),
685 Argument::Str(s) => Argument::Str(s),
686 Argument::Fixed(f) => Argument::Fixed(f),
687 Argument::Fd(f) => Argument::Fd(f),
688 Argument::Object(o) => {
689 if o != 0 {
690 let obj = match guard.map.find(o) {
692 Some(o) => o,
693 None => {
694 let err = WaylandError::Protocol(ProtocolError {
695 code: 0,
696 object_id: 0,
697 object_interface: "".into(),
698 message: format!("Unknown object {o}."),
699 });
700 return Err(guard.store_and_return_error(err));
701 }
702 };
703 if let Some(next_interface) = arg_interfaces.next() {
704 if !same_interface_or_anonymous(next_interface, obj.interface) {
705 let err = WaylandError::Protocol(ProtocolError {
706 code: 0,
707 object_id: 0,
708 object_interface: "".into(),
709 message: format!(
710 "Protocol error: server sent object {} for interface {}, but it has interface {}.",
711 o, next_interface.name, obj.interface.name
712 ),
713 });
714 return Err(guard.store_and_return_error(err));
715 }
716 }
717 Argument::Object(ObjectId { id: InnerObjectId { id: o, serial: obj.data.serial, interface: obj.interface }})
718 } else {
719 Argument::Object(ObjectId { id: InnerObjectId { id: 0, serial: 0, interface: &ANONYMOUS_INTERFACE }})
720 }
721 }
722 Argument::NewId(new_id) => {
723 let child_interface = match message_desc.child_interface {
725 Some(iface) => iface,
726 None => panic!("Received event {}@{}.{} which creates an object without specifying its interface, this is unsupported.", receiver.interface.name, message.sender_id, message_desc.name),
727 };
728
729 let child_udata = Arc::new(UninitObjectData);
730
731 if new_id >= SERVER_ID_LIMIT
733 && guard.map.with(new_id, |obj| obj.data.client_destroyed).unwrap_or(false)
734 {
735 guard.map.remove(new_id);
736 }
737
738 let child_obj = Object {
739 interface: child_interface,
740 version: receiver.version,
741 data: Data {
742 client_destroyed: receiver.data.client_destroyed,
743 server_destroyed: false,
744 user_data: child_udata,
745 serial: guard.next_serial(),
746 }
747 };
748
749 let child_id = InnerObjectId { id: new_id, serial: child_obj.data.serial, interface: child_obj.interface };
750 created_id = Some(child_id.clone());
751
752 if let Err(()) = guard.map.insert_at(new_id, child_obj) {
753 let err = WaylandError::Protocol(ProtocolError {
755 code: 0,
756 object_id: 0,
757 object_interface: "".into(),
758 message: format!(
759 "Protocol error: server tried to create \
760 an object \"{}\" with invalid id {}.",
761 child_interface.name, new_id
762 ),
763 });
764 return Err(guard.store_and_return_error(err));
765 }
766
767 Argument::NewId(ObjectId { id: child_id })
768 }
769 });
770 }
771
772 if guard.debug {
773 debug::print_dispatched_message(
774 receiver.interface.name,
775 message.sender_id,
776 message_desc.name,
777 &args,
778 );
779 }
780
781 if receiver.data.client_destroyed {
783 continue;
784 }
785
786 let id = InnerObjectId {
788 id: message.sender_id,
789 serial: receiver.data.serial,
790 interface: receiver.interface,
791 };
792
793 std::mem::drop(guard);
795 #[cfg(feature = "log")]
796 crate::log_debug!(
797 "Dispatching {}.{} ({})",
798 id,
799 receiver.version,
800 debug::DisplaySlice(&args)
801 );
802 let ret = receiver
803 .data
804 .user_data
805 .clone()
806 .event(&backend, Message { sender_id: ObjectId { id }, opcode: message.opcode, args });
807 guard = backend.backend.state.lock_protocol();
809
810 if message_desc.is_destructor {
812 guard
813 .map
814 .with(message.sender_id, |obj| {
815 obj.data.server_destroyed = true;
816 obj.data.client_destroyed = true;
817 })
818 .unwrap();
819 receiver.data.user_data.destroyed(ObjectId {
820 id: InnerObjectId {
821 id: message.sender_id,
822 serial: receiver.data.serial,
823 interface: receiver.interface,
824 },
825 });
826 }
827
828 match (created_id, ret) {
829 (Some(child_id), Some(child_data)) => {
830 guard.map.with(child_id.id, |obj| obj.data.user_data = child_data).unwrap();
831 }
832 (None, None) => {}
833 (Some(child_id), None) => {
834 panic!("Callback creating object {child_id} did not provide any object data.");
835 }
836 (None, Some(_)) => {
837 panic!("An object data was returned from a callback not creating any object");
838 }
839 }
840
841 dispatched += 1;
842 }
843 Ok(dispatched)
844}