1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use anyhow::format_err;
use fuchsia_zircon as zx;
use thiserror::Error;

use crate::header::HeaderIdentifier;
use crate::operation::{OpCode, ResponseCode};

/// Errors that occur during the use of the OBEX library.
#[derive(Error, Debug)]
pub enum Error {
    #[error("Error parsing packet: {:?}", .0)]
    Packet(#[from] PacketError),
    #[error("Header {:?} already exists in HeaderSet", .0)]
    AlreadyExists(HeaderIdentifier),
    #[error("{:?} cannot be added with {:?}", .0, .1)]
    IncompatibleHeaders(HeaderIdentifier, HeaderIdentifier),
    #[error("Encountered an IO Error: {}", .0)]
    IOError(#[from] zx::Status),
    #[error("Operation is already in progress")]
    OperationInProgress,
    #[error("Internal error during {:?}: {:?}", .operation, .msg)]
    OperationError { operation: OpCode, msg: String },
    #[error("Single Response Mode is not supported")]
    SrmNotSupported,
    #[error("Peer disconnected")]
    PeerDisconnected,
    #[error("Peer rejected {:?} request with Error: {:?}", .operation, .response)]
    PeerRejected { operation: OpCode, response: ResponseCode },
    #[error("Invalid {:?} response from peer: {:?}", .operation, .msg)]
    PeerResponse { operation: OpCode, msg: String },
    #[error("{:?} is not implemented", .operation)]
    NotImplemented { operation: OpCode },
    #[error(transparent)]
    Other(#[from] anyhow::Error),
}

impl Error {
    pub fn peer_rejected(operation: OpCode, response: ResponseCode) -> Self {
        Self::PeerRejected { operation, response }
    }

    pub fn response(operation: OpCode, msg: impl Into<String>) -> Self {
        Self::PeerResponse { operation, msg: msg.into() }
    }

    pub fn operation(operation: OpCode, msg: impl Into<String>) -> Self {
        Self::OperationError { operation, msg: msg.into() }
    }

    pub fn not_implemented(operation: OpCode) -> Self {
        Self::NotImplemented { operation }
    }

    pub fn other(msg: impl Into<String>) -> Self {
        Self::Other(format_err!(msg.into()).into())
    }
}

/// Errors that occur during the encoding & decoding of OBEX packets.
#[derive(Error, Debug)]
pub enum PacketError {
    #[error("Buffer is too small")]
    BufferTooSmall,
    #[error("Invalid data length")]
    DataLength,
    #[error("Invalid data: {}", .0)]
    Data(String),
    #[error("Invalid header identifier: {}", .0)]
    Identifier(u8),
    #[error("Invalid packet OpCode: {}", .0)]
    OpCode(u8),
    #[error("Invalid header encoding")]
    HeaderEncoding,
    #[error("Invalid response code: {}", .0)]
    ResponseCode(u8),
    #[error("Field is RFA.")]
    Reserved,
    /// An error from another source
    #[error(transparent)]
    Other(#[from] anyhow::Error),
}

impl PacketError {
    pub fn external(e: impl Into<anyhow::Error>) -> Self {
        Self::Other(e.into())
    }

    pub fn data(e: impl Into<String>) -> Self {
        Self::Data(e.into())
    }
}