1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
45//! This module contains an AST for arguments for both AT commands and responses.
6//!
7//! The format of of these is not specifed in any one place in the spec, but they are
8//! described thoughout HFP 1.8.
910use crate::lowlevel::write_to::WriteTo;
11use std::io;
1213/// An argument list set off from a command or response by a delimiter such as "=" or ":".
14#[derive(Debug, Clone, PartialEq)]
15pub struct DelimitedArguments {
16/// A string setting off arguments from the command or response. This is normally `=`
17 /// or ": ", but could be ">" or absent. This latter is currently only in a variants
18 /// of the `ATD` command, specified in HFP v1.8 4.19.
19pub delimiter: Option<String>,
20/// The actual arguments to the execute commmand.
21pub arguments: Arguments,
22/// An optional terminator for the arguments to the command, such as the ";" used to
23 /// terminate ATD commands.
24pub terminator: Option<String>,
25}
2627impl WriteTo for DelimitedArguments {
28fn write_to<W: io::Write>(&self, sink: &mut W) -> io::Result<()> {
29let DelimitedArguments { delimiter, arguments, terminator } = self;
30if let Some(string) = delimiter {
31if string == ":" {
32// Hack. The parser ignores whitespace, but the colon in a response must be followed by a space, so special case this.
33sink.write_all(": ".as_bytes())?;
34 } else {
35 sink.write_all(string.as_bytes())?;
36 }
37 };
38 arguments.write_to(sink)?;
39if let Some(terminator) = terminator {
40 sink.write_all(terminator.as_bytes())?
41};
4243Ok(())
44 }
45}
46/// The collection of arguments to a given command or response.
47///
48/// AT supports multiple different formats, represented here by the different enum
49/// branches.
50#[derive(Debug, Clone, PartialEq)]
51pub enum Arguments {
52/// A sequence of multiple arguments lists delimited by parentheses, like, `(1,2)(3,4)(a=1)`
53ParenthesisDelimitedArgumentLists(Vec<Vec<Argument>>),
54/// A single argument list delimited by commas, like, `1,2,a=3`
55ArgumentList(Vec<Argument>),
56}
5758impl Arguments {
59fn write_comma_delimited_argument_list<W: io::Write>(
60&self,
61 arguments: &[Argument],
62 sink: &mut W,
63 ) -> io::Result<()> {
64if !arguments.is_empty() {
65for argument in &arguments[0..arguments.len() - 1] {
66 argument.write_to(sink)?;
67 sink.write_all(b",")?;
68 }
69 arguments[arguments.len() - 1].write_to(sink)?;
70 }
7172Ok(())
73 }
7475fn write_paren_delimited_argument_lists<W: io::Write>(
76&self,
77 argument_lists: &[Vec<Argument>],
78 sink: &mut W,
79 ) -> io::Result<()> {
80for arguments in argument_lists {
81 sink.write_all(b"(")?;
82self.write_comma_delimited_argument_list(arguments, sink)?;
83 sink.write_all(b")")?;
84 }
8586Ok(())
87 }
88}
8990impl WriteTo for Arguments {
91fn write_to<W: io::Write>(&self, sink: &mut W) -> io::Result<()> {
92match self {
93 Arguments::ParenthesisDelimitedArgumentLists(argument_lists) => {
94self.write_paren_delimited_argument_lists(&argument_lists, sink)
95 }
96 Arguments::ArgumentList(argument_list) => {
97self.write_comma_delimited_argument_list(&argument_list, sink)
98 }
99 }
100 }
101}
102103/// An individual argument in a list.
104#[derive(Debug, Clone, PartialEq)]
105pub enum Argument {
106/// A primitive string or int.
107PrimitiveArgument(String),
108/// A key-value pair like `a=1`
109KeyValueArgument { key: String, value: String },
110}
111112impl Argument {
113pub fn is_empty(&self) -> bool {
114match self {
115 Argument::PrimitiveArgument(argument) => argument.is_empty(),
116 Argument::KeyValueArgument { key, value } => key.is_empty() && value.is_empty(),
117 }
118 }
119}
120121impl WriteTo for Argument {
122fn write_to<W: io::Write>(&self, sink: &mut W) -> io::Result<()> {
123match self {
124 Argument::PrimitiveArgument(argument) => sink.write_all(argument.as_bytes())?,
125 Argument::KeyValueArgument { key, value } => {
126 sink.write_all(key.as_bytes())?;
127 sink.write_all(b"=")?;
128 sink.write_all(value.as_bytes())?;
129 }
130 }
131Ok(())
132 }
133}