Merge pull request #1574 from MichaelDvP/dev2

Update dev2 to latest changes of dev
This commit is contained in:
Proddy
2024-01-21 10:18:10 +01:00
committed by GitHub
319 changed files with 5315 additions and 5780 deletions

View File

@@ -13,16 +13,27 @@
- heatpump energy meters [#1463](https://github.com/emsesp/EMS-ESP32/issues/1463) - heatpump energy meters [#1463](https://github.com/emsesp/EMS-ESP32/issues/1463)
- heatpump max power [#1475](https://github.com/emsesp/EMS-ESP32/issues/1475) - heatpump max power [#1475](https://github.com/emsesp/EMS-ESP32/issues/1475)
- checkbox for MQTT-TLS enable [#1474](https://github.com/emsesp/EMS-ESP32/issues/1474) - checkbox for MQTT-TLS enable [#1474](https://github.com/emsesp/EMS-ESP32/issues/1474)
- added SK (Slovencina) language. Thanks @misa1515 - added SK (Slovenian) language. Thanks @misa1515
- CPU info [#1497](https://github.com/emsesp/EMS-ESP32/pull/1497) - CPU info [#1497](https://github.com/emsesp/EMS-ESP32/pull/1497)
- Show network hostname in Web UI under Network Status
- Improved HA Discovery so each section (EMS device, Scheduler, Analog, Temperature, Custom, Shower) have their own section
- boiler Bosch C1200W, id 12, [#1536](https://github.com/emsesp/EMS-ESP32/issues/1536)
- mixer MM100 telegram 0x2CC [#1554](https://github.com/emsesp/EMS-ESP32/issues/1554)
- boiler hpSetDiffPressure [#1563](https://github.com/emsesp/EMS-ESP32/issues/1563)
- custom variables [#1423](https://github.com/emsesp/EMS-ESP32/issues/1423)
## Fixed ## Fixed
- exhaust temperature for some boilers - exhaust temperature for some boilers
- add back boil2hyst [#1477](https://github.com/emsesp/EMS-ESP32/issues/1477) - add back boil2hyst [#1477](https://github.com/emsesp/EMS-ESP32/issues/1477)
- subscribed MQTT topics not detecting changes by EMS-ESP [#1494](https://github.com/emsesp/EMS-ESP32/issues/1494) - subscribed MQTT topics not detecting changes by EMS-ESP [#1494](https://github.com/emsesp/EMS-ESP32/issues/1494)
- changed HA name and grouping to be consistent [#1528](https://github.com/emsesp/EMS-ESP32/issues/1528)
- MQTT autodiscovery in Domoticz not working [#1360](https://github.com/emsesp/EMS-ESP32/issues/1528)
- dhw comfort for new ems+, [#1495](https://github.com/emsesp/EMS-ESP32/issues/1495)
- added writeable icon to Web's Custom Entity page for each entity shown in the table
## Changed ## Changed
- use flag for BC400 compatible thermostats, manage different mode settings - use flag for BC400 compatible thermostats, manage different mode settings
- HA don't set entity_category to Diagnostic/Configuration for EMS entities [#1459](https://github.com/emsesp/EMS-ESP32/discussions/1459) - HA don't set entity_category to Diagnostic/Configuration for EMS entities [#1459](https://github.com/emsesp/EMS-ESP32/discussions/1459)
- upgraded ArduinoJson to 7.0.0 #1538 and then 7.0.2

View File

@@ -20,20 +20,20 @@
"lint": "eslint . --cache --fix" "lint": "eslint . --cache --fix"
}, },
"dependencies": { "dependencies": {
"@alova/adapter-xhr": "^1.0.2", "@alova/adapter-xhr": "^1.0.3",
"@babel/core": "^7.23.7", "@babel/core": "^7.23.7",
"@emotion/react": "^11.11.3", "@emotion/react": "^11.11.3",
"@emotion/styled": "^11.11.0", "@emotion/styled": "^11.11.0",
"@mui/icons-material": "^5.15.3", "@mui/icons-material": "^5.15.5",
"@mui/material": "^5.15.3", "@mui/material": "^5.15.5",
"@table-library/react-table-library": "4.1.7", "@table-library/react-table-library": "4.1.7",
"@types/imagemin": "^8.0.5", "@types/imagemin": "^8.0.5",
"@types/lodash-es": "^4.17.12", "@types/lodash-es": "^4.17.12",
"@types/node": "^20.10.6", "@types/node": "^20.11.5",
"@types/react": "^18.2.46", "@types/react": "^18.2.48",
"@types/react-dom": "^18.2.18", "@types/react-dom": "^18.2.18",
"@types/react-router-dom": "^5.3.3", "@types/react-router-dom": "^5.3.3",
"alova": "^2.16.2", "alova": "^2.17.0",
"async-validator": "^4.2.5", "async-validator": "^4.2.5",
"history": "^5.3.0", "history": "^5.3.0",
"jwt-decode": "^4.0.0", "jwt-decode": "^4.0.0",
@@ -42,9 +42,9 @@
"react": "latest", "react": "latest",
"react-dom": "latest", "react-dom": "latest",
"react-dropzone": "^14.2.3", "react-dropzone": "^14.2.3",
"react-icons": "^4.12.0", "react-icons": "^5.0.1",
"react-router-dom": "^6.21.1", "react-router-dom": "^6.21.3",
"react-toastify": "^9.1.3", "react-toastify": "^10.0.4",
"sockette": "^2.0.6", "sockette": "^2.0.6",
"typesafe-i18n": "^5.26.2", "typesafe-i18n": "^5.26.2",
"typescript": "^5.3.3" "typescript": "^5.3.3"
@@ -52,8 +52,8 @@
"devDependencies": { "devDependencies": {
"@preact/compat": "^17.1.2", "@preact/compat": "^17.1.2",
"@preact/preset-vite": "^2.8.1", "@preact/preset-vite": "^2.8.1",
"@typescript-eslint/eslint-plugin": "^6.17.0", "@typescript-eslint/eslint-plugin": "^6.19.0",
"@typescript-eslint/parser": "^6.17.0", "@typescript-eslint/parser": "^6.19.0",
"concurrently": "^8.2.2", "concurrently": "^8.2.2",
"eslint": "^8.56.0", "eslint": "^8.56.0",
"eslint-config-airbnb": "^19.0.4", "eslint-config-airbnb": "^19.0.4",
@@ -67,12 +67,12 @@
"eslint-plugin-react": "^7.33.2", "eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"preact": "^10.19.3", "preact": "^10.19.3",
"prettier": "^3.1.1", "prettier": "^3.2.4",
"rollup-plugin-visualizer": "^5.12.0", "rollup-plugin-visualizer": "^5.12.0",
"terser": "^5.26.0", "terser": "^5.27.0",
"vite": "^5.0.10", "vite": "^5.0.12",
"vite-plugin-imagemin": "^0.6.1", "vite-plugin-imagemin": "^0.6.1",
"vite-tsconfig-paths": "^4.2.3" "vite-tsconfig-paths": "^4.3.1"
}, },
"packageManager": "yarn@4.0.2" "packageManager": "yarn@4.0.2"
} }

View File

@@ -12,6 +12,7 @@ var totalSize = 0;
const generateWWWClass = () => const generateWWWClass = () =>
`typedef std::function<void(const String& uri, const String& contentType, const uint8_t * content, size_t len)> RouteRegistrationHandler; `typedef std::function<void(const String& uri, const String& contentType, const uint8_t * content, size_t len)> RouteRegistrationHandler;
// Total size is ${totalSize} bytes
class WWWData { class WWWData {
${indent}public: ${indent}public:

View File

@@ -50,8 +50,10 @@ const SingleUpload: FC<SingleUploadProps> = ({ onDrop, onCancel, isUploading, pr
const progressText = () => { const progressText = () => {
if (uploading) { if (uploading) {
if (progress.total) { if (progress.total && progress.loaded) {
return LL.UPLOADING() + ': ' + Math.round((progress.loaded * 100) / progress.total) + '%'; return progress.loaded <= progress.total
? LL.UPLOADING() + ': ' + Math.round((progress.loaded * 100) / progress.total) + '%'
: LL.UPLOADING() + ': ' + Math.round((progress.total * 100) / progress.loaded) + '%';
} }
} }
return LL.UPLOAD_DROP_TEXT(); return LL.UPLOAD_DROP_TEXT();
@@ -83,7 +85,13 @@ const SingleUpload: FC<SingleUploadProps> = ({ onDrop, onCancel, isUploading, pr
<Box width="100%" p={2}> <Box width="100%" p={2}>
<LinearProgress <LinearProgress
variant="determinate" variant="determinate"
value={progress.total === 0 ? 0 : Math.round((progress.loaded * 100) / progress.total)} value={
progress.total === 0 || progress.loaded === 0
? 0
: progress.loaded <= progress.total
? Math.round((progress.loaded * 100) / progress.total)
: Math.round((progress.total * 100) / progress.loaded)
}
/> />
</Box> </Box>
<Button startIcon={<CancelIcon />} variant="outlined" color="secondary" onClick={onCancel}> <Button startIcon={<CancelIcon />} variant="outlined" color="secondary" onClick={onCancel}>

View File

@@ -273,6 +273,7 @@ const MqttSettingsForm: FC = () => {
> >
<MenuItem value={0}>Home Assistant</MenuItem> <MenuItem value={0}>Home Assistant</MenuItem>
<MenuItem value={1}>Domoticz</MenuItem> <MenuItem value={1}>Domoticz</MenuItem>
<MenuItem value={2}>Domoticz (latest)</MenuItem>
</TextField> </TextField>
</Grid> </Grid>
<Grid item xs={12} sm={6} md={4}> <Grid item xs={12} sm={6} md={4}>

View File

@@ -1,5 +1,6 @@
import DeviceHubIcon from '@mui/icons-material/DeviceHub'; import DeviceHubIcon from '@mui/icons-material/DeviceHub';
import DnsIcon from '@mui/icons-material/Dns'; import DnsIcon from '@mui/icons-material/Dns';
import GiteIcon from '@mui/icons-material/Gite';
import RefreshIcon from '@mui/icons-material/Refresh'; import RefreshIcon from '@mui/icons-material/Refresh';
import RouterIcon from '@mui/icons-material/Router'; import RouterIcon from '@mui/icons-material/Router';
import SettingsInputAntennaIcon from '@mui/icons-material/SettingsInputAntenna'; import SettingsInputAntennaIcon from '@mui/icons-material/SettingsInputAntenna';
@@ -115,6 +116,15 @@ const NetworkStatusForm: FC = () => {
<ListItemText primary="Status" secondary={networkStatus(data)} /> <ListItemText primary="Status" secondary={networkStatus(data)} />
</ListItem> </ListItem>
<Divider variant="inset" component="li" /> <Divider variant="inset" component="li" />
<ListItem>
<ListItemAvatar>
<Avatar sx={{ bgcolor: networkStatusHighlight(data, theme) }}>
<GiteIcon />
</Avatar>
</ListItemAvatar>
<ListItemText primary="Hostname" secondary={data.hostname} />
</ListItem>
<Divider variant="inset" component="li" />
{isWiFi(data) && ( {isWiFi(data) && (
<> <>
<ListItem> <ListItem>

View File

@@ -37,7 +37,8 @@ const GenerateToken: FC<GenerateTokenProps> = ({ username, onClose }) => {
if (open) { if (open) {
void generateToken(); void generateToken();
} }
}, [open, generateToken]); // eslint-disable-next-line react-hooks/exhaustive-deps
}, [open]);
return ( return (
<Dialog sx={dialogStyle} onClose={onClose} open={!!username} fullWidth maxWidth="sm"> <Dialog sx={dialogStyle} onClose={onClose} open={!!username} fullWidth maxWidth="sm">

View File

@@ -227,6 +227,8 @@ const SystemStatusForm: FC = () => {
<ListItemText <ListItemText
primary="CPU" primary="CPU"
secondary={ secondary={
data.esp_platform +
'/' +
data.cpu_type + data.cpu_type +
' (rev.' + ' (rev.' +
data.cpu_rev + data.cpu_rev +

View File

@@ -136,6 +136,7 @@ const UploadFileForm: FC = () => {
<Typography variant="body2"> <Typography variant="body2">
{LL.UPLOAD_TEXT()} {LL.UPLOAD_TEXT()}
<br /> <br />
<br />
{LL.RESTART_TEXT(1)}. {LL.RESTART_TEXT(1)}.
</Typography> </Typography>
</Box> </Box>

View File

@@ -63,7 +63,7 @@ const en: Translation = {
FREQ: 'Frequency', FREQ: 'Frequency',
DUTY_CYCLE: 'Duty Cycle', DUTY_CYCLE: 'Duty Cycle',
UNIT: 'UoM', UNIT: 'UoM',
STARTVALUE: 'Start value', STARTVALUE: 'Start Value',
WARN_GPIO: 'Warning: be careful when assigning a GPIO!', WARN_GPIO: 'Warning: be careful when assigning a GPIO!',
EDIT: 'Edit', EDIT: 'Edit',
SENSOR: 'Sensor', SENSOR: 'Sensor',

View File

@@ -420,7 +420,7 @@ const DashboardDevices: FC = () => {
<MessageBox my={2} level="warning" message={LL.EMS_BUS_SCANNING()} /> <MessageBox my={2} level="warning" message={LL.EMS_BUS_SCANNING()} />
)} )}
{coreData.connected && ( {coreData.devices.length !== 0 && (
<Table data={{ nodes: coreData.devices }} select={device_select} theme={device_theme} layout={{ custom: true }}> <Table data={{ nodes: coreData.devices }} select={device_select} theme={device_theme} layout={{ custom: true }}>
{(tableList: any) => ( {(tableList: any) => (
<> <>

View File

@@ -103,7 +103,7 @@ const DashboardDevicesDialog = ({
return ( return (
<Dialog sx={dialogStyle} open={open} onClose={close}> <Dialog sx={dialogStyle} open={open} onClose={close}>
<DialogTitle> <DialogTitle>
{selectedItem.v === '' && selectedItem.c ? LL.RUN_COMMAND() : writeable ? LL.CHANGE_VALUE() : LL.VALUE(0)} {selectedItem.v === '' && selectedItem.c ? LL.RUN_COMMAND() : writeable ? LL.CHANGE_VALUE() : LL.VALUE(1)}
</DialogTitle> </DialogTitle>
<DialogContent dividers> <DialogContent dividers>
<Box color="warning.main" p={0} pl={0} pr={0} mt={0} mb={2}> <Box color="warning.main" p={0} pl={0} pr={0} mt={0} mb={2}>

View File

@@ -262,7 +262,7 @@ const DashboardSensors: FC = () => {
setSelectedAnalogSensor({ setSelectedAnalogSensor({
id: Math.floor(Math.random() * (Math.floor(200) - 100) + 100), id: Math.floor(Math.random() * (Math.floor(200) - 100) + 100),
n: '', n: '',
g: 40, g: 21, // default GPIO 21 which is safe for all platforms
u: 0, u: 0,
v: 0, v: 0,
o: 0, o: 0,

View File

@@ -182,7 +182,7 @@ const DashboardSensorsAnalogDialog = ({
<Grid item xs={4}> <Grid item xs={4}>
<TextField <TextField
name="o" name="o"
label={LL.VALUE(0)} label={LL.VALUE(1)}
value={numberValue(editItem.o)} value={numberValue(editItem.o)}
fullWidth fullWidth
type="number" type="number"
@@ -197,7 +197,7 @@ const DashboardSensorsAnalogDialog = ({
<Grid item xs={4}> <Grid item xs={4}>
<TextField <TextField
name="o" name="o"
label={LL.VALUE(0)} label={LL.VALUE(1)}
value={numberValue(editItem.o)} value={numberValue(editItem.o)}
fullWidth fullWidth
select select

View File

@@ -2,8 +2,8 @@ import { Tab } from '@mui/material';
import { Navigate, Route, Routes } from 'react-router-dom'; import { Navigate, Route, Routes } from 'react-router-dom';
import SettingsApplication from './SettingsApplication'; import SettingsApplication from './SettingsApplication';
import SettingsCustomEntities from './SettingsCustomEntities';
import SettingsCustomization from './SettingsCustomization'; import SettingsCustomization from './SettingsCustomization';
import SettingsEntities from './SettingsEntities';
import SettingsScheduler from './SettingsScheduler'; import SettingsScheduler from './SettingsScheduler';
import type { FC } from 'react'; import type { FC } from 'react';
import { RouterTabs, useRouterTab, useLayoutTitle } from 'components'; import { RouterTabs, useRouterTab, useLayoutTitle } from 'components';
@@ -27,7 +27,7 @@ const Settings: FC = () => {
<Route path="application" element={<SettingsApplication />} /> <Route path="application" element={<SettingsApplication />} />
<Route path="customization" element={<SettingsCustomization />} /> <Route path="customization" element={<SettingsCustomization />} />
<Route path="scheduler" element={<SettingsScheduler />} /> <Route path="scheduler" element={<SettingsScheduler />} />
<Route path="customentities" element={<SettingsEntities />} /> <Route path="customentities" element={<SettingsCustomEntities />} />
<Route path="*" element={<Navigate replace to="/settings/application" />} /> <Route path="*" element={<Navigate replace to="/settings/application" />} />
</Routes> </Routes>
</> </>

View File

@@ -1,5 +1,7 @@
import AddIcon from '@mui/icons-material/Add'; import AddIcon from '@mui/icons-material/Add';
import CancelIcon from '@mui/icons-material/Cancel'; import CancelIcon from '@mui/icons-material/Cancel';
import RefreshIcon from '@mui/icons-material/Refresh';
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
import WarningIcon from '@mui/icons-material/Warning'; import WarningIcon from '@mui/icons-material/Warning';
import { Button, Typography, Box } from '@mui/material'; import { Button, Typography, Box } from '@mui/material';
import { Table, Header, HeaderRow, HeaderCell, Body, Row, Cell } from '@table-library/react-table-library/table'; import { Table, Header, HeaderRow, HeaderCell, Body, Row, Cell } from '@table-library/react-table-library/table';
@@ -11,7 +13,7 @@ import { useBlocker } from 'react-router-dom';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import SettingsEntitiesDialog from './SettingsEntitiesDialog'; import SettingsCustomEntitiesDialog from './SettingsCustomEntitiesDialog';
import * as EMSESP from './api'; import * as EMSESP from './api';
import { DeviceValueTypeNames, DeviceValueUOM_s } from './types'; import { DeviceValueTypeNames, DeviceValueUOM_s } from './types';
import { entityItemValidation } from './validators'; import { entityItemValidation } from './validators';
@@ -21,7 +23,7 @@ import { ButtonRow, FormLoader, SectionContent, BlockNavigation } from 'componen
import { useI18nContext } from 'i18n/i18n-react'; import { useI18nContext } from 'i18n/i18n-react';
const SettingsEntities: FC = () => { const SettingsCustomEntities: FC = () => {
const { LL } = useI18nContext(); const { LL } = useI18nContext();
const [numChanges, setNumChanges] = useState<number>(0); const [numChanges, setNumChanges] = useState<number>(0);
const blocker = useBlocker(numChanges !== 0); const blocker = useBlocker(numChanges !== 0);
@@ -43,6 +45,7 @@ const SettingsEntities: FC = () => {
function hasEntityChanged(ei: EntityItem) { function hasEntityChanged(ei: EntityItem) {
return ( return (
ei.id !== ei.o_id || ei.id !== ei.o_id ||
ei.ram !== ei.o_ram ||
(ei?.name || '') !== (ei?.o_name || '') || (ei?.name || '') !== (ei?.o_name || '') ||
ei.device_id !== ei.o_device_id || ei.device_id !== ei.o_device_id ||
ei.type_id !== ei.o_type_id || ei.type_id !== ei.o_type_id ||
@@ -51,7 +54,8 @@ const SettingsEntities: FC = () => {
ei.factor !== ei.o_factor || ei.factor !== ei.o_factor ||
ei.value_type !== ei.o_value_type || ei.value_type !== ei.o_value_type ||
ei.writeable !== ei.o_writeable || ei.writeable !== ei.o_writeable ||
ei.deleted !== ei.o_deleted ei.deleted !== ei.o_deleted ||
(ei.value || '') !== (ei.o_value || '')
); );
} }
@@ -118,6 +122,7 @@ const SettingsEntities: FC = () => {
.filter((ei) => !ei.deleted) .filter((ei) => !ei.deleted)
.map((condensed_ei) => ({ .map((condensed_ei) => ({
id: condensed_ei.id, id: condensed_ei.id,
ram: condensed_ei.ram,
name: condensed_ei.name, name: condensed_ei.name,
device_id: condensed_ei.device_id, device_id: condensed_ei.device_id,
type_id: condensed_ei.type_id, type_id: condensed_ei.type_id,
@@ -125,7 +130,8 @@ const SettingsEntities: FC = () => {
factor: condensed_ei.factor, factor: condensed_ei.factor,
uom: condensed_ei.uom, uom: condensed_ei.uom,
writeable: condensed_ei.writeable, writeable: condensed_ei.writeable,
value_type: condensed_ei.value_type value_type: condensed_ei.value_type,
value: condensed_ei.value
})) }))
}) })
.then(() => { .then(() => {
@@ -173,14 +179,16 @@ const SettingsEntities: FC = () => {
setSelectedEntityItem({ setSelectedEntityItem({
id: Math.floor(Math.random() * (Math.floor(200) - 100) + 100), id: Math.floor(Math.random() * (Math.floor(200) - 100) + 100),
name: '', name: '',
device_id: '', ram: 0,
type_id: '', device_id: '0',
type_id: '0',
offset: 0, offset: 0,
factor: 1, factor: 1,
uom: 0, uom: 0,
value_type: 0, value_type: 0,
writeable: false, writeable: false,
deleted: false deleted: false,
value: ''
}); });
setDialogOpen(true); setDialogOpen(true);
}; };
@@ -212,18 +220,21 @@ const SettingsEntities: FC = () => {
<HeaderCell stiff>{LL.ID_OF(LL.DEVICE())}</HeaderCell> <HeaderCell stiff>{LL.ID_OF(LL.DEVICE())}</HeaderCell>
<HeaderCell stiff>{LL.ID_OF(LL.TYPE(1))}</HeaderCell> <HeaderCell stiff>{LL.ID_OF(LL.TYPE(1))}</HeaderCell>
<HeaderCell stiff>{LL.OFFSET()}</HeaderCell> <HeaderCell stiff>{LL.OFFSET()}</HeaderCell>
<HeaderCell stiff>{LL.VALUE(1) + ' ' + LL.TYPE(1)}</HeaderCell> <HeaderCell stiff>{LL.TYPE(1)}</HeaderCell>
<HeaderCell stiff>{LL.VALUE(1)}</HeaderCell> <HeaderCell stiff>{LL.VALUE(1)}</HeaderCell>
</HeaderRow> </HeaderRow>
</Header> </Header>
<Body> <Body>
{tableList.map((ei: EntityItem) => ( {tableList.map((ei: EntityItem) => (
<Row key={ei.name} item={ei} onClick={() => editEntityItem(ei)}> <Row key={ei.name} item={ei} onClick={() => editEntityItem(ei)}>
<Cell>{ei.name}</Cell> <Cell>
<Cell>{showHex(ei.device_id as number, 2)}</Cell> {ei.name}&nbsp;
<Cell>{showHex(ei.type_id as number, 3)}</Cell> {ei.writeable && <EditOutlinedIcon color="primary" sx={{ fontSize: 12 }} />}
<Cell>{ei.offset}</Cell> </Cell>
<Cell>{DeviceValueTypeNames[ei.value_type]}</Cell> <Cell>{ei.ram === 1 ? '' : showHex(ei.device_id as number, 2)}</Cell>
<Cell>{ei.ram === 1 ? '' : showHex(ei.type_id as number, 3)}</Cell>
<Cell>{ei.ram === 1 ? '' : ei.offset}</Cell>
<Cell>{ei.ram === 1 ? 'RAM' : DeviceValueTypeNames[ei.value_type]}</Cell>
<Cell>{formatValue(ei.value, ei.uom)}</Cell> <Cell>{formatValue(ei.value, ei.uom)}</Cell>
</Row> </Row>
))} ))}
@@ -244,7 +255,7 @@ const SettingsEntities: FC = () => {
{renderEntity()} {renderEntity()}
{selectedEntityItem && ( {selectedEntityItem && (
<SettingsEntitiesDialog <SettingsCustomEntitiesDialog
open={dialogOpen} open={dialogOpen}
creating={creating} creating={creating}
onClose={onDialogClose} onClose={onDialogClose}
@@ -274,7 +285,10 @@ const SettingsEntities: FC = () => {
</Box> </Box>
<Box flexWrap="nowrap" whiteSpace="nowrap"> <Box flexWrap="nowrap" whiteSpace="nowrap">
<ButtonRow> <ButtonRow>
<Button startIcon={<AddIcon />} variant="outlined" color="secondary" onClick={addEntityItem}> <Button startIcon={<RefreshIcon />} variant="outlined" color="secondary" onClick={fetchEntities}>
{LL.REFRESH()}
</Button>
<Button startIcon={<AddIcon />} variant="outlined" color="primary" onClick={addEntityItem}>
{LL.ADD(0)} {LL.ADD(0)}
</Button> </Button>
</ButtonRow> </ButtonRow>
@@ -284,4 +298,4 @@ const SettingsEntities: FC = () => {
); );
}; };
export default SettingsEntities; export default SettingsCustomEntities;

View File

@@ -30,7 +30,7 @@ import { useI18nContext } from 'i18n/i18n-react';
import { updateValue } from 'utils'; import { updateValue } from 'utils';
import { validate } from 'validators'; import { validate } from 'validators';
type SettingsEntitiesDialogProps = { type SettingsCustomEntitiesDialogProps = {
open: boolean; open: boolean;
creating: boolean; creating: boolean;
onClose: () => void; onClose: () => void;
@@ -39,14 +39,14 @@ type SettingsEntitiesDialogProps = {
validator: Schema; validator: Schema;
}; };
const SettingsEntitiesDialog = ({ const SettingsCustomEntitiesDialog = ({
open, open,
creating, creating,
onClose, onClose,
onSave, onSave,
selectedItem, selectedItem,
validator validator
}: SettingsEntitiesDialogProps) => { }: SettingsCustomEntitiesDialogProps) => {
const { LL } = useI18nContext(); const { LL } = useI18nContext();
const [editItem, setEditItem] = useState<EntityItem>(selectedItem); const [editItem, setEditItem] = useState<EntityItem>(selectedItem);
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>(); const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();
@@ -100,7 +100,7 @@ const SettingsEntitiesDialog = ({
<Box flexWrap="nowrap" whiteSpace="nowrap" /> <Box flexWrap="nowrap" whiteSpace="nowrap" />
</Box> </Box>
<Grid container spacing={2}> <Grid container spacing={2}>
<Grid item xs={8}> <Grid item xs={4}>
<ValidatedTextField <ValidatedTextField
fieldErrors={fieldErrors} fieldErrors={fieldErrors}
name="name" name="name"
@@ -111,6 +111,36 @@ const SettingsEntitiesDialog = ({
onChange={updateFormValue} onChange={updateFormValue}
/> />
</Grid> </Grid>
<Grid item xs={4}>
<TextField
name="ram"
label={LL.VALUE(1) + ' ' + LL.TYPE(1)}
value={editItem.ram}
variant="outlined"
onChange={updateFormValue}
margin="normal"
fullWidth
select
>
<MenuItem value={0}>EMS-{LL.VALUE(1)}</MenuItem>
<MenuItem value={1}>RAM-{LL.VALUE(1)}</MenuItem>
</TextField>
</Grid>
{editItem.ram === 1 && (
<Grid item xs={4}>
<TextField
name="value"
label={LL.STARTVALUE()}
value={editItem.value}
variant="outlined"
onChange={updateFormValue}
fullWidth
margin="normal"
/>
</Grid>
)}
{editItem.ram === 0 && (
<>
<Grid item xs={4} mt={3}> <Grid item xs={4} mt={3}>
<BlockFormControlLabel <BlockFormControlLabel
control={<Checkbox checked={editItem.writeable} onChange={updateFormValue} name="writeable" />} control={<Checkbox checked={editItem.writeable} onChange={updateFormValue} name="writeable" />}
@@ -212,7 +242,7 @@ const SettingsEntitiesDialog = ({
</Grid> </Grid>
</> </>
)} )}
{editItem.value_type === DeviceValueType.STRING && ( {editItem.value_type === DeviceValueType.STRING && editItem.device_id !== '0' && (
<Grid item xs={4}> <Grid item xs={4}>
<TextField <TextField
name="factor" name="factor"
@@ -227,6 +257,8 @@ const SettingsEntitiesDialog = ({
/> />
</Grid> </Grid>
)} )}
</>
)}
</Grid> </Grid>
</DialogContent> </DialogContent>
@@ -249,4 +281,4 @@ const SettingsEntitiesDialog = ({
); );
}; };
export default SettingsEntitiesDialog; export default SettingsCustomEntitiesDialog;

View File

@@ -210,7 +210,7 @@ const SettingsSchedulerDialog = ({
/> />
<TextField <TextField
name="value" name="value"
label={LL.VALUE(0)} label={LL.VALUE(1)}
multiline multiline
margin="normal" margin="normal"
fullWidth fullWidth

View File

@@ -20,7 +20,7 @@ export const readCoreData = () => alovaInstance.Get<CoreData>(`/rest/coreData`);
export const readDeviceData = (id: number) => export const readDeviceData = (id: number) =>
alovaInstance.Get<DeviceData>('/rest/deviceData', { alovaInstance.Get<DeviceData>('/rest/deviceData', {
// alovaInstance.Get<DeviceData>(`/rest/deviceData/${id}`, { // alovaInstance.Get<DeviceData>(`/rest/deviceData/${id}`, {
params: { id }, // TODO remove later params: { id }, // TODO replace later
responseType: 'arraybuffer' // uses msgpack responseType: 'arraybuffer' // uses msgpack
}); });
export const writeDeviceValue = (data: any) => alovaInstance.Post('/rest/writeDeviceValue', data); export const writeDeviceValue = (data: any) => alovaInstance.Post('/rest/writeDeviceValue', data);
@@ -56,7 +56,7 @@ export const getSchedule = () => alovaInstance.Get('/rest/getSchedule');
export const readDeviceEntities = (id: number) => export const readDeviceEntities = (id: number) =>
// alovaInstance.Get<DeviceEntity[]>(`/rest/deviceEntities/${id}`, { // alovaInstance.Get<DeviceEntity[]>(`/rest/deviceEntities/${id}`, {
alovaInstance.Get<DeviceEntity[]>(`/rest/deviceEntities`, { alovaInstance.Get<DeviceEntity[]>(`/rest/deviceEntities`, {
params: { id }, // TODO remove later params: { id }, // TODO replace later
responseType: 'arraybuffer', responseType: 'arraybuffer',
transformData(data: any) { transformData(data: any) {
return data.map((de: DeviceEntity) => ({ ...de, o_m: de.m, o_cn: de.cn, o_mi: de.mi, o_ma: de.ma })); return data.map((de: DeviceEntity) => ({ ...de, o_m: de.m, o_cn: de.cn, o_mi: de.mi, o_ma: de.ma }));
@@ -88,7 +88,7 @@ export const writeSchedule = (data: any) => alovaInstance.Post('/rest/schedule',
// SettingsEntities // SettingsEntities
export const readCustomEntities = () => export const readCustomEntities = () =>
alovaInstance.Get<EntityItem[]>('/rest/customentities', { alovaInstance.Get<EntityItem[]>('/rest/customEntities', {
name: 'entities', name: 'entities',
transformData(data: any) { transformData(data: any) {
return data.entities.map((ei: EntityItem) => ({ return data.entities.map((ei: EntityItem) => ({
@@ -106,4 +106,4 @@ export const readCustomEntities = () =>
})); }));
} }
}); });
export const writeCustomEntities = (data: any) => alovaInstance.Post('/rest/customentities', data); export const writeCustomEntities = (data: any) => alovaInstance.Post('/rest/customEntities', data);

View File

@@ -177,7 +177,8 @@ export enum DeviceValueUOM {
L, L,
KMIN, KMIN,
K, K,
VOLTS VOLTS,
MBAR
} }
export const DeviceValueUOM_s = [ export const DeviceValueUOM_s = [
@@ -204,7 +205,8 @@ export const DeviceValueUOM_s = [
'l', 'l',
'K*min', 'K*min',
'K', 'K',
'V' 'V',
'mbar'
]; ];
export enum AnalogType { export enum AnalogType {
@@ -223,12 +225,12 @@ export enum AnalogType {
export const AnalogTypeNames = [ export const AnalogTypeNames = [
'(disabled)', '(disabled)',
'Digital in', 'Digital In',
'Counter', 'Counter',
'ADC', 'ADC',
'Timer', 'Timer',
'Rate', 'Rate',
'Digital out', 'Digital Out',
'PWM 0', 'PWM 0',
'PWM 1', 'PWM 1',
'PWM 2' 'PWM 2'
@@ -323,6 +325,7 @@ export enum ScheduleFlag {
export interface EntityItem { export interface EntityItem {
id: number; // unique number id: number; // unique number
ram: number;
name: string; name: string;
device_id: number | string; device_id: number | string;
type_id: number | string; type_id: number | string;
@@ -334,6 +337,7 @@ export interface EntityItem {
writeable: boolean; writeable: boolean;
deleted?: boolean; deleted?: boolean;
o_id?: number; o_id?: number;
o_ram?: number;
o_name?: string; o_name?: string;
o_device_id?: number | string; o_device_id?: number | string;
o_type_id?: number | string; o_type_id?: number | string;
@@ -343,6 +347,7 @@ export interface EntityItem {
o_value_type?: number; o_value_type?: number;
o_deleted?: boolean; o_deleted?: boolean;
o_writeable?: boolean; o_writeable?: boolean;
o_value?: any;
} }
export interface Entities { export interface Entities {
@@ -398,6 +403,6 @@ export const DeviceValueTypeNames = [
'ULONG', 'ULONG',
'TIME', 'TIME',
'ENUM', 'ENUM',
'STRING', 'RAW',
'CMD' 'CMD'
]; ];

View File

@@ -33,6 +33,7 @@ export interface NetworkStatus {
gateway_ip: string; gateway_ip: string;
dns_ip_1: string; dns_ip_1: string;
dns_ip_2: string; dns_ip_2: string;
hostname: string;
} }
export interface NetworkSettings { export interface NetworkSettings {

View File

@@ -9,7 +9,6 @@ export interface NTPStatus {
utc_time: string; utc_time: string;
local_time: string; local_time: string;
server: string; server: string;
uptime: number;
} }
export interface NTPSettings { export interface NTPSettings {

View File

@@ -1,91 +0,0 @@
import { debounce } from 'lodash-es';
import { useCallback, useEffect, useRef, useState } from 'react';
import Sockette from 'sockette';
import { addAccessTokenParameter } from 'api/authentication';
interface WebSocketIdMessage {
type: 'id';
id: string;
}
interface WebSocketPayloadMessage<D> {
type: 'payload';
origin_id: string;
payload: D;
}
export type WebSocketMessage<D> = WebSocketIdMessage | WebSocketPayloadMessage<D>;
export const useWs = <D>(wsUrl: string, wsThrottle = 100) => {
const ws = useRef<Sockette>();
const clientId = useRef<string>();
const [connected, setConnected] = useState<boolean>(false);
const [data, setData] = useState<D>();
const [transmit, setTransmit] = useState<boolean>();
const [clear, setClear] = useState<boolean>();
const onMessage = useCallback((event: MessageEvent) => {
const rawData = event.data;
if (typeof rawData === 'string' || rawData instanceof String) {
const message = JSON.parse(rawData as string) as WebSocketMessage<D>;
switch (message.type) {
case 'id':
clientId.current = message.id;
break;
case 'payload':
if (clientId.current) {
setData((existingData) => (clientId.current === message.origin_id && existingData) || message.payload);
}
break;
}
}
}, []);
const doSaveData = useCallback((newData: D, clearData = false) => {
if (!ws.current) {
return;
}
if (clearData) {
setData(undefined);
}
ws.current.json(newData);
}, []);
const saveData = useRef(debounce(doSaveData, wsThrottle));
const updateData = (newData: React.SetStateAction<D | undefined>, transmitData: true, clearData: false) => {
setData(newData);
setTransmit(transmitData);
setClear(clearData);
};
useEffect(() => {
if (!transmit) {
return;
}
data && saveData.current(data, clear);
setTransmit(false);
setClear(false);
}, [doSaveData, data, transmit, clear]);
useEffect(() => {
const instance = new Sockette(addAccessTokenParameter(wsUrl), {
onmessage: onMessage,
onopen: () => {
setConnected(true);
},
onclose: () => {
clientId.current = undefined;
setConnected(false);
setData(undefined);
}
});
ws.current = instance;
// eslint-disable-next-line @typescript-eslint/unbound-method
return instance.close;
}, [wsUrl, onMessage]);
return { connected, data, updateData } as const;
};

View File

@@ -1,4 +1,4 @@
import { defineConfig } from 'vite'; import { defineConfig, splitVendorChunkPlugin } from 'vite';
import viteTsconfigPaths from 'vite-tsconfig-paths'; import viteTsconfigPaths from 'vite-tsconfig-paths';
import preact from '@preact/preset-vite'; import preact from '@preact/preset-vite';
import viteImagemin from 'vite-plugin-imagemin'; import viteImagemin from 'vite-plugin-imagemin';
@@ -44,6 +44,7 @@ export default defineConfig(({ command, mode }) => {
plugins: [ plugins: [
preact(), preact(),
viteTsconfigPaths(), viteTsconfigPaths(),
splitVendorChunkPlugin(),
{ {
...viteImagemin({ ...viteImagemin({
verbose: false, verbose: false,
@@ -112,6 +113,20 @@ export default defineConfig(({ command, mode }) => {
nameCache: null, nameCache: null,
safari10: false, safari10: false,
toplevel: false toplevel: false
},
rollupOptions: {
output: {
manualChunks(id: string) {
if (id.includes('node_modules')) {
// creating a chunk to react routes deps. Reducing the vendor chunk size
if (id.includes('react-router-dom') || id.includes('@remix-run') || id.includes('react-router')) {
return '@react-router';
}
return 'vendor';
}
}
}
} }
} }
}; };

View File

@@ -12,10 +12,10 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@alova/adapter-xhr@npm:^1.0.2": "@alova/adapter-xhr@npm:^1.0.3":
version: 1.0.2 version: 1.0.3
resolution: "@alova/adapter-xhr@npm:1.0.2" resolution: "@alova/adapter-xhr@npm:1.0.3"
checksum: a57d178e89e3b655191bebccbc34d22760813b97b430e16f77b6ad561e3bb4ad8a34948aa2d724f5833d675f21a337ab769a3e5f73878430c3139374c6afb6ea checksum: 53923b0b7f833bbbda662ad28f29bb8226d2126ab7dcc57c9aa5486212cb02f0cfa19760d33ab63334688458138fc3c4713084c2f6a558c969d83efda7828601
languageName: node languageName: node
linkType: hard linkType: hard
@@ -401,12 +401,12 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@babel/runtime@npm:^7.23.6": "@babel/runtime@npm:^7.23.8":
version: 7.23.6 version: 7.23.8
resolution: "@babel/runtime@npm:7.23.6" resolution: "@babel/runtime@npm:7.23.8"
dependencies: dependencies:
regenerator-runtime: "npm:^0.14.0" regenerator-runtime: "npm:^0.14.0"
checksum: 4c4ab16f0361c59fb23956e4d0a29935f1f8a64aa8dd37876ce38355b6f4d8f0e54237aacb89c73b1532def60539ddde2d651523c8fa887b30b19a8cf0c465b0 checksum: ec8f1967a36164da6cac868533ffdff97badd76d23d7d820cc84f0818864accef972f22f9c6a710185db1e3810e353fc18c3da721e5bb3ee8bc61bdbabce03ff
languageName: node languageName: node
linkType: hard linkType: hard
@@ -841,41 +841,41 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@floating-ui/core@npm:^1.4.2": "@floating-ui/core@npm:^1.5.3":
version: 1.5.0
resolution: "@floating-ui/core@npm:1.5.0"
dependencies:
"@floating-ui/utils": "npm:^0.1.3"
checksum: 3182715a30493f44a32158f4d77ab5b6c212064b160cb84b5b8405ec2845bd8a9167c25292709e841cad9e70c6b9efdc30f876044e3b0909139fea8eca00c631
languageName: node
linkType: hard
"@floating-ui/dom@npm:^1.5.1":
version: 1.5.3 version: 1.5.3
resolution: "@floating-ui/dom@npm:1.5.3" resolution: "@floating-ui/core@npm:1.5.3"
dependencies: dependencies:
"@floating-ui/core": "npm:^1.4.2" "@floating-ui/utils": "npm:^0.2.0"
"@floating-ui/utils": "npm:^0.1.3" checksum: 7d9feaca2565a2a71bf03d23cd292c03def63097d7fde7d62909cdb8ddb84664781f3922086bcf10443f3310cb92381a0ecf745b2774edb917fa74fe61015c56
checksum: d2d5ae7a0949c0ebf7fbf97a21612bf94dbd29cb6c847e00588b8e2a5575ade27c47cb19f5d230fc21a571d99aa0c714b301c9221d33921047408c0ed9d91a30
languageName: node languageName: node
linkType: hard linkType: hard
"@floating-ui/react-dom@npm:^2.0.4": "@floating-ui/dom@npm:^1.5.4":
version: 2.0.4 version: 1.5.4
resolution: "@floating-ui/react-dom@npm:2.0.4" resolution: "@floating-ui/dom@npm:1.5.4"
dependencies: dependencies:
"@floating-ui/dom": "npm:^1.5.1" "@floating-ui/core": "npm:^1.5.3"
"@floating-ui/utils": "npm:^0.2.0"
checksum: 3ba02ba2b4227c1e18df6ccdd029a1c100058db2e76ca1dac60a593ec72b2d4d995fa5c2d1639a5c38adb17e12398fbfe4f6cf5fd45f2ee6170ed0cf64acea06
languageName: node
linkType: hard
"@floating-ui/react-dom@npm:^2.0.5":
version: 2.0.5
resolution: "@floating-ui/react-dom@npm:2.0.5"
dependencies:
"@floating-ui/dom": "npm:^1.5.4"
peerDependencies: peerDependencies:
react: ">=16.8.0" react: ">=16.8.0"
react-dom: ">=16.8.0" react-dom: ">=16.8.0"
checksum: 4240a718502c797fd2e174cd06dcd7321a6eda9c8966dbaf61864b9e16445e95649a59bfe7c19ee13f68c11f3693724d7970c7e618089a3d3915bd343639cfae checksum: b4fc008c725149b9565949184d844c914a8fa2687636c3c1166a1d52ca58537b3ba9b0a0e2945cf424662c846e60b173df0d325af7e700a31550e5e0b346070a
languageName: node languageName: node
linkType: hard linkType: hard
"@floating-ui/utils@npm:^0.1.3": "@floating-ui/utils@npm:^0.2.0":
version: 0.1.6 version: 0.2.1
resolution: "@floating-ui/utils@npm:0.1.6" resolution: "@floating-ui/utils@npm:0.2.1"
checksum: 450ec4ecc1dd8161b1904d4e1e9d95e653cc06f79af6c3b538b79efb10541d90bcc88646ab3cdffc5b92e00c4804ca727b025d153ad285f42dbbb39aec219ec9 checksum: 33c9ab346e7b05c5a1e6a95bc902aafcfc2c9d513a147e2491468843bd5607531b06d0b9aa56aa491cbf22a6c2495c18ccfc4c0344baec54a689a7bb8e4898d6
languageName: node languageName: node
linkType: hard linkType: hard
@@ -970,16 +970,16 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@mui/base@npm:5.0.0-beta.30": "@mui/base@npm:5.0.0-beta.32":
version: 5.0.0-beta.30 version: 5.0.0-beta.32
resolution: "@mui/base@npm:5.0.0-beta.30" resolution: "@mui/base@npm:5.0.0-beta.32"
dependencies: dependencies:
"@babel/runtime": "npm:^7.23.6" "@babel/runtime": "npm:^7.23.8"
"@floating-ui/react-dom": "npm:^2.0.4" "@floating-ui/react-dom": "npm:^2.0.5"
"@mui/types": "npm:^7.2.12" "@mui/types": "npm:^7.2.13"
"@mui/utils": "npm:^5.15.3" "@mui/utils": "npm:^5.15.5"
"@popperjs/core": "npm:^2.11.8" "@popperjs/core": "npm:^2.11.8"
clsx: "npm:^2.0.0" clsx: "npm:^2.1.0"
prop-types: "npm:^15.8.1" prop-types: "npm:^15.8.1"
peerDependencies: peerDependencies:
"@types/react": ^17.0.0 || ^18.0.0 "@types/react": ^17.0.0 || ^18.0.0
@@ -988,22 +988,22 @@ __metadata:
peerDependenciesMeta: peerDependenciesMeta:
"@types/react": "@types/react":
optional: true optional: true
checksum: 55e18d59ac96f5bbfbfdadd907751f5e6a4f74f611b5e99fe5f8002c76fa117b62c159f52ea0f12574a66460d62734082438cff19cb73e3fca9dc22f82f6eaf2 checksum: c88cd8a412ecaeaf0040e20708b2a607b9594a4462449ad06b90e96465aad0dada23295f801ed72851025fd023ababc410b6a48fcb69d7cdef90b55e62aa9a11
languageName: node languageName: node
linkType: hard linkType: hard
"@mui/core-downloads-tracker@npm:^5.15.3": "@mui/core-downloads-tracker@npm:^5.15.5":
version: 5.15.3 version: 5.15.5
resolution: "@mui/core-downloads-tracker@npm:5.15.3" resolution: "@mui/core-downloads-tracker@npm:5.15.5"
checksum: 002451af1aa555c0163c0ffacde5c15062e0ae0f30b81945e1a0befe7b6c5d14924a2b068b7b5f713c177ee3eecca4fc250d590d11206a6b5465700c399a34d1 checksum: 4c9b1281ebe8d17d402e22f7f50c347c0b3918b1ed17af721f4de5ce282d90bc6d90fe9730595998b2bbb2f7ebe57fc55d4c858f31754fccdb606af472a59dc8
languageName: node languageName: node
linkType: hard linkType: hard
"@mui/icons-material@npm:^5.15.3": "@mui/icons-material@npm:^5.15.5":
version: 5.15.3 version: 5.15.5
resolution: "@mui/icons-material@npm:5.15.3" resolution: "@mui/icons-material@npm:5.15.5"
dependencies: dependencies:
"@babel/runtime": "npm:^7.23.6" "@babel/runtime": "npm:^7.23.8"
peerDependencies: peerDependencies:
"@mui/material": ^5.0.0 "@mui/material": ^5.0.0
"@types/react": ^17.0.0 || ^18.0.0 "@types/react": ^17.0.0 || ^18.0.0
@@ -1011,22 +1011,22 @@ __metadata:
peerDependenciesMeta: peerDependenciesMeta:
"@types/react": "@types/react":
optional: true optional: true
checksum: 2393a9dcd0834cdda728b8ebca5d8f6acbfc34316346aaea257e32961abf7cf578419df196b50223b89b3e2556098aea283786ca4eeedaf58be3d204f499f6bc checksum: 25feb86a76ce83c81391c95d0c1c867e988cc7bc1b5a05c5698b71cb3cd1005fd148b07c2fa8908cda9fc4e44ea8b6e0fd2197bc0abafac0ee4880b477852eea
languageName: node languageName: node
linkType: hard linkType: hard
"@mui/material@npm:^5.15.3": "@mui/material@npm:^5.15.5":
version: 5.15.3 version: 5.15.5
resolution: "@mui/material@npm:5.15.3" resolution: "@mui/material@npm:5.15.5"
dependencies: dependencies:
"@babel/runtime": "npm:^7.23.6" "@babel/runtime": "npm:^7.23.8"
"@mui/base": "npm:5.0.0-beta.30" "@mui/base": "npm:5.0.0-beta.32"
"@mui/core-downloads-tracker": "npm:^5.15.3" "@mui/core-downloads-tracker": "npm:^5.15.5"
"@mui/system": "npm:^5.15.3" "@mui/system": "npm:^5.15.5"
"@mui/types": "npm:^7.2.12" "@mui/types": "npm:^7.2.13"
"@mui/utils": "npm:^5.15.3" "@mui/utils": "npm:^5.15.5"
"@types/react-transition-group": "npm:^4.4.10" "@types/react-transition-group": "npm:^4.4.10"
clsx: "npm:^2.0.0" clsx: "npm:^2.1.0"
csstype: "npm:^3.1.2" csstype: "npm:^3.1.2"
prop-types: "npm:^15.8.1" prop-types: "npm:^15.8.1"
react-is: "npm:^18.2.0" react-is: "npm:^18.2.0"
@@ -1044,16 +1044,16 @@ __metadata:
optional: true optional: true
"@types/react": "@types/react":
optional: true optional: true
checksum: fe8d318aed036b649a82e4833254f833ece028b6a25cec001991e6864d9e520752df6a746b6ca856c0310cc9aae16697aa77ddf53a85c889bb5d04c5aa5c1dcb checksum: 2a094d94acfc8f945b6cc73b295799f3174d7292707230e9b9486d810990561778f5f228f2fdc13a064ae234d528fb28c9b53f6c487ca43e65dc17460886165c
languageName: node languageName: node
linkType: hard linkType: hard
"@mui/private-theming@npm:^5.15.3": "@mui/private-theming@npm:^5.15.5":
version: 5.15.3 version: 5.15.5
resolution: "@mui/private-theming@npm:5.15.3" resolution: "@mui/private-theming@npm:5.15.5"
dependencies: dependencies:
"@babel/runtime": "npm:^7.23.6" "@babel/runtime": "npm:^7.23.8"
"@mui/utils": "npm:^5.15.3" "@mui/utils": "npm:^5.15.5"
prop-types: "npm:^15.8.1" prop-types: "npm:^15.8.1"
peerDependencies: peerDependencies:
"@types/react": ^17.0.0 || ^18.0.0 "@types/react": ^17.0.0 || ^18.0.0
@@ -1061,15 +1061,15 @@ __metadata:
peerDependenciesMeta: peerDependenciesMeta:
"@types/react": "@types/react":
optional: true optional: true
checksum: 4404a7d9545974631b329f391df72fa54edb5aefa6d32d9656b200284613e8ea1bdd3d0add2abe7278f1343dd5cf7552c7e4d2aaf5593f292c7db3cd63ddff21 checksum: 1b26bc897417dcd91bbc65af3584c3cdf6704e9beb707c97bb7977962536213d7c7bf8e1004cbe86a19625ed5feba82d3ad2997e943138ed36114a8a36bf0fed
languageName: node languageName: node
linkType: hard linkType: hard
"@mui/styled-engine@npm:^5.15.3": "@mui/styled-engine@npm:^5.15.5":
version: 5.15.3 version: 5.15.5
resolution: "@mui/styled-engine@npm:5.15.3" resolution: "@mui/styled-engine@npm:5.15.5"
dependencies: dependencies:
"@babel/runtime": "npm:^7.23.6" "@babel/runtime": "npm:^7.23.8"
"@emotion/cache": "npm:^11.11.0" "@emotion/cache": "npm:^11.11.0"
csstype: "npm:^3.1.2" csstype: "npm:^3.1.2"
prop-types: "npm:^15.8.1" prop-types: "npm:^15.8.1"
@@ -1082,20 +1082,20 @@ __metadata:
optional: true optional: true
"@emotion/styled": "@emotion/styled":
optional: true optional: true
checksum: 6775f92cda9f17428baf5b95e5849f31eead92485e332902ff29bd49bd03fbe2f5e762ebcdd122f7f31e102ec42cda29cbb5fdef79f5d03f416705d119b69e75 checksum: 10e38ed39f7defc26d7e14e9634afcd9d540eaa1b9aeb957a6d1154a14a3cca2843e9aa7ead126604728bbf2125203c1f157059c06b397ed0278fc4b7cfae5c5
languageName: node languageName: node
linkType: hard linkType: hard
"@mui/system@npm:^5.15.3": "@mui/system@npm:^5.15.5":
version: 5.15.3 version: 5.15.5
resolution: "@mui/system@npm:5.15.3" resolution: "@mui/system@npm:5.15.5"
dependencies: dependencies:
"@babel/runtime": "npm:^7.23.6" "@babel/runtime": "npm:^7.23.8"
"@mui/private-theming": "npm:^5.15.3" "@mui/private-theming": "npm:^5.15.5"
"@mui/styled-engine": "npm:^5.15.3" "@mui/styled-engine": "npm:^5.15.5"
"@mui/types": "npm:^7.2.12" "@mui/types": "npm:^7.2.13"
"@mui/utils": "npm:^5.15.3" "@mui/utils": "npm:^5.15.5"
clsx: "npm:^2.0.0" clsx: "npm:^2.1.0"
csstype: "npm:^3.1.2" csstype: "npm:^3.1.2"
prop-types: "npm:^15.8.1" prop-types: "npm:^15.8.1"
peerDependencies: peerDependencies:
@@ -1110,27 +1110,27 @@ __metadata:
optional: true optional: true
"@types/react": "@types/react":
optional: true optional: true
checksum: 7b71cad3c3b4f8136cf51a9e7040440073201618eaa5d0fcbd8830e3c3f35eb8a38303bb2bc9da84e0c95844193fdb4238af50e1f1d74a8e9fa79500a49c31db checksum: bc40858eff92efe1424b4de5782ca48ec0bccfe2de244b00af8f8607a7f47b5ec7006a0e369d1c52ddb3fe01d7666d1f7ed6d9a9070bee28dfa4ab2cecc4d015
languageName: node languageName: node
linkType: hard linkType: hard
"@mui/types@npm:^7.2.12": "@mui/types@npm:^7.2.13":
version: 7.2.12 version: 7.2.13
resolution: "@mui/types@npm:7.2.12" resolution: "@mui/types@npm:7.2.13"
peerDependencies: peerDependencies:
"@types/react": ^17.0.0 || ^18.0.0 "@types/react": ^17.0.0 || ^18.0.0
peerDependenciesMeta: peerDependenciesMeta:
"@types/react": "@types/react":
optional: true optional: true
checksum: 7d3ef53fee7eddc063d2083dc129f7d6d38b472a9196c3522fc5a75e66849fbf2b824be3f6aee11dc02c4475864e544026e6051ffb9d33f5dc1fc2a2279a8b72 checksum: a35bff025f715073329bd7cbe11ef4ce331ea377adffc0c5cd264bea47283590ce928d1fdbbc27506d1d462151325c81e71f2378ac4335feef3042010bbf3fcd
languageName: node languageName: node
linkType: hard linkType: hard
"@mui/utils@npm:^5.15.3": "@mui/utils@npm:^5.15.5":
version: 5.15.3 version: 5.15.5
resolution: "@mui/utils@npm:5.15.3" resolution: "@mui/utils@npm:5.15.5"
dependencies: dependencies:
"@babel/runtime": "npm:^7.23.6" "@babel/runtime": "npm:^7.23.8"
"@types/prop-types": "npm:^15.7.11" "@types/prop-types": "npm:^15.7.11"
prop-types: "npm:^15.8.1" prop-types: "npm:^15.8.1"
react-is: "npm:^18.2.0" react-is: "npm:^18.2.0"
@@ -1140,7 +1140,7 @@ __metadata:
peerDependenciesMeta: peerDependenciesMeta:
"@types/react": "@types/react":
optional: true optional: true
checksum: c4d66e34332f448527c6dea66a7011f95dc230ccaf5a3ee898a6fd69b77a3584af1fd644d095dc7edb2d480e5c050db06f9b9ec9dea3bc5091a80cf8b676f709 checksum: c8ff39a23ec540c6fd6495e44df6dc5531afca535cbb605f81cd5ef66af946e6c6415290caade8cfa0f61ecfb55703d8065c4968530c0b54c52d44f23a04cbfe
languageName: node languageName: node
linkType: hard linkType: hard
@@ -1277,10 +1277,10 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@remix-run/router@npm:1.14.1": "@remix-run/router@npm:1.14.2":
version: 1.14.1 version: 1.14.2
resolution: "@remix-run/router@npm:1.14.1" resolution: "@remix-run/router@npm:1.14.2"
checksum: caed61639006444a66ca832f1e500bac2fcf02695183e967ff1452d3172f888f2bb40591b239c85f9003b9628383cfd4c8ef55cde800d14276905c7031c9f0b9 checksum: 422844e88b985f1e287301b302c6cf8169c9eea792f80d40464f97b25393bb2e697228ebd7a7b61444d5a51c5873c4a637aad20acde5886a5caf62e833c5ceee
languageName: node languageName: node
linkType: hard linkType: hard
@@ -1568,12 +1568,12 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/node@npm:^20.10.6": "@types/node@npm:^20.11.5":
version: 20.10.6 version: 20.11.5
resolution: "@types/node@npm:20.10.6" resolution: "@types/node@npm:20.11.5"
dependencies: dependencies:
undici-types: "npm:~5.26.4" undici-types: "npm:~5.26.4"
checksum: 08471220d3cbbb6669835c4b78541edf5eface8f2c2e36c550cfa4ff73da73071c90e200a06359fac25d6564127597c23e178128058fb676824ec23d5178a017 checksum: 9f31c471047d7b3e240ce7b77ff29b0d15e83be7e3feafb3d0b0d0931122b438b1eefa302a5a2e1e9849914ff3fd76aafbd8ccb372efb1331ba048da63bce6f8
languageName: node languageName: node
linkType: hard linkType: hard
@@ -1648,14 +1648,14 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/react@npm:^18.2.46": "@types/react@npm:^18.2.48":
version: 18.2.46 version: 18.2.48
resolution: "@types/react@npm:18.2.46" resolution: "@types/react@npm:18.2.48"
dependencies: dependencies:
"@types/prop-types": "npm:*" "@types/prop-types": "npm:*"
"@types/scheduler": "npm:*" "@types/scheduler": "npm:*"
csstype: "npm:^3.0.2" csstype: "npm:^3.0.2"
checksum: 10fb28a5b8504106512ce3b154c45d1ac045c31633786773a29f003b3079b434060368bb56f95ef6c39510835ceec4fb8fdc271d6ca2b9cdd979379cf53f126b checksum: 2e56ea6bd821ae96bd943f727a59d85384eaf5f8a3e6fce4fa1d34453e32d8eedda742432b3857fa0de7a4214bf84ce4239757eb52918e76452c00384731e585
languageName: node languageName: node
linkType: hard linkType: hard
@@ -1691,15 +1691,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/eslint-plugin@npm:^6.17.0": "@typescript-eslint/eslint-plugin@npm:^6.19.0":
version: 6.17.0 version: 6.19.0
resolution: "@typescript-eslint/eslint-plugin@npm:6.17.0" resolution: "@typescript-eslint/eslint-plugin@npm:6.19.0"
dependencies: dependencies:
"@eslint-community/regexpp": "npm:^4.5.1" "@eslint-community/regexpp": "npm:^4.5.1"
"@typescript-eslint/scope-manager": "npm:6.17.0" "@typescript-eslint/scope-manager": "npm:6.19.0"
"@typescript-eslint/type-utils": "npm:6.17.0" "@typescript-eslint/type-utils": "npm:6.19.0"
"@typescript-eslint/utils": "npm:6.17.0" "@typescript-eslint/utils": "npm:6.19.0"
"@typescript-eslint/visitor-keys": "npm:6.17.0" "@typescript-eslint/visitor-keys": "npm:6.19.0"
debug: "npm:^4.3.4" debug: "npm:^4.3.4"
graphemer: "npm:^1.4.0" graphemer: "npm:^1.4.0"
ignore: "npm:^5.2.4" ignore: "npm:^5.2.4"
@@ -1712,44 +1712,44 @@ __metadata:
peerDependenciesMeta: peerDependenciesMeta:
typescript: typescript:
optional: true optional: true
checksum: f2a5774e9cc03e491a5a488501e5622c7eebd766f5a4fc2c30642864a3b89b0807946bde33a678f326ba7032f3f6a51aa0bf9c2d10adc823804fc9fb47db55a6 checksum: 5ed8483d792c4bc6ed697159c84a47ba5c35cd124949883813f2053b972537de3900a7ae26d4d6f370194f2cc7929baa2d09268e0b90118f20ed961cf6c176b9
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/parser@npm:^6.17.0": "@typescript-eslint/parser@npm:^6.19.0":
version: 6.17.0 version: 6.19.0
resolution: "@typescript-eslint/parser@npm:6.17.0" resolution: "@typescript-eslint/parser@npm:6.19.0"
dependencies: dependencies:
"@typescript-eslint/scope-manager": "npm:6.17.0" "@typescript-eslint/scope-manager": "npm:6.19.0"
"@typescript-eslint/types": "npm:6.17.0" "@typescript-eslint/types": "npm:6.19.0"
"@typescript-eslint/typescript-estree": "npm:6.17.0" "@typescript-eslint/typescript-estree": "npm:6.19.0"
"@typescript-eslint/visitor-keys": "npm:6.17.0" "@typescript-eslint/visitor-keys": "npm:6.19.0"
debug: "npm:^4.3.4" debug: "npm:^4.3.4"
peerDependencies: peerDependencies:
eslint: ^7.0.0 || ^8.0.0 eslint: ^7.0.0 || ^8.0.0
peerDependenciesMeta: peerDependenciesMeta:
typescript: typescript:
optional: true optional: true
checksum: 2ed0ed4a5b30e953430ce3279df3655af09fa1caed2abf11804d239717daefc32a22864f6620ef57bb9c684c74a99a13241384fea5096e961385e3678fc2e920 checksum: 0c6280a69127cf521b3403be9877775eecda2b2e4e44a67874b0d9cf82ed95a7971dac2db633e55ec22f8026da2681137110b2924313421a22b7c03eba8cda67
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/scope-manager@npm:6.17.0": "@typescript-eslint/scope-manager@npm:6.19.0":
version: 6.17.0 version: 6.19.0
resolution: "@typescript-eslint/scope-manager@npm:6.17.0" resolution: "@typescript-eslint/scope-manager@npm:6.19.0"
dependencies: dependencies:
"@typescript-eslint/types": "npm:6.17.0" "@typescript-eslint/types": "npm:6.19.0"
"@typescript-eslint/visitor-keys": "npm:6.17.0" "@typescript-eslint/visitor-keys": "npm:6.19.0"
checksum: fe09c628553c9336e6a36d32c1d34e78ebd20aa02130a6bf535329621ba5a98aaac171f607bc6e4d17b3478c42e7de6476376636897ce3f227c754eb99acd07e checksum: d36c51c05e14c51ce13181120eeea46d1edd59ed1ff16dc4ec1f5532a975b5faec5c10a373aaa90545f82a12330c6cba18ecedc734e18288f5874855c48ba808
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/type-utils@npm:6.17.0": "@typescript-eslint/type-utils@npm:6.19.0":
version: 6.17.0 version: 6.19.0
resolution: "@typescript-eslint/type-utils@npm:6.17.0" resolution: "@typescript-eslint/type-utils@npm:6.19.0"
dependencies: dependencies:
"@typescript-eslint/typescript-estree": "npm:6.17.0" "@typescript-eslint/typescript-estree": "npm:6.19.0"
"@typescript-eslint/utils": "npm:6.17.0" "@typescript-eslint/utils": "npm:6.19.0"
debug: "npm:^4.3.4" debug: "npm:^4.3.4"
ts-api-utils: "npm:^1.0.1" ts-api-utils: "npm:^1.0.1"
peerDependencies: peerDependencies:
@@ -1757,23 +1757,23 @@ __metadata:
peerDependenciesMeta: peerDependenciesMeta:
typescript: typescript:
optional: true optional: true
checksum: dc7938429193acfda61b7282197ec046039e2c4da41cdcddf4daaf300d10229e4e23bb0fcf0503b19c0b99a874849c8a9f5bb35ce106260f56a14106d2b41d8c checksum: f1f20ac28c03dd18546050b63ec0b0fd8c67780265ccb9ef566f16441c3de5deb2607a6046fefdebe8a43ac11fecdf0b009f8e5f70a3d15916d855be74b0f3bb
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/types@npm:6.17.0": "@typescript-eslint/types@npm:6.19.0":
version: 6.17.0 version: 6.19.0
resolution: "@typescript-eslint/types@npm:6.17.0" resolution: "@typescript-eslint/types@npm:6.19.0"
checksum: 87ab1b5a3270ab34b917c22a2fb90a9ad7d9f3b19d73a337bc9efbe65f924da13482c97e8ccbe3bd3d081aa96039eeff50de41c1da2a2128066429b931cdb21d checksum: 396ad2ad9f2d759dd87bc880a1ffc9d11fda04db8af9402abb4e8eccd58c01fa2d26e38b186526d0b457012f7c912e7afdab2a3798a73aa0ae34abaf50d617ae
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/typescript-estree@npm:6.17.0": "@typescript-eslint/typescript-estree@npm:6.19.0":
version: 6.17.0 version: 6.19.0
resolution: "@typescript-eslint/typescript-estree@npm:6.17.0" resolution: "@typescript-eslint/typescript-estree@npm:6.19.0"
dependencies: dependencies:
"@typescript-eslint/types": "npm:6.17.0" "@typescript-eslint/types": "npm:6.19.0"
"@typescript-eslint/visitor-keys": "npm:6.17.0" "@typescript-eslint/visitor-keys": "npm:6.19.0"
debug: "npm:^4.3.4" debug: "npm:^4.3.4"
globby: "npm:^11.1.0" globby: "npm:^11.1.0"
is-glob: "npm:^4.0.3" is-glob: "npm:^4.0.3"
@@ -1783,34 +1783,34 @@ __metadata:
peerDependenciesMeta: peerDependenciesMeta:
typescript: typescript:
optional: true optional: true
checksum: 1671b0d2f2fdf07074fb1e2524d61935cec173bd8db6e482cc5b2dcc77aed3ffa831396736ffa0ee2fdbddd8585ae9ca8d6c97bcaea1385b23907a1ec0508f83 checksum: 06e24bb145a302299a6cf86b36652bd4d7080c4e88517ebc24bdc137c57425a68db256ba628ce16b568bfec8020ae2a748ccee93e304efeded329cb3292b17bf
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/utils@npm:6.17.0": "@typescript-eslint/utils@npm:6.19.0":
version: 6.17.0 version: 6.19.0
resolution: "@typescript-eslint/utils@npm:6.17.0" resolution: "@typescript-eslint/utils@npm:6.19.0"
dependencies: dependencies:
"@eslint-community/eslint-utils": "npm:^4.4.0" "@eslint-community/eslint-utils": "npm:^4.4.0"
"@types/json-schema": "npm:^7.0.12" "@types/json-schema": "npm:^7.0.12"
"@types/semver": "npm:^7.5.0" "@types/semver": "npm:^7.5.0"
"@typescript-eslint/scope-manager": "npm:6.17.0" "@typescript-eslint/scope-manager": "npm:6.19.0"
"@typescript-eslint/types": "npm:6.17.0" "@typescript-eslint/types": "npm:6.19.0"
"@typescript-eslint/typescript-estree": "npm:6.17.0" "@typescript-eslint/typescript-estree": "npm:6.19.0"
semver: "npm:^7.5.4" semver: "npm:^7.5.4"
peerDependencies: peerDependencies:
eslint: ^7.0.0 || ^8.0.0 eslint: ^7.0.0 || ^8.0.0
checksum: 37c63afcf66124bf84808699997953b8c84a378aa2c490a771b611d82cdac8499c58fac8eeb8378528e97660b59563d99297bfec4b982cd68760b0ffe54aa714 checksum: 4080c36331204ffef9f218e29f43da767f17551fa4d3877c3d3b49194f7c7382dd9ae2124e7b5ebd47d5556946bb6ad195b47d7d215553efabacdebf81b9e74d
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/visitor-keys@npm:6.17.0": "@typescript-eslint/visitor-keys@npm:6.19.0":
version: 6.17.0 version: 6.19.0
resolution: "@typescript-eslint/visitor-keys@npm:6.17.0" resolution: "@typescript-eslint/visitor-keys@npm:6.19.0"
dependencies: dependencies:
"@typescript-eslint/types": "npm:6.17.0" "@typescript-eslint/types": "npm:6.19.0"
eslint-visitor-keys: "npm:^3.4.1" eslint-visitor-keys: "npm:^3.4.1"
checksum: a2aed0e1437fdab8858ab9c7c8e355f8b72a5fa4b0adc54f28b8a2bbc29d4bb93214968ee940f83d013d0a4b83d00cd4eeeb05fb4c2c7d0ead324c6793f7d6d4 checksum: 8d51c0b8d94c5df044fde958f62741cef55be97c6a3a16c47e4df9af7b2ff13aa1ee03ca5240777481dca53f3b7a9b00b329e50aff5e3ad829d96bc5f63ca2c3
languageName: node languageName: node
linkType: hard linkType: hard
@@ -1825,24 +1825,24 @@ __metadata:
version: 0.0.0-use.local version: 0.0.0-use.local
resolution: "EMS-ESP@workspace:." resolution: "EMS-ESP@workspace:."
dependencies: dependencies:
"@alova/adapter-xhr": "npm:^1.0.2" "@alova/adapter-xhr": "npm:^1.0.3"
"@babel/core": "npm:^7.23.7" "@babel/core": "npm:^7.23.7"
"@emotion/react": "npm:^11.11.3" "@emotion/react": "npm:^11.11.3"
"@emotion/styled": "npm:^11.11.0" "@emotion/styled": "npm:^11.11.0"
"@mui/icons-material": "npm:^5.15.3" "@mui/icons-material": "npm:^5.15.5"
"@mui/material": "npm:^5.15.3" "@mui/material": "npm:^5.15.5"
"@preact/compat": "npm:^17.1.2" "@preact/compat": "npm:^17.1.2"
"@preact/preset-vite": "npm:^2.8.1" "@preact/preset-vite": "npm:^2.8.1"
"@table-library/react-table-library": "npm:4.1.7" "@table-library/react-table-library": "npm:4.1.7"
"@types/imagemin": "npm:^8.0.5" "@types/imagemin": "npm:^8.0.5"
"@types/lodash-es": "npm:^4.17.12" "@types/lodash-es": "npm:^4.17.12"
"@types/node": "npm:^20.10.6" "@types/node": "npm:^20.11.5"
"@types/react": "npm:^18.2.46" "@types/react": "npm:^18.2.48"
"@types/react-dom": "npm:^18.2.18" "@types/react-dom": "npm:^18.2.18"
"@types/react-router-dom": "npm:^5.3.3" "@types/react-router-dom": "npm:^5.3.3"
"@typescript-eslint/eslint-plugin": "npm:^6.17.0" "@typescript-eslint/eslint-plugin": "npm:^6.19.0"
"@typescript-eslint/parser": "npm:^6.17.0" "@typescript-eslint/parser": "npm:^6.19.0"
alova: "npm:^2.16.2" alova: "npm:^2.17.0"
async-validator: "npm:^4.2.5" async-validator: "npm:^4.2.5"
concurrently: "npm:^8.2.2" concurrently: "npm:^8.2.2"
eslint: "npm:^8.56.0" eslint: "npm:^8.56.0"
@@ -1861,21 +1861,21 @@ __metadata:
lodash-es: "npm:^4.17.21" lodash-es: "npm:^4.17.21"
mime-types: "npm:^2.1.35" mime-types: "npm:^2.1.35"
preact: "npm:^10.19.3" preact: "npm:^10.19.3"
prettier: "npm:^3.1.1" prettier: "npm:^3.2.4"
react: "npm:latest" react: "npm:latest"
react-dom: "npm:latest" react-dom: "npm:latest"
react-dropzone: "npm:^14.2.3" react-dropzone: "npm:^14.2.3"
react-icons: "npm:^4.12.0" react-icons: "npm:^5.0.1"
react-router-dom: "npm:^6.21.1" react-router-dom: "npm:^6.21.3"
react-toastify: "npm:^9.1.3" react-toastify: "npm:^10.0.4"
rollup-plugin-visualizer: "npm:^5.12.0" rollup-plugin-visualizer: "npm:^5.12.0"
sockette: "npm:^2.0.6" sockette: "npm:^2.0.6"
terser: "npm:^5.26.0" terser: "npm:^5.27.0"
typesafe-i18n: "npm:^5.26.2" typesafe-i18n: "npm:^5.26.2"
typescript: "npm:^5.3.3" typescript: "npm:^5.3.3"
vite: "npm:^5.0.10" vite: "npm:^5.0.12"
vite-plugin-imagemin: "npm:^0.6.1" vite-plugin-imagemin: "npm:^0.6.1"
vite-tsconfig-paths: "npm:^4.2.3" vite-tsconfig-paths: "npm:^4.3.1"
languageName: unknown languageName: unknown
linkType: soft linkType: soft
@@ -1944,10 +1944,10 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"alova@npm:^2.16.2": "alova@npm:^2.17.0":
version: 2.16.2 version: 2.17.0
resolution: "alova@npm:2.16.2" resolution: "alova@npm:2.17.0"
checksum: 06fafddf380d4d8e8e5dd172ebcaa0bc229c76c11b2675cfb2c0ab884a36d4818159267adb14ec7a3cbe681464793085b0386d7741e6a6a732c764b14c8783a8 checksum: ff3bda492ac7dc8665403293644736ab90d7989a8479cfb2fa7fcab8fdb6e92b755851e5bcae07f55f5a5170c66c6486f047d19efb8ca39b6b3298717c3f50d7
languageName: node languageName: node
linkType: hard linkType: hard
@@ -2617,17 +2617,10 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"clsx@npm:^1.1.1": "clsx@npm:^2.1.0":
version: 1.2.1 version: 2.1.0
resolution: "clsx@npm:1.2.1" resolution: "clsx@npm:2.1.0"
checksum: 5ded6f61f15f1fa0350e691ccec43a28b12fb8e64c8e94715f2a937bc3722d4c3ed41d6e945c971fc4dcc2a7213a43323beaf2e1c28654af63ba70c9968a8643 checksum: 2e0ce7c3b6803d74fc8147c408f88e79245583202ac14abd9691e2aebb9f312de44270b79154320d10bb7804a9197869635d1291741084826cff20820f31542b
languageName: node
linkType: hard
"clsx@npm:^2.0.0":
version: 2.0.0
resolution: "clsx@npm:2.0.0"
checksum: 943766d1b02fee3538c871e56638d87f973fbc2d6291ce221215ea436fdecb9be97ad323f411839c2d52c45640c449b1a53fbfe7e8b3d529b4e263308b630c9a
languageName: node languageName: node
linkType: hard linkType: hard
@@ -7091,12 +7084,12 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"prettier@npm:^3.1.1": "prettier@npm:^3.2.4":
version: 3.1.1 version: 3.2.4
resolution: "prettier@npm:3.1.1" resolution: "prettier@npm:3.2.4"
bin: bin:
prettier: bin/prettier.cjs prettier: bin/prettier.cjs
checksum: 26a249f321b97d26c04483f1bf2eeb22e082a76f4222a2c922bebdc60111691aad4ec3979610e83942e0b956058ec361d9e9c81c185172264eb6db9aa678082b checksum: e2b735d0552501b3a7ac8bd3ba3b6de2920bb35bd4cd02d08cb9057ebe3e96d83b9a7e4b903d987b7530a50223b12c74d107c154337236ae2c68156ba1e65cd2
languageName: node languageName: node
linkType: hard linkType: hard
@@ -7202,12 +7195,12 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"react-icons@npm:^4.12.0": "react-icons@npm:^5.0.1":
version: 4.12.0 version: 5.0.1
resolution: "react-icons@npm:4.12.0" resolution: "react-icons@npm:5.0.1"
peerDependencies: peerDependencies:
react: "*" react: "*"
checksum: 5cc20509ca0b182f1e7bf42c271846c48f688c8922e2439f48728805adc93ba18476a13588cbe91ee43a2d03b2787e0dc0b5cc4b9c4e4ae3426f4464b3c1b734 checksum: c4458c643ae32a793ddebc5fa1235c7ec051be1b131205510e8199d15a4c89221a501f95a71fa21c2da93e8dd225290e2e24bb80abd3fb85801e43009e692098
languageName: node languageName: node
linkType: hard linkType: hard
@@ -7225,39 +7218,39 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"react-router-dom@npm:^6.21.1": "react-router-dom@npm:^6.21.3":
version: 6.21.1 version: 6.21.3
resolution: "react-router-dom@npm:6.21.1" resolution: "react-router-dom@npm:6.21.3"
dependencies: dependencies:
"@remix-run/router": "npm:1.14.1" "@remix-run/router": "npm:1.14.2"
react-router: "npm:6.21.1" react-router: "npm:6.21.3"
peerDependencies: peerDependencies:
react: ">=16.8" react: ">=16.8"
react-dom: ">=16.8" react-dom: ">=16.8"
checksum: 2d75bd889828fa5516ad076b44506656d826c365645e7079138cd0ef899db28a1b212f708a6c6e3b543ae11b96b2031f01201cc2fe1733dd4d9c5cbdd4d734ef checksum: 6e23e35d02e5c83847c8e47d7912d1f6c2c42a35f2317802031bdd993a8205468138a045ff34f67fe807fe9f7dc9d0995ee05bab25aedc0bf978e620ac132815
languageName: node languageName: node
linkType: hard linkType: hard
"react-router@npm:6.21.1": "react-router@npm:6.21.3":
version: 6.21.1 version: 6.21.3
resolution: "react-router@npm:6.21.1" resolution: "react-router@npm:6.21.3"
dependencies: dependencies:
"@remix-run/router": "npm:1.14.1" "@remix-run/router": "npm:1.14.2"
peerDependencies: peerDependencies:
react: ">=16.8" react: ">=16.8"
checksum: 1220cc75e0c915a26dde9dbb6509a8f0b0163d96e5ad591af91d9bb5a92a18401718f8d872a03d1cb366e7a6216c165a5cadd12375adf97943f37d7f5c487a90 checksum: 3d5107cfdb440519d84e6ad6d95454e3bf41ec97677b95f7b2a7f281f8ddf191b765cf1b599ead951f3cd33ed4429f140590d74a01cfdf835dc2f812023a978a
languageName: node languageName: node
linkType: hard linkType: hard
"react-toastify@npm:^9.1.3": "react-toastify@npm:^10.0.4":
version: 9.1.3 version: 10.0.4
resolution: "react-toastify@npm:9.1.3" resolution: "react-toastify@npm:10.0.4"
dependencies: dependencies:
clsx: "npm:^1.1.1" clsx: "npm:^2.1.0"
peerDependencies: peerDependencies:
react: ">=16" react: ">=16"
react-dom: ">=16" react-dom: ">=16"
checksum: 12667aa10e6cf3f74be2e3c704c2d5570dd7de66fff89ae38fbfab1122e9a9f632de1cb712fe44a9a60b8ecca7590578157cb4ca6c4e8105a8cf80936a94e181 checksum: 57f4d0032bf328381bdfeb78ab5efa988d425627a61ffa43b0caa184633a0ea44253a349d6b967247fa3d480ad82a2bbaa9063ce3f89be9550eb9b30398a6837
languageName: node languageName: node
linkType: hard linkType: hard
@@ -8345,9 +8338,9 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"terser@npm:^5.26.0": "terser@npm:^5.27.0":
version: 5.26.0 version: 5.27.0
resolution: "terser@npm:5.26.0" resolution: "terser@npm:5.27.0"
dependencies: dependencies:
"@jridgewell/source-map": "npm:^0.3.3" "@jridgewell/source-map": "npm:^0.3.3"
acorn: "npm:^8.8.2" acorn: "npm:^8.8.2"
@@ -8355,7 +8348,7 @@ __metadata:
source-map-support: "npm:~0.5.20" source-map-support: "npm:~0.5.20"
bin: bin:
terser: bin/terser terser: bin/terser
checksum: 0282c5c065cbfa1e725d5609b99579252bc20b83cd1d75e8ab8b46d5da2c9d0fcfc453a12624f2d2d4c1240bfa0017a90fcf1e3b88258e5842fca1b0b82be8d8 checksum: 9b2c5cb00747dea5994034ca064fb3cc7efc1be6b79a35247662d51ab43bdbe9cbf002bbf29170b5f3bd068c811d0212e22d94acd2cf0d8562687b96f1bffc9f
languageName: node languageName: node
linkType: hard linkType: hard
@@ -8444,17 +8437,17 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"tsconfck@npm:^2.1.0": "tsconfck@npm:^3.0.1":
version: 2.1.2 version: 3.0.1
resolution: "tsconfck@npm:2.1.2" resolution: "tsconfck@npm:3.0.1"
peerDependencies: peerDependencies:
typescript: ^4.3.5 || ^5.0.0 typescript: ^5.0.0
peerDependenciesMeta: peerDependenciesMeta:
typescript: typescript:
optional: true optional: true
bin: bin:
tsconfck: bin/tsconfck.js tsconfck: bin/tsconfck.js
checksum: 61df3b03b334a25eabb0a52e67a0c8d85770c631f2739db7703af8fdd102a2ebd598f1c851cc5fc6d6a59f2497a26c845be71c934ea16d838a3ff95a885034fb checksum: c5317404e2a809af31ad093f82365518a5856b2f342371991f729f42cab0def1b87dca8d22df3fb8c82acda7248710d4fb5030270db024c8000bc8272a3e6d58
languageName: node languageName: node
linkType: hard linkType: hard
@@ -8755,25 +8748,25 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"vite-tsconfig-paths@npm:^4.2.3": "vite-tsconfig-paths@npm:^4.3.1":
version: 4.2.3 version: 4.3.1
resolution: "vite-tsconfig-paths@npm:4.2.3" resolution: "vite-tsconfig-paths@npm:4.3.1"
dependencies: dependencies:
debug: "npm:^4.1.1" debug: "npm:^4.1.1"
globrex: "npm:^0.1.2" globrex: "npm:^0.1.2"
tsconfck: "npm:^2.1.0" tsconfck: "npm:^3.0.1"
peerDependencies: peerDependencies:
vite: "*" vite: "*"
peerDependenciesMeta: peerDependenciesMeta:
vite: vite:
optional: true optional: true
checksum: ba6abe5d18fc1c1e494e1f1d8a7db56445c2a40e15aadb5d47a9c66cc5372d6f69b94ff0b1e47b67659d6ecaeddebab0a9d11e40b1c3c36c0115800736a6c760 checksum: 1432f80750f5cbe181c265eb9fc2e9fff8b25a2858f176dc0a02311e3e826333526ee9c16bb0aaaa8555a417ea944d68a2e8225181215cd9502370f913eb3f79
languageName: node languageName: node
linkType: hard linkType: hard
"vite@npm:^5.0.10": "vite@npm:^5.0.12":
version: 5.0.10 version: 5.0.12
resolution: "vite@npm:5.0.10" resolution: "vite@npm:5.0.12"
dependencies: dependencies:
esbuild: "npm:^0.19.3" esbuild: "npm:^0.19.3"
fsevents: "npm:~2.3.3" fsevents: "npm:~2.3.3"
@@ -8807,7 +8800,7 @@ __metadata:
optional: true optional: true
bin: bin:
vite: bin/vite.js vite: bin/vite.js
checksum: 5421e9c7f8cf3152eace9a8b528269141635f367e5dc63c5f1fe2712a766d9757f8197733cf3f28be590afdd520130d38de90c955e6dba6edfa6f9056c1e5ea7 checksum: ed0bb26a0d0c8e1dae0b70af9e36adffd7e15d80297443fe4da762596dc81570bad7f0291f590a57c1553f5e435338d8c7ffc483bd9431a95c09d9ac90665fad
languageName: node languageName: node
linkType: hard linkType: hard

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#include "src/ArduinoJson.h" #include "src/ArduinoJson.h"

View File

@@ -1,854 +1,123 @@
ArduinoJson: change log ArduinoJson: change log
======================= =======================
v6.21.3 (2023-07-23) v7.0.2 (2024-01-19)
------- ------
* Fix compatibility with the Blynk libary (issue #1914) * Fix assertion `poolIndex < count_` after `JsonDocument::clear()` (issue #2034)
v7.0.1 (2024-01-10)
------
* Fix "no matching function" with `JsonObjectConst::operator[]` (issue #2019)
* Remove unused files in the PlatformIO package
* Fix `volatile bool` serialized as `1` or `0` instead of `true` or `false` (issue #2029)
v7.0.0 (2024-01-03)
------
* Remove `BasicJsonDocument`
* Remove `StaticJsonDocument`
* Add abstract `Allocator` class
* Merge `DynamicJsonDocument` with `JsonDocument`
* Remove `JSON_ARRAY_SIZE()`, `JSON_OBJECT_SIZE()`, and `JSON_STRING_SIZE()`
* Remove `ARDUINOJSON_ENABLE_STRING_DEDUPLICATION` (string deduplication cannot be disabled anymore)
* Remove `JsonDocument::capacity()`
* Store the strings in the heap
* Reference-count shared strings
* Always store `serialized("string")` by copy (#1915)
* Remove the zero-copy mode of `deserializeJson()` and `deserializeMsgPack()`
* Fix double lookup in `to<JsonVariant>()` * Fix double lookup in `to<JsonVariant>()`
* Fix double call to `size()` in `serializeMsgPack()` * Fix double call to `size()` in `serializeMsgPack()`
* Include `ARDUINOJSON_SLOT_OFFSET_SIZE` in the namespace name * Include `ARDUINOJSON_SLOT_OFFSET_SIZE` in the namespace name
* Remove `JsonVariant::shallowCopy()`
* `JsonDocument`'s capacity grows as needed, no need to pass it to the constructor anymore
* `JsonDocument`'s allocator is not monotonic anymore, removed values get recycled
* Show a link to the documentation when user passes an unsupported input type * Show a link to the documentation when user passes an unsupported input type
* Remove `JsonDocument::memoryUsage()`
v6.21.2 (2023-04-12) * Remove `JsonDocument::garbageCollect()`
------- * Add `deserializeJson(JsonVariant, ...)` and `deserializeMsgPack(JsonVariant, ...)` (#1226)
* Call `shrinkToFit()` in `deserializeJson()` and `deserializeMsgPack()`
* Fix compatibility with the Zephyr Project (issue #1905) * `serializeJson()` and `serializeMsgPack()` replace the content of `std::string` and `String` instead of appending to it
* Allow using PROGMEM outside of Arduino (issue #1903) * Replace `add()` with `add<T>()` (`add(T)` is still supported)
* Set default for `ARDUINOJSON_ENABLE_PROGMEM` to `1` on AVR * Remove `createNestedArray()` and `createNestedObject()` (use `to<JsonArray>()` and `to<JsonObject>()` instead)
v6.21.1 (2023-03-27)
-------
* Double speed of `DynamicJsonDocument::garbageCollect()`
* Fix compatibility with GCC 5.2 (issue #1897)
v6.21.0 (2023-03-14)
-------
* Drop support for C++98/C++03. Minimum required is C++11.
* Remove `ARDUINOJSON_NAMESPACE`; use `ArduinoJson` instead.
* Make string support generic (issue #1807)
v6.20.1 (2023-02-08)
-------
* Remove explicit exclusion of `as<char*>()` and `as<char>()` (issue #1860)
If you try to call them, you'll now get the same error message as any unsupported type.
You could also add a custom converter for `char*` and `char`.
v6.20.0 (2022-12-26)
-------
* Add `JsonVariant::shallowCopy()` (issue #1343)
* Fix `9.22337e+18 is outside the range of representable values of type 'long'`
* Fix comparison operators for `JsonArray`, `JsonArrayConst`, `JsonObject`, and `JsonObjectConst`
* Fix lax parsing of `true`, `false`, and `null` (issue #1781)
* Remove undocumented `accept()` functions
* Rename `addElement()` to `add()`
* Remove `getElement()`, `getOrAddElement()`, `getMember()`, and `getOrAddMember()`
* Remove undocumented `JsonDocument::data()` and `JsonDocument::memoryPool()`
* Remove undocumented `JsonArrayIterator::internal()` and `JsonObjectIterator::internal()`
* Rename things in `ARDUINOJSON_NAMESPACE` to match the public names
* Add documentation to most public symbols
* Remove support for naked `char` (was deprecated since 6.18.0)
> ### BREAKING CHANGES > ### BREAKING CHANGES
> >
> This release hides `JsonVariant`'s functions that were only intended for internal use. > As every major release, ArduinoJson 7 introduces several breaking changes.
> If you were using them in your programs, you must replace with `operator[]` and `to<JsonVariant>()`, like so: > I added some stubs so that most existing programs should compile, but I highty recommend you upgrade your code.
>
> #### `JsonDocument`
>
> In ArduinoJson 6, you could allocate the memory pool on the stack (with `StaticJsonDocument`) or in the heap (with `DynamicJsonDocument`).
> In ArduinoJson 7, the memory pool is always allocated in the heap, so `StaticJsonDocument` and `DynamicJsonDocument` have been merged into `JsonDocument`.
>
> In ArduinoJson 6, `JsonDocument` had a fixed capacity; in ArduinoJson 7, it has an elastic capacity that grows as needed.
> Therefore, you don't need to specify the capacity anymore, so the macros `JSON_ARRAY_SIZE()`, `JSON_OBJECT_SIZE()`, and `JSON_STRING_SIZE()` have been removed.
> >
> ```c++ > ```c++
> // before > // ArduinoJson 6
> JsonVariant a = variant.getElement(idx); > StaticJsonDocument<256> doc;
> JsonVariant b = variant.getOrAddElement(idx); > // or
> JsonVariant c = variant.getMember(key); > DynamicJsonDocument doc(256);
> JsonVariant d = variant.getOrAddMember(key);
> >
> // after > // ArduinoJson 7
> JsonVariant a = variant[idx]; > JsonDocument doc;
> JsonVariant b = idx < variant.size() ? variant[idx] : variant[idx].to<JsonVariant>();
> JsonVariant c = variant[key];
> JsonVariant d = variant.containsKey(key) ? variant[key] : variant[key].to<JsonVariant>();
> ```
v6.19.4 (2022-04-05)
-------
* Add `ElementProxy::memoryUsage()`
* Add `MemberProxy::memoryUsage()` (issue #1730)
* Add implicit conversion from `JsonDocument` to `JsonVariant`
* Fix comparisons operators with `const JsonDocument&`
v6.19.3 (2022-03-08)
-------
* Fix `call of overloaded 'String(const char*, int)' is ambiguous`
* Fix `JsonString` operator `==` and `!=` for non-zero-terminated string
* Fix `-Wsign-conversion` on GCC 8 (issue #1715)
* MessagePack: serialize round floats as integers (issue #1718)
v6.19.2 (2022-02-14)
-------
* Fix `cannot convert 'pgm_p' to 'const void*'` (issue #1707)
v6.19.1 (2022-01-14)
-------
* Fix crash when adding an object member in a too small `JsonDocument`
* Fix filter not working in zero-copy mode (issue #1697)
v6.19.0 (2022-01-08)
-------
* Remove `ARDUINOJSON_EMBEDDED_MODE` and assume we run on an embedded platform.
Dependent settings (like `ARDUINOJSON_DEFAULT_NESTING_LIMIT`) must be set individually.
* Change the default of `ARDUINOJSON_USE_DOUBLE` to `1`
* Change the default of `ARDUINOJSON_USE_LONG_LONG` to `1` on 32-bit platforms
* Add `as<JsonString>()` and `is<JsonString>()`
* Add safe bool idiom in `JsonString`
* Add support for NUL in string values (issue #1646)
* Add support for arbitrary array rank in `copyArray()`
* Add support for `char[][]` in `copyArray()`
* Remove `DeserializationError == bool` and `DeserializationError != bool`
* Renamed undocumented function `isUndefined()` to `isUnbound()`
* Fix `JsonVariant::memoryUsage()` for raw strings
* Fix `call of overloaded 'swap(BasicJsonDocument&, BasicJsonDocument&)' is ambiguous` (issue #1678)
* Fix inconsistent pool capacity between `BasicJsonDocument`'s copy and move constructors
* Fix inconsistent pool capacity between `BasicJsonDocument`'s copy and move assignments
* Fix return type of `StaticJsonDocument::operator=`
* Avoid pool reallocation in `BasicJsonDocument`'s copy assignment if capacity is the same
* Avoid including `Arduino.h` when all its features are disabled (issue #1692, PR #1693 by @paulocsanz)
* Assume `PROGMEM` is available as soon as `ARDUINO` is defined (consequence of #1693)
v6.18.5 (2021-09-28)
-------
* Set `ARDUINOJSON_EMBEDDED_MODE` to `1` on Nios II (issue #1657)
v6.18.4 (2021-09-06)
-------
* Fixed error `'dummy' may be used uninitialized` on GCC 11
* Fixed error `expected unqualified-id before 'const'` on GCC 11 (issue #1622)
* Filter: exact match takes precedence over wildcard (issue #1628)
* Fixed deserialization of `\u0000` (issue #1646)
v6.18.3 (2021-07-27)
-------
* Changed return type of `convertToJson()` and `Converter<T>::toJson()` to `void`
* Added `as<std::string_view>()` and `is<std::string_view>()`
v6.18.2 (2021-07-19)
-------
* Removed a symlink because the Arduino Library Specification forbids it
v6.18.1 (2021-07-03)
-------
* Fixed support for `volatile float` and `volatile double` (issue #1557)
* Fixed error `[Pe070]: incomplete type is not allowed` on IAR (issue #1560)
* Fixed `serializeJson(doc, String)` when allocation fails (issue #1572)
* Fixed clang-tidy warnings (issue #1574, PR #1577 by @armandas)
* Added fake class `InvalidConversion<T1,T2>` to easily identify invalid conversions (issue #1585)
* Added support for `std::string_view` (issue #1578, PR #1554 by @0xFEEDC0DE64)
* Fixed warning `definition of implicit copy constructor for 'MsgPackDeserializer' is deprecated because it has a user-declared copy assignment operator`
* Added `JsonArray::clear()` (issue #1597)
* Fixed `JsonVariant::as<unsigned>()` (issue #1601)
* Added support for ESP-IDF component build (PR #1562 by @qt1, PR #1599 by @andreaskuster)
v6.18.0 (2021-05-05)
-------
* Added support for custom converters (issue #687)
* Added support for `Printable` (issue #1444)
* Removed support for `char` values, see below (issue #1498)
* `deserializeJson()` leaves `\uXXXX` unchanged instead of returning `NotSupported`
* `deserializeMsgPack()` inserts `null` instead of returning `NotSupported`
* Removed `DeserializationError::NotSupported`
* Added `JsonVariant::is<JsonArrayConst/JsonObjectConst>()` (issue #1412)
* Added `JsonVariant::is<JsonVariant/JsonVariantConst>()` (issue #1412)
* Changed `JsonVariantConst::is<JsonArray/JsonObject>()` to return `false` (issue #1412)
* Simplified `JsonVariant::as<T>()` to always return `T` (see below)
* Updated folders list in `.mbedignore` (PR #1515 by @AGlass0fMilk)
* Fixed member-call-on-null-pointer in `getMember()` when array is empty
* `serializeMsgPack(doc, buffer, size)` doesn't add null-terminator anymore (issue #1545)
* `serializeJson(doc, buffer, size)` adds null-terminator only if there is enough room
* PlatformIO: set `build.libArchive` to `false` (PR #1550 by @askreet)
> ### BREAKING CHANGES
>
> #### Support for `char` removed
>
> We cannot cast a `JsonVariant` to a `char` anymore, so the following will break:
> ```c++
> char age = doc["age"]; // error: no matching function for call to 'variantAs(VariantData*&)'
> ```
> Instead, you must use another integral type, such as `int8_t`:
> ```c++
> int8_t age = doc["age"]; // OK
> ``` > ```
> >
> Similarly, we cannot assign from a `char` anymore, so the following will break: > In ArduinoJson 7, `JsonDocument` reuses released memory, so `garbageCollect()` has been removed.
> ```c++ > `shrinkToFit()` is still available and releases the over-allocated memory.
> char age;
> doc["age"] = age; // error: no matching function for call to 'VariantRef::set(const char&)'
> ```
> Instead, you must use another integral type, such as `int8_t`:
> ```c++
> int8_t age;
> doc["age"] = age; // OK
> ```
> A deprecation warning with the message "Support for `char` is deprecated, use `int8_t` or `uint8_t` instead" was added to allow a smooth transition.
> >
> #### `as<T>()` always returns `T` > Due to a change in the implementation, it's not possible to store a pointer to a variant from another `JsonDocument`, so `shallowCopy()` has been removed.
> >
> Previously, `JsonVariant::as<T>()` could return a type different from `T`. > In ArduinoJson 6, the meaning of `memoryUsage()` was clear: it returned the number of bytes used in the memory pool.
> The most common example is `as<char*>()` that returned a `const char*`. > In ArduinoJson 7, the meaning of `memoryUsage()` would be ambiguous, so it has been removed.
> While this feature simplified a few use cases, it was confusing and complicated the
> implementation of custom converters.
> >
> Starting from this version, `as<T>` doesn't try to auto-correct the return type and always return `T`, > #### Custom allocators
> which means that you cannot write this anymore: >
> In ArduinoJson 6, you could specify a custom allocator class as a template parameter of `BasicJsonDocument`.
> In ArduinoJson 7, you must inherit from `ArduinoJson::Allocator` and pass a pointer to an instance of your class to the constructor of `JsonDocument`.
> >
> ```c++ > ```c++
> Serial.println(doc["sensor"].as<char*>()); // error: invalid conversion from 'const char*' to 'char*' [-fpermissive] > // ArduinoJson 6
> class MyAllocator {
> // ...
> };
> BasicJsonDocument<MyAllocator> doc(256);
>
> // ArduinoJson 7
> class MyAllocator : public ArduinoJson::Allocator {
> // ...
> };
> MyAllocator myAllocator;
> JsonDocument doc(&myAllocator);
> ``` > ```
> >
> Instead, you must write: > #### `createNestedArray()` and `createNestedObject()`
>
> In ArduinoJson 6, you could create a nested array or object with `createNestedArray()` and `createNestedObject()`.
> In ArduinoJson 7, you must use `add<T>()` or `to<T>()` instead.
>
> For example, to create `[[],{}]`, you would write:
> >
> ```c++ > ```c++
> Serial.println(doc["sensor"].as<const char*>()); // OK > // ArduinoJson 6
> arr.createNestedArray();
> arr.createNestedObject();
>
> // ArduinoJson 7
> arr.add<JsonArray>();
> arr.add<JsonObject>();
> ``` > ```
> >
> A deprecation warning with the message "Replace `as<char*>()` with `as<const char*>()`" was added to allow a smooth transition. > And to create `{"array":[],"object":{}}`, you would write:
>
> #### `DeserializationError::NotSupported` removed
>
> On a different topic, `DeserializationError::NotSupported` has been removed.
> Instead of returning this error:
>
> * `deserializeJson()` leaves `\uXXXX` unchanged (only when `ARDUINOJSON_DECODE_UNICODE` is `0`)
> * `deserializeMsgPack()` replaces unsupported values with `null`s
>
> #### Const-aware `is<T>()`
>
> Lastly, a very minor change concerns `JsonVariantConst::is<T>()`.
> It used to return `true` for `JsonArray` and `JsonOject`, but now it returns `false`.
> Instead, you must use `JsonArrayConst` and `JsonObjectConst`.
v6.17.3 (2021-02-15)
-------
* Made `JsonDocument`'s destructor protected (issue #1480)
* Added missing calls to `client.stop()` in `JsonHttpClient.ino` (issue #1485)
* Fixed error `expected ')' before 'char'` when `isdigit()` is a macro (issue #1487)
* Fixed error `definition of implicit copy constructor is deprecated` on Clang 10
* PlatformIO: set framework compatibility to `*` (PR #1490 by @maxgerhardt)
v6.17.2 (2020-11-14)
-------
* Fixed invalid conversion error in `operator|(JsonVariant, char*)` (issue #1432)
* Changed the default value of `ARDUINOJSON_ENABLE_PROGMEM` (issue #1433).
It now checks that the `pgm_read_XXX` macros are defined before enabling `PROGMEM`.
v6.17.1 (2020-11-07)
-------
* Fixed error `ambiguous overload for 'operator|'` (issue #1411)
* Fixed `operator|(MemberProxy, JsonObject)` (issue #1415)
* Allowed more than 32767 values in non-embedded mode (issue #1414)
v6.17.0 (2020-10-19)
-------
* Added a build failure when nullptr is defined as a macro (issue #1355)
* Added `JsonDocument::overflowed()` which tells if the memory pool was too small (issue #1358)
* Added `DeserializationError::EmptyInput` which tells if the input was empty
* Added `DeserializationError::f_str()` which returns a `const __FlashStringHelper*` (issue #846)
* Added `operator|(JsonVariantConst, JsonVariantConst)`
* Added filtering for MessagePack (issue #1298, PR #1394 by Luca Passarella)
* Moved float convertion tables to PROGMEM
* Fixed `JsonVariant::set((char*)0)` which returned false instead of true (issue #1368)
* Fixed error `No such file or directory #include <WString.h>` (issue #1381)
v6.16.1 (2020-08-04)
-------
* Fixed `deserializeJson()` that stopped reading after `{}` (issue #1335)
v6.16.0 (2020-08-01)
-------
* Added comparisons (`>`, `>=`, `==`, `!=`, `<`, and `<=`) between `JsonVariant`s
* Added string deduplication (issue #1303)
* Added `JsonString::operator!=`
* Added wildcard key (`*`) for filters (issue #1309)
* Set `ARDUINOJSON_DECODE_UNICODE` to `1` by default
* Fixed `copyArray()` not working with `String`, `ElementProxy`, and `MemberProxy`
* Fixed error `getOrAddElement is not a member of ElementProxy` (issue #1311)
* Fixed excessive stack usage when compiled with `-Og` (issues #1210 and #1314)
* Fixed `Warning[Pa093]: implicit conversion from floating point to integer` on IAR compiler (PR #1328 by @stawiski)
v6.15.2 (2020-05-15)
-------
* CMake: don't build tests when imported in another project
* CMake: made project arch-independent
* Visual Studio: fixed error C2766 with flag `/Zc:__cplusplus` (issue #1250)
* Added support for `JsonDocument` to `copyArray()` (issue #1255)
* Added support for `enum`s in `as<T>()` and `is<T>()` (issue #1256)
* Added `JsonVariant` as an input type for `deserializeXxx()`
For example, you can do: `deserializeJson(doc2, doc1["payload"])`
* Break the build if using 64-bit integers with ARDUINOJSON_USE_LONG_LONG==0
v6.15.1 (2020-04-08)
-------
* Fixed "maybe-uninitialized" warning (issue #1217)
* Fixed "statement is unreachable" warning on IAR (issue #1233)
* Fixed "pointless integer comparison" warning on IAR (issue #1233)
* Added CMake "install" target (issue #1209)
* Disabled alignment on AVR (issue #1231)
v6.15.0 (2020-03-22)
-------
* Added `DeserializationOption::Filter` (issue #959)
* Added example `JsonFilterExample.ino`
* Changed the array subscript operator to automatically add missing elements
* Fixed "deprecated-copy" warning on GCC 9 (fixes #1184)
* Fixed `MemberProxy::set(char[])` not duplicating the string (issue #1191)
* Fixed enums serialized as booleans (issue #1197)
* Fixed incorrect string comparison on some platforms (issue #1198)
* Added move-constructor and move-assignment to `BasicJsonDocument`
* Added `BasicJsonDocument::garbageCollect()` (issue #1195)
* Added `StaticJsonDocument::garbageCollect()`
* Changed copy-constructor of `BasicJsonDocument` to preserve the capacity of the source.
* Removed copy-constructor of `JsonDocument` (issue #1189)
> ### BREAKING CHANGES
>
> #### Copy-constructor of `BasicJsonDocument`
>
> In previous versions, the copy constructor of `BasicJsonDocument` looked at the source's `memoryUsage()` to choose its capacity.
> Now, the copy constructor of `BasicJsonDocument` uses the same capacity as the source.
>
> Example:
> >
> ```c++ > ```c++
> DynamicJsonDocument doc1(64); > // ArduinoJson 6
> doc1.set(String("example")); > obj.createNestedArray("array");
> obj.createNestedObject("object");
> >
> DynamicJsonDocument doc2 = doc1; > // ArduinoJson 7
> Serial.print(doc2.capacity()); // 8 with ArduinoJson 6.14 > obj["array"].to<JsonArray>();
> // 64 with ArduinoJson 6.15 > obj["object"].to<JsonObject>();
> ```
>
> I made this change to get consistent results between copy-constructor and move-constructor, and whether RVO applies or not.
>
> If you use the copy-constructor to optimize your documents, you can use `garbageCollect()` or `shrinkToFit()` instead.
>
> #### Copy-constructor of `JsonDocument`
>
> In previous versions, it was possible to create a function that take a `JsonDocument` by value.
>
> ```c++
> void myFunction(JsonDocument doc) {}
> ```
>
> This function gives the wrong clues because it doesn't receive a copy of the `JsonDocument`, only a sliced version.
> It worked because the copy constructor copied the internal pointers, but it was an accident.
>
> From now, if you need to pass a `JsonDocument` to a function, you must use a reference:
>
> ```c++
> void myFunction(JsonDocument& doc) {}
> ```
v6.14.1 (2020-01-27)
-------
* Fixed regression in UTF16 decoding (issue #1173)
* Fixed `containsKey()` on `JsonVariantConst`
* Added `getElement()` and `getMember()` to `JsonVariantConst`
v6.14.0 (2020-01-16)
-------
* Added `BasicJsonDocument::shrinkToFit()`
* Added support of `uint8_t` for `serializeJson()`, `serializeJsonPretty()`, and `serializeMsgPack()` (issue #1142)
* Added `ARDUINOJSON_ENABLE_COMMENTS` to enable support for comments (defaults to 0)
* Auto enable support for `std::string` and `std::stream` on modern compilers (issue #1156)
(No need to define `ARDUINOJSON_ENABLE_STD_STRING` and `ARDUINOJSON_ENABLE_STD_STREAM` anymore)
* Improved decoding of UTF-16 surrogate pairs (PR #1157 by @kaysievers)
(ArduinoJson now produces standard UTF-8 instead of CESU-8)
* Added `measureJson`, `measureJsonPretty`, and `measureMsgPack` to `keywords.txt`
(This file is used for syntax highlighting in the Arduino IDE)
* Fixed `variant.is<nullptr_t>()`
* Fixed value returned by `serializeJson()`, `serializeJsonPretty()`, and `serializeMsgPack()` when writing to a `String`
* Improved speed of `serializeJson()`, `serializeJsonPretty()`, and `serializeMsgPack()` when writing to a `String`
> ### BREAKING CHANGES
>
> #### Comments
>
> Support for comments in input is now optional and disabled by default.
>
> If you need support for comments, you must defined `ARDUINOJSON_ENABLE_COMMENTS` to `1`; otherwise, you'll receive `InvalidInput` errors.
>
> ```c++
> #define ARDUINOJSON_ENABLE_COMMENTS 1
> #include <ArduinoJson.h>
> ```
v6.13.0 (2019-11-01)
-------
* Added support for custom writer/reader classes (issue #1088)
* Added conversion from `JsonArray` and `JsonObject` to `bool`, to be consistent with `JsonVariant`
* Fixed `deserializeJson()` when input contains duplicate keys (issue #1095)
* Improved `deserializeMsgPack()` speed by reading several bytes at once
* Added detection of Atmel AVR8/GNU C Compiler (issue #1112)
* Fixed deserializer that stopped reading at the first `0xFF` (PR #1118 by @mikee47)
* Fixed dangling reference in copies of `MemberProxy` and `ElementProxy` (issue #1120)
v6.12.0 (2019-09-05)
-------
* Use absolute instead of relative includes (issue #1072)
* Changed `JsonVariant::as<bool>()` to return `true` for any non-null value (issue #1005)
* Moved ancillary files to `extras/` (issue #1011)
v6.11.5 (2019-08-23)
-------
* Added fallback implementations of `strlen_P()`, `strncmp_P()`, `strcmp_P()`, and `memcpy_P()` (issue #1073)
v6.11.4 (2019-08-12)
-------
* Added `measureJson()` to the `ArduinoJson` namespace (PR #1069 by @nomis)
* Added support for `basic_string<char, traits, allocator>` (issue #1045)
* Fixed example `JsonConfigFile.ino` for ESP8266
* Include `Arduino.h` if `ARDUINO` is defined (PR #1071 by @nomis)
v6.11.3 (2019-07-22)
-------
* Added operators `==` and `!=` for `JsonDocument`, `ElementProxy`, and `MemberProxy`
* Fixed comparison of `JsonVariant` when one contains a linked string and the other contains an owned string (issue #1051)
v6.11.2 (2019-07-08)
-------
* Fixed assignment of `JsonDocument` to `JsonVariant` (issue #1023)
* Fix invalid conversion error on Particle Argon (issue #1035)
v6.11.1 (2019-06-21)
-------
* Fixed `serialized()` not working with Flash strings (issue #1030)
v6.11.0 (2019-05-26)
-------
* Fixed `deserializeJson()` silently accepting a `Stream*` (issue #978)
* Fixed invalid result from `operator|` (issue #981)
* Made `deserializeJson()` more picky about trailing characters (issue #980)
* Added `ARDUINOJSON_ENABLE_NAN` (default=0) to enable NaN in JSON (issue #973)
* Added `ARDUINOJSON_ENABLE_INFINITY` (default=0) to enable Infinity in JSON
* Removed implicit conversion in comparison operators (issue #998)
* Added lexicographical comparison for `JsonVariant`
* Added support for `nullptr` (issue #998)
> ### BREAKING CHANGES
>
> #### NaN and Infinity
>
> The JSON specification allows neither NaN not Infinity, but previous
> versions of ArduinoJson supported it. Now, ArduinoJson behaves like most
> other libraries: a NaN or and Infinity in the `JsonDocument`, becomes
> a `null` in the output JSON. Also, `deserializeJson()` returns
> `InvalidInput` if the JSON document contains NaN or Infinity.
>
> This version still supports NaN and Infinity in JSON documents, but
> it's disabled by default to be compatible with other JSON parsers.
> If you need the old behavior back, define `ARDUINOJSON_ENABLE_NAN` and
> `ARDUINOJSON_ENABLE_INFINITY` to `1`;:
>
> ```c++
> #define ARDUINOJSON_ENABLE_NAN 1
> #define ARDUINOJSON_ENABLE_INFINITY 1
> #include <ArduinoJson.h>
> ```
>
> #### The "or" operator
>
> This version slightly changes the behavior of the | operator when the
> variant contains a float and the user requests an integer.
>
> Older versions returned the floating point value truncated.
> Now, it returns the default value.
>
> ```c++
> // suppose variant contains 1.2
> int value = variant | 3;
>
> // old behavior:
> value == 1
>
> // new behavior
> value == 3
> ```
>
> If you need the old behavior, you must add `if (variant.is<float>())`.
v6.10.1 (2019-04-23)
-------
* Fixed error "attributes are not allowed on a function-definition"
* Fixed `deserializeJson()` not being picky enough (issue #969)
* Fixed error "no matching function for call to write(uint8_t)" (issue #972)
v6.10.0 (2019-03-22)
-------
* Fixed an integer overflow in the JSON deserializer
* Added overflow handling in `JsonVariant::as<T>()` and `JsonVariant::is<T>()`.
- `as<T>()` returns `0` if the integer `T` overflows
- `is<T>()` returns `false` if the integer `T` overflows
* Added `BasicJsonDocument` to support custom allocator (issue #876)
* Added `JsonDocument::containsKey()` (issue #938)
* Added `JsonVariant::containsKey()`
v6.9.1 (2019-03-01)
------
* Fixed warning "unused variable" with GCC 4.4 (issue #912)
* Fixed warning "cast increases required alignment" (issue #914)
* Fixed warning "conversion may alter value" (issue #914)
* Fixed naming conflict with "CAPACITY" (issue #839)
* Muted warning "will change in GCC 7.1" (issue #914)
* Added a clear error message for `StaticJsonBuffer` and `DynamicJsonBuffer`
* Marked ArduinoJson.h as a "system header"
v6.9.0 (2019-02-26)
------
* Decode escaped Unicode characters like \u00DE (issue #304, PR #791)
Many thanks to Daniel Schulte (aka @trilader) who implemented this feature.
* Added option ARDUINOJSON_DECODE_UNICODE to enable it
* Converted `JsonArray::copyFrom()/copyTo()` to free functions `copyArray()`
* Renamed `JsonArray::copyFrom()` and `JsonObject::copyFrom()` to `set()`
* Renamed `JsonArray::get()` to `getElement()`
* Renamed `JsonArray::add()` (without arg) to `addElement()`
* Renamed `JsonObject::get()` to `getMember()`
* Renamed `JsonObject::getOrCreate()` to `getOrAddMember()`
* Fixed `JsonVariant::isNull()` not returning `true` after `set((char*)0)`
* Fixed segfault after `variant.set(serialized((char*)0))`
* Detect `IncompleteInput` in `false`, `true`, and `null`
* Added `JsonDocument::size()`
* Added `JsonDocument::remove()`
* Added `JsonVariant::clear()`
* Added `JsonVariant::remove()`
v6.8.0-beta (2019-01-30)
-----------
* Import functions in the ArduinoJson namespace to get clearer errors
* Improved syntax highlighting in Arduino IDE
* Removed default capacity of `DynamicJsonDocument`
* `JsonArray::copyFrom()` accepts `JsonArrayConst`
* `JsonVariant::set()` accepts `JsonArrayConst` and `JsonObjectConst`
* `JsonDocument` was missing in the ArduinoJson namespace
* Added `memoryUsage()` to `JsonArray`, `JsonObject`, and `JsonVariant`
* Added `nesting()` to `JsonArray`, `JsonDocument`, `JsonObject`, and `JsonVariant`
* Replaced `JsonDocument::nestingLimit` with an additional parameter
to `deserializeJson()` and `deserializeMsgPack()`
* Fixed uninitialized variant in `JsonDocument`
* Fixed `StaticJsonDocument` copy constructor and copy assignment
* The copy constructor of `DynamicJsonDocument` chooses the capacity according to the memory usage of the source, not from the capacity of the source.
* Added the ability to create/assign a `StaticJsonDocument`/`DynamicJsonDocument` from a `JsonArray`/`JsonObject`/`JsonVariant`
* Added `JsonDocument::isNull()`
* Added `JsonDocument::operator[]`
* Added `ARDUINOJSON_TAB` to configure the indentation character
* Reduced the size of the pretty JSON serializer
* Added `add()`, `createNestedArray()` and `createNestedObject()` to `JsonVariant`
* `JsonVariant` automatically promotes to `JsonObject` or `JsonArray` on write.
Calling `JsonVariant::to<T>()` is not required anymore.
* `JsonDocument` now support the same operations as `JsonVariant`.
Calling `JsonDocument::as<T>()` is not required anymore.
* Fixed example `JsonHttpClient.ino`
* User can now use a `JsonString` as a key or a value
> ### BREAKING CHANGES
>
> #### `DynamicJsonDocument`'s constructor
>
> The parameter to the constructor of `DynamicJsonDocument` is now mandatory
>
> Old code:
>
> ```c++
> DynamicJsonDocument doc;
> ```
>
> New code:
>
> ```c++
> DynamicJsonDocument doc(1024);
> ```
>
> #### Nesting limit
>
> `JsonDocument::nestingLimit` was replaced with a new parameter to `deserializeJson()` and `deserializeMsgPack()`.
>
> Old code:
>
> ```c++
> doc.nestingLimit = 15;
> deserializeJson(doc, input);
> ```
>
> New code:
>
> ```c++
> deserializeJson(doc, input, DeserializationOption::NestingLimit(15));
> ```
v6.7.0-beta (2018-12-07)
-----------
* Removed the automatic expansion of `DynamicJsonDocument`, it now has a fixed capacity.
* Restored the monotonic allocator because the code was getting too big
* Reduced the memory usage
* Reduced the code size
* Renamed `JsonKey` to `JsonString`
* Removed spurious files in the Particle library
v6.6.0-beta (2018-11-13)
-----------
* Removed `JsonArray::is<T>(i)` and `JsonArray::set(i,v)`
* Removed `JsonObject::is<T>(k)` and `JsonObject::set(k,v)`
* Replaced `T JsonArray::get<T>(i)` with `JsonVariant JsonArray::get(i)`
* Replaced `T JsonObject::get<T>(k)` with `JsonVariant JsonObject::get(k)`
* Added `JSON_STRING_SIZE()`
* ~~Replacing or removing a value now releases the memory~~
* Added `DeserializationError::code()` to be used in switch statements (issue #846)
v6.5.0-beta (2018-10-13)
-----------
* Added implicit conversion from `JsonArray` and `JsonObject` to `JsonVariant`
* Allow mixed configuration in compilation units (issue #809)
* Fixed object keys not being duplicated
* `JsonPair::key()` now returns a `JsonKey`
* Increased the default capacity of `DynamicJsonDocument`
* Fixed `JsonVariant::is<String>()` (closes #763)
* Added `JsonArrayConst`, `JsonObjectConst`, and `JsonVariantConst`
* Added copy-constructor and copy-assignment-operator for `JsonDocument` (issue #827)
v6.4.0-beta (2018-09-11)
-----------
* Copy `JsonArray` and `JsonObject`, instead of storing pointers (issue #780)
* Added `JsonVariant::to<JsonArray>()` and `JsonVariant::to<JsonObject>()`
v6.3.0-beta (2018-08-31)
-----------
* Implemented reference semantics for `JsonVariant`
* Replaced `JsonPair`'s `key` and `value` with `key()` and `value()`
* Fixed `serializeJson(obj[key], dst)` (issue #794)
> ### BREAKING CHANGES
>
> #### JsonVariant
>
> `JsonVariant` now has a semantic similar to `JsonObject` and `JsonArray`.
> It's a reference to a value stored in the `JsonDocument`.
> As a consequence, a `JsonVariant` cannot be used as a standalone variable anymore.
>
> Old code:
>
> ```c++
> JsonVariant myValue = 42;
> ```
>
> New code:
>
> ```c++
> DynamicJsonDocument doc;
> JsonVariant myValue = doc.to<JsonVariant>();
> myValue.set(42);
> ```
>
> #### JsonPair
>
> Old code:
>
> ```c++
> for(JsonPair p : myObject) {
> Serial.println(p.key);
> Serial.println(p.value.as<int>());
> }
> ```
>
> New code:
>
> ```c++
> for(JsonPair p : myObject) {
> Serial.println(p.key());
> Serial.println(p.value().as<int>());
> }
> ```
>
> CAUTION: the key is now read only!
v6.2.3-beta (2018-07-19)
-----------
* Fixed exception when using Flash strings as object keys (issue #784)
v6.2.2-beta (2018-07-18)
-----------
* Fixed `invalid application of 'sizeof' to incomplete type '__FlashStringHelper'` (issue #783)
* Fixed `char[]` not duplicated when passed to `JsonVariant::operator[]`
v6.2.1-beta (2018-07-17)
-----------
* Fixed `JsonObject` not inserting keys of type `String` (issue #782)
v6.2.0-beta (2018-07-12)
-----------
* Disabled lazy number deserialization (issue #772)
* Fixed `JsonVariant::is<int>()` that returned true for empty strings
* Improved float serialization when `-fsingle-precision-constant` is used
* Renamed function `RawJson()` to `serialized()`
* `serializeMsgPack()` now supports values marked with `serialized()`
> ### BREAKING CHANGES
>
> #### Non quoted strings
>
> Non quoted strings are now forbidden in values, but they are still allowed in keys.
> For example, `{key:"value"}` is accepted, but `{key:value}` is not.
>
> #### Preformatted values
>
> Old code:
>
> ```c++
> object["values"] = RawJson("[1,2,3,4]");
> ```
>
> New code:
>
> ```c++
> object["values"] = serialized("[1,2,3,4]");
> ```
v6.1.0-beta (2018-07-02)
-----------
* Return `JsonArray` and `JsonObject` by value instead of reference (issue #309)
* Replaced `success()` with `isNull()`
> ### BREAKING CHANGES
>
> Old code:
>
> ```c++
> JsonObject& obj = doc.to<JsonObject>();
> JsonArray& arr = obj.createNestedArray("key");
> if (!arr.success()) {
> Serial.println("Not enough memory");
> return;
> }
> ```
>
> New code:
>
> ```c++
> JsonObject obj = doc.to<JsonObject>();
> JsonArray arr = obj.createNestedArray("key");
> if (arr.isNull()) {
> Serial.println("Not enough memory");
> return;
> }
> ```
v6.0.1-beta (2018-06-11)
-----------
* Fixed conflicts with `isnan()` and `isinf()` macros (issue #752)
v6.0.0-beta (2018-06-07)
-----------
* Added `DynamicJsonDocument` and `StaticJsonDocument`
* Added `deserializeJson()`
* Added `serializeJson()` and `serializeJsonPretty()`
* Added `measureJson()` and `measureJsonPretty()`
* Added `serializeMsgPack()`, `deserializeMsgPack()` and `measureMsgPack()` (issue #358)
* Added example `MsgPackParser.ino` (issue #358)
* Added support for non zero-terminated strings (issue #704)
* Removed `JsonBuffer::parseArray()`, `parseObject()` and `parse()`
* Removed `JsonBuffer::createArray()` and `createObject()`
* Removed `printTo()` and `prettyPrintTo()`
* Removed `measureLength()` and `measurePrettyLength()`
* Removed all deprecated features
> ### BREAKING CHANGES
>
> #### Deserialization
>
> Old code:
>
> ```c++
> DynamicJsonBuffer jb;
> JsonObject& obj = jb.parseObject(json);
> if (obj.success()) {
>
> }
> ```
>
> New code:
>
> ```c++
> DynamicJsonDocument doc;
> DeserializationError error = deserializeJson(doc, json);
> if (error) {
>
> }
> JsonObject& obj = doc.as<JsonObject>();
> ```
>
> #### Serialization
>
> Old code:
>
> ```c++
> DynamicJsonBuffer jb;
> JsonObject& obj = jb.createObject();
> obj["key"] = "value";
> obj.printTo(Serial);
> ```
>
> New code:
>
> ```c++
> DynamicJsonDocument obj;
> JsonObject& obj = doc.to<JsonObject>();
> obj["key"] = "value";
> serializeJson(doc, Serial);
> ``` > ```

View File

@@ -0,0 +1,25 @@
# ArduinoJson - https://arduinojson.org
# Copyright © 2014-2024, Benoit BLANCHON
# MIT License
cmake_minimum_required(VERSION 3.15)
if(ESP_PLATFORM)
# Build ArduinoJson as an ESP-IDF component
idf_component_register(INCLUDE_DIRS src)
return()
endif()
project(ArduinoJson VERSION 7.0.2)
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
include(CTest)
endif()
add_subdirectory(src)
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING)
include(extras/CompileOptions.cmake)
add_subdirectory(extras/tests)
add_subdirectory(extras/fuzzing)
endif()

View File

@@ -1,7 +1,7 @@
The MIT License (MIT) The MIT License (MIT)
--------------------- ---------------------
Copyright © 2014-2023, Benoit BLANCHON Copyright © 2014-2024, Benoit BLANCHON
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

View File

@@ -1,161 +0,0 @@
<p align="center">
<a href="https://arduinojson.org/"><img alt="ArduinoJson" src="https://arduinojson.org/images/logo.svg" width="200" /></a>
</p>
---
[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/bblanchon/ArduinoJson/ci.yml?branch=6.x&logo=github)](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A6.x)
[![Continuous Integration](https://ci.appveyor.com/api/projects/status/m7s53wav1l0abssg/branch/6.x?svg=true)](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x)
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/arduinojson.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson)
[![Coveralls branch](https://img.shields.io/coveralls/github/bblanchon/ArduinoJson/6.x?logo=coveralls)](https://coveralls.io/github/bblanchon/ArduinoJson?branch=6.x)
[![Arduino Library Manager](https://img.shields.io/static/v1?label=Arduino&message=v6.21.3&logo=arduino&logoColor=white&color=blue)](https://www.ardu-badge.com/ArduinoJson/6.21.3)
[![PlatformIO Registry](https://badges.registry.platformio.org/packages/bblanchon/library/ArduinoJson.svg?version=6.21.3)](https://registry.platformio.org/packages/libraries/bblanchon/ArduinoJson?version=6.21.3)
[![ESP IDF](https://img.shields.io/static/v1?label=ESP+IDF&message=v6.21.3&logo=cpu&logoColor=white&color=blue)](https://components.espressif.com/components/bblanchon/arduinojson)
[![GitHub stars](https://img.shields.io/github/stars/bblanchon/ArduinoJson?style=flat&logo=github&color=orange)](https://github.com/bblanchon/ArduinoJson/stargazers)
[![GitHub Sponsors](https://img.shields.io/github/sponsors/bblanchon?logo=github&color=orange)](https://github.com/sponsors/bblanchon)
ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
## Features
* [JSON deserialization](https://arduinojson.org/v6/api/json/deserializejson/)
* [Optionally decodes UTF-16 escape sequences to UTF-8](https://arduinojson.org/v6/api/config/decode_unicode/)
* [Optionally stores links to the input buffer (zero-copy)](https://arduinojson.org/v6/api/json/deserializejson/)
* [Optionally supports comments in the input](https://arduinojson.org/v6/api/config/enable_comments/)
* [Optionally filters the input to keep only desired values](https://arduinojson.org/v6/api/json/deserializejson/#filtering)
* Supports single quotes as a string delimiter
* Compatible with [NDJSON](http://ndjson.org/) and [JSON Lines](https://jsonlines.org/)
* [JSON serialization](https://arduinojson.org/v6/api/json/serializejson/)
* [Can write to a buffer or a stream](https://arduinojson.org/v6/api/json/serializejson/)
* [Optionally indents the document (prettified JSON)](https://arduinojson.org/v6/api/json/serializejsonpretty/)
* [MessagePack serialization](https://arduinojson.org/v6/api/msgpack/serializemsgpack/)
* [MessagePack deserialization](https://arduinojson.org/v6/api/msgpack/deserializemsgpack/)
* Efficient
* [Twice smaller than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/)
* [Almost 10% faster than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/)
* [Consumes roughly 10% less RAM than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/)
* [Fixed memory allocation, no heap fragmentation](https://arduinojson.org/v6/api/jsondocument/)
* [Optionally works without heap memory (zero malloc)](https://arduinojson.org/v6/api/staticjsondocument/)
* [Deduplicates strings](https://arduinojson.org/news/2020/08/01/version-6-16-0/)
* Versatile
* Supports [custom allocators (to use external RAM chip, for example)](https://arduinojson.org/v6/how-to/use-external-ram-on-esp32/)
* Supports [`String`](https://arduinojson.org/v6/api/config/enable_arduino_string/), [`std::string`](https://arduinojson.org/v6/api/config/enable_std_string/), and [`std::string_view`](https://arduinojson.org/v6/api/config/enable_string_view/)
* Supports [`Stream`](https://arduinojson.org/v6/api/config/enable_arduino_stream/) and [`std::istream`/`std::ostream`](https://arduinojson.org/v6/api/config/enable_std_stream/)
* Supports [Flash strings](https://arduinojson.org/v6/api/config/enable_progmem/)
* Supports [custom readers](https://arduinojson.org/v6/api/json/deserializejson/#custom-reader) and [custom writers](https://arduinojson.org/v6/api/json/serializejson/#custom-writer)
* Supports [custom converters](https://arduinojson.org/news/2021/05/04/version-6-18-0/)
* Portable
* Usable on any C++ project (not limited to Arduino)
* Compatible with C++11, C++14 and C++17
* Support for C++98/C++03 available on [ArduinoJson 6.20.x](https://github.com/bblanchon/ArduinoJson/tree/6.20.x)
* Zero warnings with `-Wall -Wextra -pedantic` and `/W4`
* [Header-only library](https://en.wikipedia.org/wiki/Header-only)
* Works with virtually any board
* Arduino boards: [Uno](https://amzn.to/38aL2ik), [Due](https://amzn.to/36YkWi2), [Micro](https://amzn.to/35WkdwG), [Nano](https://amzn.to/2QTvwRX), [Mega](https://amzn.to/36XWhuf), [Yun](https://amzn.to/30odURc), [Leonardo](https://amzn.to/36XWjlR)...
* Espressif chips: [ESP8266](https://amzn.to/36YluV8), [ESP32](https://amzn.to/2G4pRCB)
* Lolin (WeMos) boards: [D1 mini](https://amzn.to/2QUpz7q), [D1 Mini Pro](https://amzn.to/36UsGSs)...
* Teensy boards: [4.0](https://amzn.to/30ljXGq), [3.2](https://amzn.to/2FT0EuC), [2.0](https://amzn.to/2QXUMXj)
* Particle boards: [Argon](https://amzn.to/2FQHa9X), [Boron](https://amzn.to/36WgLUd), [Electron](https://amzn.to/30vEc4k), [Photon](https://amzn.to/387F9Cd)...
* Texas Instruments boards: [MSP430](https://amzn.to/30nJWgg)...
* Soft cores: [Nios II](https://en.wikipedia.org/wiki/Nios_II)...
* Tested on all major development environments
* [Arduino IDE](https://www.arduino.cc/en/Main/Software)
* [Atmel Studio](http://www.atmel.com/microsite/atmel-studio/)
* [Atollic TrueSTUDIO](https://atollic.com/truestudio/)
* [Energia](http://energia.nu/)
* [IAR Embedded Workbench](https://www.iar.com/iar-embedded-workbench/)
* [Keil uVision](http://www.keil.com/)
* [MPLAB X IDE](http://www.microchip.com/mplab/mplab-x-ide)
* [Particle](https://www.particle.io/)
* [PlatformIO](http://platformio.org/)
* [Sloeber plugin for Eclipse](https://eclipse.baeyens.it/)
* [Visual Micro](http://www.visualmicro.com/)
* [Visual Studio](https://www.visualstudio.com/)
* [Even works with online compilers like wandbox.org](https://wandbox.org/permlink/RlZSKy17DjJ6HcdN)
* [CMake friendly](https://arduinojson.org/v6/how-to/use-arduinojson-with-cmake/)
* Well designed
* [Elegant API](http://arduinojson.org/v6/example/)
* [Thread-safe](https://en.wikipedia.org/wiki/Thread_safety)
* Self-contained (no external dependency)
* `const` friendly
* [`for` friendly](https://arduinojson.org/v6/api/jsonobject/begin_end/)
* [TMP friendly](https://en.wikipedia.org/wiki/Template_metaprogramming)
* Handles [integer overflows](https://arduinojson.org/v6/api/jsonvariant/as/#integer-overflows)
* Well tested
* [Unit test coverage close to 100%](https://coveralls.io/github/bblanchon/ArduinoJson?branch=6.x)
* Continuously tested on
* [Visual Studio 2017, 2019, 2022](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x)
* [GCC 5, 6, 7, 8, 9, 10, 11](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22)
* [Clang 3.8, 3.9, 4.0, 5.0, 6.0, 7, 8, 9, 10](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22)
* [Continuously fuzzed with Google OSS Fuzz](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson)
* Passes all default checks of [clang-tidy](https://releases.llvm.org/10.0.0/tools/clang/tools/extra/docs/clang-tidy/)
* Well documented
* [Tutorials](https://arduinojson.org/v6/doc/deserialization/)
* [Examples](https://arduinojson.org/v6/example/)
* [How-tos](https://arduinojson.org/v6/example/)
* [FAQ](https://arduinojson.org/v6/faq/)
* [Troubleshooter](https://arduinojson.org/v6/troubleshooter/)
* [Book](https://arduinojson.org/book/)
* [Changelog](CHANGELOG.md)
* Vibrant user community
* Most popular of all Arduino libraries on [GitHub](https://github.com/search?o=desc&q=arduino+library&s=stars&type=Repositories)
* [Used in hundreds of projects](https://www.hackster.io/search?i=projects&q=arduinojson)
* [Responsive support](https://github.com/bblanchon/ArduinoJson/issues?q=is%3Aissue+is%3Aclosed)
## Quickstart
### Deserialization
Here is a program that parses a JSON document with ArduinoJson.
```c++
char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
DynamicJsonDocument doc(1024);
deserializeJson(doc, json);
const char* sensor = doc["sensor"];
long time = doc["time"];
double latitude = doc["data"][0];
double longitude = doc["data"][1];
```
See the [tutorial on arduinojson.org](https://arduinojson.org/v6/doc/deserialization/)
### Serialization
Here is a program that generates a JSON document with ArduinoJson:
```c++
DynamicJsonDocument doc(1024);
doc["sensor"] = "gps";
doc["time"] = 1351824120;
doc["data"][0] = 48.756080;
doc["data"][1] = 2.302038;
serializeJson(doc, Serial);
// This prints:
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
```
See the [tutorial on arduinojson.org](https://arduinojson.org/v6/doc/serialization/)
## Sponsors
ArduinoJson is thankful to its sponsors. Please give them a visit; they deserve it!
<p>
<a href="https://www.programmingelectronics.com/" rel="sponsored">
<img src="https://arduinojson.org/images/2021/10/programmingeleactronicsacademy.png" alt="Programming Electronics Academy" width="200">
</a>
</p>
<p>
<a href="https://github.com/1technophile" rel="sponsored">
<img alt="1technophile" src="https://avatars.githubusercontent.com/u/12672732?s=40&v=4">
</a>
</p>
If you run a commercial project that embeds ArduinoJson, think about [sponsoring the library's development](https://github.com/sponsors/bblanchon): it ensures the code that your products rely on stays actively maintained. It can also give your project some exposure to the makers' community.
If you are an individual user and want to support the development (or give a sign of appreciation), consider purchasing the book [Mastering ArduinoJson](https://arduinojson.org/book/)&nbsp;❤, or simply [cast a star](https://github.com/bblanchon/ArduinoJson/stargazers)&nbsp;⭐.

View File

@@ -0,0 +1,13 @@
version: "7.0.2"
description: >-
A simple and efficient JSON library for embedded C++.
⭐ 6444 stars on GitHub!
Supports serialization, deserialization, MessagePack, streams, filtering, and more.
Fully tested and documented.
url: https://arduinojson.org/
files:
exclude:
- "**/.vs/**/*"
- ".devcontainer/**/*"
- "examples/**/*"
- "extras/**/*"

View File

@@ -1,40 +0,0 @@
# Macros
JSON_ARRAY_SIZE KEYWORD2
JSON_OBJECT_SIZE KEYWORD2
JSON_STRING_SIZE KEYWORD2
# Free functions
deserializeJson KEYWORD2
deserializeMsgPack KEYWORD2
serialized KEYWORD2
serializeJson KEYWORD2
serializeJsonPretty KEYWORD2
serializeMsgPack KEYWORD2
measureJson KEYWORD2
measureJsonPretty KEYWORD2
measureMsgPack KEYWORD2
# Methods
add KEYWORD2
as KEYWORD2
createNestedArray KEYWORD2
createNestedObject KEYWORD2
get KEYWORD2
set KEYWORD2
to KEYWORD2
# Type names
DeserializationError KEYWORD1 DATA_TYPE
DynamicJsonDocument KEYWORD1 DATA_TYPE
JsonArray KEYWORD1 DATA_TYPE
JsonArrayConst KEYWORD1 DATA_TYPE
JsonDocument KEYWORD1 DATA_TYPE
JsonFloat KEYWORD1 DATA_TYPE
JsonInteger KEYWORD1 DATA_TYPE
JsonObject KEYWORD1 DATA_TYPE
JsonObjectConst KEYWORD1 DATA_TYPE
JsonString KEYWORD1 DATA_TYPE
JsonUInt KEYWORD1 DATA_TYPE
JsonVariant KEYWORD1 DATA_TYPE
JsonVariantConst KEYWORD1 DATA_TYPE
StaticJsonDocument KEYWORD1 DATA_TYPE

View File

@@ -0,0 +1,23 @@
{
"name": "ArduinoJson",
"keywords": "json, rest, http, web",
"description": "A simple and efficient JSON library for embedded C++. ⭐ 6444 stars on GitHub! Supports serialization, deserialization, MessagePack, streams, filtering, and more. Fully tested and documented.",
"homepage": "https://arduinojson.org/?utm_source=meta&utm_medium=library.json",
"repository": {
"type": "git",
"url": "https://github.com/bblanchon/ArduinoJson.git"
},
"version": "7.0.2",
"authors": {
"name": "Benoit Blanchon",
"url": "https://blog.benoitblanchon.fr"
},
"export": {
"include": ["src", "examples", "LICENSE.txt", "ArduinoJson.h"]
},
"frameworks": "*",
"platforms": "*",
"build": {
"libArchive": false
}
}

View File

@@ -1,9 +1,9 @@
name=ArduinoJson name=ArduinoJson
version=6.21.3 version=7.0.2
author=Benoit Blanchon <blog.benoitblanchon.fr> author=Benoit Blanchon <blog.benoitblanchon.fr>
maintainer=Benoit Blanchon <blog.benoitblanchon.fr> maintainer=Benoit Blanchon <blog.benoitblanchon.fr>
sentence=A simple and efficient JSON library for embedded C++. sentence=A simple and efficient JSON library for embedded C++.
paragraph=ArduinoJson supports serialization, deserialization, MessagePack, ✔ fixed allocation, ✔ zero-copy, ✔ streams, filtering, and more. It is the most popular Arduino library on GitHub ❤❤❤❤❤. Check out arduinojson.org for a comprehensive documentation. paragraph=⭐ 6444 stars on GitHub! Supports serialization, deserialization, MessagePack, streams, filtering, and more. Fully tested and documented.
category=Data Processing category=Data Processing
url=https://arduinojson.org/?utm_source=meta&utm_medium=library.properties url=https://arduinojson.org/?utm_source=meta&utm_medium=library.properties
architectures=* architectures=*

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -30,18 +30,19 @@
#include "ArduinoJson/Object/JsonObject.hpp" #include "ArduinoJson/Object/JsonObject.hpp"
#include "ArduinoJson/Variant/JsonVariantConst.hpp" #include "ArduinoJson/Variant/JsonVariantConst.hpp"
#include "ArduinoJson/Document/DynamicJsonDocument.hpp" #include "ArduinoJson/Document/JsonDocument.hpp"
#include "ArduinoJson/Document/StaticJsonDocument.hpp"
#include "ArduinoJson/Array/ArrayImpl.hpp"
#include "ArduinoJson/Array/ElementProxy.hpp" #include "ArduinoJson/Array/ElementProxy.hpp"
#include "ArduinoJson/Array/JsonArrayImpl.hpp"
#include "ArduinoJson/Array/Utilities.hpp" #include "ArduinoJson/Array/Utilities.hpp"
#include "ArduinoJson/Collection/CollectionImpl.hpp" #include "ArduinoJson/Collection/CollectionImpl.hpp"
#include "ArduinoJson/Object/JsonObjectImpl.hpp" #include "ArduinoJson/Memory/VariantPoolImpl.hpp"
#include "ArduinoJson/Object/MemberProxy.hpp" #include "ArduinoJson/Object/MemberProxy.hpp"
#include "ArduinoJson/Object/ObjectImpl.hpp"
#include "ArduinoJson/Variant/ConverterImpl.hpp" #include "ArduinoJson/Variant/ConverterImpl.hpp"
#include "ArduinoJson/Variant/JsonVariantCopier.hpp"
#include "ArduinoJson/Variant/VariantCompare.hpp" #include "ArduinoJson/Variant/VariantCompare.hpp"
#include "ArduinoJson/Variant/VariantImpl.hpp" #include "ArduinoJson/Variant/VariantRefBaseImpl.hpp"
#include "ArduinoJson/Json/JsonDeserializer.hpp" #include "ArduinoJson/Json/JsonDeserializer.hpp"
#include "ArduinoJson/Json/JsonSerializer.hpp" #include "ArduinoJson/Json/JsonSerializer.hpp"

View File

@@ -0,0 +1,57 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Collection/CollectionData.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
class ArrayData : public CollectionData {
public:
VariantData* addElement(ResourceManager* resources) {
return addSlot(resources).data();
}
static VariantData* addElement(ArrayData* array, ResourceManager* resources) {
if (!array)
return nullptr;
return array->addElement(resources);
}
VariantData* getOrAddElement(size_t index, ResourceManager* resources);
VariantData* getElement(size_t index, const ResourceManager* resources) const;
static VariantData* getElement(const ArrayData* array, size_t index,
const ResourceManager* resources) {
if (!array)
return nullptr;
return array->getElement(index, resources);
}
void removeElement(size_t index, ResourceManager* resources);
static void removeElement(ArrayData* array, size_t index,
ResourceManager* resources) {
if (!array)
return;
array->removeElement(index, resources);
}
bool copyFrom(const ArrayData& src, ResourceManager* resources);
static bool copy(ArrayData* dst, const ArrayData* src,
ResourceManager* resources) {
if (!dst || !src)
return false;
return dst->copyFrom(*src, resources);
}
private:
iterator at(size_t index, const ResourceManager* resources) const;
};
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -0,0 +1,50 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Array/ArrayData.hpp>
#include <ArduinoJson/Variant/VariantCompare.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
inline ArrayData::iterator ArrayData::at(
size_t index, const ResourceManager* resources) const {
auto it = createIterator(resources);
while (!it.done() && index) {
it.next(resources);
--index;
}
return it;
}
inline VariantData* ArrayData::getOrAddElement(size_t index,
ResourceManager* resources) {
auto it = createIterator(resources);
while (!it.done() && index > 0) {
it.next(resources);
index--;
}
if (it.done())
index++;
VariantData* element = it.data();
while (index > 0) {
element = addElement(resources);
if (!element)
return nullptr;
index--;
}
return element;
}
inline VariantData* ArrayData::getElement(
size_t index, const ResourceManager* resources) const {
return at(index, resources).data();
}
inline void ArrayData::removeElement(size_t index, ResourceManager* resources) {
remove(at(index, resources), resources);
}
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -9,7 +9,7 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
// A proxy class to get or set an element of an array. // A proxy class to get or set an element of an array.
// https://arduinojson.org/v6/api/jsonarray/subscript/ // https://arduinojson.org/v7/api/jsonarray/subscript/
template <typename TUpstream> template <typename TUpstream>
class ElementProxy : public VariantRefBase<ElementProxy<TUpstream>>, class ElementProxy : public VariantRefBase<ElementProxy<TUpstream>>,
public VariantOperators<ElementProxy<TUpstream>> { public VariantOperators<ElementProxy<TUpstream>> {
@@ -40,17 +40,22 @@ class ElementProxy : public VariantRefBase<ElementProxy<TUpstream>>,
} }
private: private:
FORCE_INLINE MemoryPool* getPool() const { FORCE_INLINE ResourceManager* getResourceManager() const {
return VariantAttorney::getPool(upstream_); return VariantAttorney::getResourceManager(upstream_);
} }
FORCE_INLINE VariantData* getData() const { FORCE_INLINE VariantData* getData() const {
return variantGetElement(VariantAttorney::getData(upstream_), index_); return VariantData::getElement(
VariantAttorney::getData(upstream_), index_,
VariantAttorney::getResourceManager(upstream_));
} }
FORCE_INLINE VariantData* getOrCreateData() const { FORCE_INLINE VariantData* getOrCreateData() const {
return variantGetOrAddElement(VariantAttorney::getOrCreateData(upstream_), auto data = VariantAttorney::getOrCreateData(upstream_);
index_, VariantAttorney::getPool(upstream_)); if (!data)
return nullptr;
return data->getOrAddElement(
index_, VariantAttorney::getResourceManager(upstream_));
} }
TUpstream upstream_; TUpstream upstream_;

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -12,7 +12,7 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
class JsonObject; class JsonObject;
// A reference to an array in a JsonDocument // A reference to an array in a JsonDocument
// https://arduinojson.org/v6/api/jsonarray/ // https://arduinojson.org/v7/api/jsonarray/
class JsonArray : public detail::VariantOperators<JsonArray> { class JsonArray : public detail::VariantOperators<JsonArray> {
friend class detail::VariantAttorney; friend class detail::VariantAttorney;
@@ -20,155 +20,166 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
typedef JsonArrayIterator iterator; typedef JsonArrayIterator iterator;
// Constructs an unbound reference. // Constructs an unbound reference.
FORCE_INLINE JsonArray() : data_(0), pool_(0) {} FORCE_INLINE JsonArray() : data_(0), resources_(0) {}
// INTERNAL USE ONLY // INTERNAL USE ONLY
FORCE_INLINE JsonArray(detail::MemoryPool* pool, detail::CollectionData* data) FORCE_INLINE JsonArray(detail::ArrayData* data,
: data_(data), pool_(pool) {} detail::ResourceManager* resources)
: data_(data), resources_(resources) {}
// Returns a JsonVariant pointing to the array. // Returns a JsonVariant pointing to the array.
// https://arduinojson.org/v6/api/jsonvariant/ // https://arduinojson.org/v7/api/jsonvariant/
operator JsonVariant() { operator JsonVariant() {
void* data = data_; // prevent warning cast-align void* data = data_; // prevent warning cast-align
return JsonVariant(pool_, reinterpret_cast<detail::VariantData*>(data)); return JsonVariant(reinterpret_cast<detail::VariantData*>(data),
resources_);
} }
// Returns a read-only reference to the array. // Returns a read-only reference to the array.
// https://arduinojson.org/v6/api/jsonarrayconst/ // https://arduinojson.org/v7/api/jsonarrayconst/
operator JsonArrayConst() const { operator JsonArrayConst() const {
return JsonArrayConst(data_); return JsonArrayConst(data_, resources_);
}
// Appends a new (empty) element to the array.
// Returns a reference to the new element.
// https://arduinojson.org/v7/api/jsonarray/add/
template <typename T>
typename detail::enable_if<!detail::is_same<T, JsonVariant>::value, T>::type
add() const {
return add<JsonVariant>().to<T>();
} }
// Appends a new (null) element to the array. // Appends a new (null) element to the array.
// Returns a reference to the new element. // Returns a reference to the new element.
// https://arduinojson.org/v6/api/jsonarray/add/ // https://arduinojson.org/v7/api/jsonarray/add/
JsonVariant add() const { template <typename T>
if (!data_) typename detail::enable_if<detail::is_same<T, JsonVariant>::value, T>::type
return JsonVariant(); add() const {
return JsonVariant(pool_, data_->addElement(pool_)); return JsonVariant(detail::ArrayData::addElement(data_, resources_),
resources_);
} }
// Appends a value to the array. // Appends a value to the array.
// https://arduinojson.org/v6/api/jsonarray/add/ // https://arduinojson.org/v7/api/jsonarray/add/
template <typename T> template <typename T>
FORCE_INLINE bool add(const T& value) const { FORCE_INLINE bool add(const T& value) const {
return add().set(value); return add<JsonVariant>().set(value);
} }
// Appends a value to the array. // Appends a value to the array.
// https://arduinojson.org/v6/api/jsonarray/add/ // https://arduinojson.org/v7/api/jsonarray/add/
template <typename T> template <typename T>
FORCE_INLINE bool add(T* value) const { FORCE_INLINE bool add(T* value) const {
return add().set(value); return add<JsonVariant>().set(value);
} }
// Returns an iterator to the first element of the array. // Returns an iterator to the first element of the array.
// https://arduinojson.org/v6/api/jsonarray/begin/ // https://arduinojson.org/v7/api/jsonarray/begin/
FORCE_INLINE iterator begin() const { FORCE_INLINE iterator begin() const {
if (!data_) if (!data_)
return iterator(); return iterator();
return iterator(pool_, data_->head()); return iterator(data_->createIterator(resources_), resources_);
} }
// Returns an iterator following the last element of the array. // Returns an iterator following the last element of the array.
// https://arduinojson.org/v6/api/jsonarray/end/ // https://arduinojson.org/v7/api/jsonarray/end/
FORCE_INLINE iterator end() const { FORCE_INLINE iterator end() const {
return iterator(); return iterator();
} }
// Copies an array. // Copies an array.
// https://arduinojson.org/v6/api/jsonarray/set/ // https://arduinojson.org/v7/api/jsonarray/set/
FORCE_INLINE bool set(JsonArrayConst src) const { FORCE_INLINE bool set(JsonArrayConst src) const {
if (!data_ || !src.data_) if (!data_)
return false;
clear();
for (auto element : src) {
if (!add(element))
return false; return false;
return data_->copyFrom(*src.data_, pool_);
} }
// Compares the content of two arrays. return true;
FORCE_INLINE bool operator==(JsonArray rhs) const {
return JsonArrayConst(data_) == JsonArrayConst(rhs.data_);
} }
// Removes the element at the specified iterator. // Removes the element at the specified iterator.
// ⚠️ Doesn't release the memory associated with the removed element. // https://arduinojson.org/v7/api/jsonarray/remove/
// https://arduinojson.org/v6/api/jsonarray/remove/
FORCE_INLINE void remove(iterator it) const { FORCE_INLINE void remove(iterator it) const {
if (!data_) detail::ArrayData::remove(data_, it.iterator_, resources_);
return;
data_->removeSlot(it.slot_);
} }
// Removes the element at the specified index. // Removes the element at the specified index.
// ⚠️ Doesn't release the memory associated with the removed element. // https://arduinojson.org/v7/api/jsonarray/remove/
// https://arduinojson.org/v6/api/jsonarray/remove/
FORCE_INLINE void remove(size_t index) const { FORCE_INLINE void remove(size_t index) const {
if (!data_) detail::ArrayData::removeElement(data_, index, resources_);
return;
data_->removeElement(index);
} }
// Removes all the elements of the array. // Removes all the elements of the array.
// ⚠️ Doesn't release the memory associated with the removed elements. // https://arduinojson.org/v7/api/jsonarray/clear/
// https://arduinojson.org/v6/api/jsonarray/clear/
void clear() const { void clear() const {
if (!data_) detail::ArrayData::clear(data_, resources_);
return;
data_->clear();
} }
// Gets or sets the element at the specified index. // Gets or sets the element at the specified index.
// https://arduinojson.org/v6/api/jsonarray/subscript/ // https://arduinojson.org/v7/api/jsonarray/subscript/
FORCE_INLINE detail::ElementProxy<JsonArray> operator[](size_t index) const { FORCE_INLINE detail::ElementProxy<JsonArray> operator[](size_t index) const {
return {*this, index}; return {*this, index};
} }
// Creates an object and appends it to the array.
// https://arduinojson.org/v6/api/jsonarray/createnestedobject/
FORCE_INLINE JsonObject createNestedObject() const;
// Creates an array and appends it to the array.
// https://arduinojson.org/v6/api/jsonarray/createnestedarray/
FORCE_INLINE JsonArray createNestedArray() const {
return add().to<JsonArray>();
}
operator JsonVariantConst() const { operator JsonVariantConst() const {
return JsonVariantConst(collectionToVariant(data_)); return JsonVariantConst(collectionToVariant(data_), resources_);
} }
// Returns true if the reference is unbound. // Returns true if the reference is unbound.
// https://arduinojson.org/v6/api/jsonarray/isnull/ // https://arduinojson.org/v7/api/jsonarray/isnull/
FORCE_INLINE bool isNull() const { FORCE_INLINE bool isNull() const {
return data_ == 0; return data_ == 0;
} }
// Returns true if the reference is bound. // Returns true if the reference is bound.
// https://arduinojson.org/v6/api/jsonarray/isnull/ // https://arduinojson.org/v7/api/jsonarray/isnull/
FORCE_INLINE operator bool() const { FORCE_INLINE operator bool() const {
return data_ != 0; return data_ != 0;
} }
// Returns the number of bytes occupied by the array.
// https://arduinojson.org/v6/api/jsonarray/memoryusage/
FORCE_INLINE size_t memoryUsage() const {
return data_ ? data_->memoryUsage() : 0;
}
// Returns the depth (nesting level) of the array. // Returns the depth (nesting level) of the array.
// https://arduinojson.org/v6/api/jsonarray/nesting/ // https://arduinojson.org/v7/api/jsonarray/nesting/
FORCE_INLINE size_t nesting() const { FORCE_INLINE size_t nesting() const {
return variantNesting(collectionToVariant(data_)); return detail::VariantData::nesting(collectionToVariant(data_), resources_);
} }
// Returns the number of elements in the array. // Returns the number of elements in the array.
// https://arduinojson.org/v6/api/jsonarray/size/ // https://arduinojson.org/v7/api/jsonarray/size/
FORCE_INLINE size_t size() const { FORCE_INLINE size_t size() const {
return data_ ? data_->size() : 0; return data_ ? data_->size(resources_) : 0;
}
// DEPRECATED: use add<JsonVariant>() instead
ARDUINOJSON_DEPRECATED("use add<JsonVariant>() instead")
JsonVariant add() const {
return add<JsonVariant>();
}
// DEPRECATED: use add<JsonArray>() instead
ARDUINOJSON_DEPRECATED("use add<JsonArray>() instead")
JsonArray createNestedArray() const {
return add<JsonArray>();
}
// DEPRECATED: use add<JsonObject>() instead
ARDUINOJSON_DEPRECATED("use add<JsonObject>() instead")
JsonObject createNestedObject() const;
// DEPRECATED: always returns zero
ARDUINOJSON_DEPRECATED("always returns zero")
size_t memoryUsage() const {
return 0;
} }
private: private:
detail::MemoryPool* getPool() const { detail::ResourceManager* getResourceManager() const {
return pool_; return resources_;
} }
detail::VariantData* getData() const { detail::VariantData* getData() const {
@@ -179,33 +190,8 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
return collectionToVariant(data_); return collectionToVariant(data_);
} }
detail::CollectionData* data_; detail::ArrayData* data_;
detail::MemoryPool* pool_; detail::ResourceManager* resources_;
};
template <>
struct Converter<JsonArray> : private detail::VariantAttorney {
static void toJson(JsonVariantConst src, JsonVariant dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst));
}
static JsonArray fromJson(JsonVariant src) {
auto data = getData(src);
auto pool = getPool(src);
return JsonArray(pool, data != 0 ? data->asArray() : 0);
}
static detail::InvalidConversion<JsonVariantConst, JsonArray> fromJson(
JsonVariantConst);
static bool checkJson(JsonVariantConst) {
return false;
}
static bool checkJson(JsonVariant src) {
auto data = getData(src);
return data && data->isArray();
}
}; };
ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -13,7 +13,7 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
class JsonObject; class JsonObject;
// A read-only reference to an array in a JsonDocument // A read-only reference to an array in a JsonDocument
// https://arduinojson.org/v6/api/jsonarrayconst/ // https://arduinojson.org/v7/api/jsonarrayconst/
class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> { class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
friend class JsonArray; friend class JsonArray;
friend class detail::VariantAttorney; friend class detail::VariantAttorney;
@@ -22,15 +22,15 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
typedef JsonArrayConstIterator iterator; typedef JsonArrayConstIterator iterator;
// Returns an iterator to the first element of the array. // Returns an iterator to the first element of the array.
// https://arduinojson.org/v6/api/jsonarrayconst/begin/ // https://arduinojson.org/v7/api/jsonarrayconst/begin/
FORCE_INLINE iterator begin() const { FORCE_INLINE iterator begin() const {
if (!data_) if (!data_)
return iterator(); return iterator();
return iterator(data_->head()); return iterator(data_->createIterator(resources_), resources_);
} }
// Returns an iterator to the element following the last element of the array. // Returns an iterator to the element following the last element of the array.
// https://arduinojson.org/v6/api/jsonarrayconst/end/ // https://arduinojson.org/v7/api/jsonarrayconst/end/
FORCE_INLINE iterator end() const { FORCE_INLINE iterator end() const {
return iterator(); return iterator();
} }
@@ -39,72 +39,49 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
FORCE_INLINE JsonArrayConst() : data_(0) {} FORCE_INLINE JsonArrayConst() : data_(0) {}
// INTERNAL USE ONLY // INTERNAL USE ONLY
FORCE_INLINE JsonArrayConst(const detail::CollectionData* data) FORCE_INLINE JsonArrayConst(const detail::ArrayData* data,
: data_(data) {} const detail::ResourceManager* resources)
: data_(data), resources_(resources) {}
// Compares the content of two arrays.
// Returns true if the two arrays are equal.
FORCE_INLINE bool operator==(JsonArrayConst rhs) const {
if (data_ == rhs.data_)
return true;
if (!data_ || !rhs.data_)
return false;
iterator it1 = begin();
iterator it2 = rhs.begin();
for (;;) {
bool end1 = it1 == end();
bool end2 = it2 == rhs.end();
if (end1 && end2)
return true;
if (end1 || end2)
return false;
if (*it1 != *it2)
return false;
++it1;
++it2;
}
}
// Returns the element at the specified index. // Returns the element at the specified index.
// https://arduinojson.org/v6/api/jsonarrayconst/subscript/ // https://arduinojson.org/v7/api/jsonarrayconst/subscript/
FORCE_INLINE JsonVariantConst operator[](size_t index) const { FORCE_INLINE JsonVariantConst operator[](size_t index) const {
return JsonVariantConst(data_ ? data_->getElement(index) : 0); return JsonVariantConst(
detail::ArrayData::getElement(data_, index, resources_), resources_);
} }
operator JsonVariantConst() const { operator JsonVariantConst() const {
return JsonVariantConst(collectionToVariant(data_)); return JsonVariantConst(getData(), resources_);
} }
// Returns true if the reference is unbound. // Returns true if the reference is unbound.
// https://arduinojson.org/v6/api/jsonarrayconst/isnull/ // https://arduinojson.org/v7/api/jsonarrayconst/isnull/
FORCE_INLINE bool isNull() const { FORCE_INLINE bool isNull() const {
return data_ == 0; return data_ == 0;
} }
// Returns true if the reference is bound. // Returns true if the reference is bound.
// https://arduinojson.org/v6/api/jsonarrayconst/isnull/ // https://arduinojson.org/v7/api/jsonarrayconst/isnull/
FORCE_INLINE operator bool() const { FORCE_INLINE operator bool() const {
return data_ != 0; return data_ != 0;
} }
// Returns the number of bytes occupied by the array.
// https://arduinojson.org/v6/api/jsonarrayconst/memoryusage/
FORCE_INLINE size_t memoryUsage() const {
return data_ ? data_->memoryUsage() : 0;
}
// Returns the depth (nesting level) of the array. // Returns the depth (nesting level) of the array.
// https://arduinojson.org/v6/api/jsonarrayconst/nesting/ // https://arduinojson.org/v7/api/jsonarrayconst/nesting/
FORCE_INLINE size_t nesting() const { FORCE_INLINE size_t nesting() const {
return variantNesting(collectionToVariant(data_)); return detail::VariantData::nesting(getData(), resources_);
} }
// Returns the number of elements in the array. // Returns the number of elements in the array.
// https://arduinojson.org/v6/api/jsonarrayconst/size/ // https://arduinojson.org/v7/api/jsonarrayconst/size/
FORCE_INLINE size_t size() const { FORCE_INLINE size_t size() const {
return data_ ? data_->size() : 0; return data_ ? data_->size(resources_) : 0;
}
// DEPRECATED: always returns zero
ARDUINOJSON_DEPRECATED("always returns zero")
size_t memoryUsage() const {
return 0;
} }
private: private:
@@ -112,24 +89,31 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
return collectionToVariant(data_); return collectionToVariant(data_);
} }
const detail::CollectionData* data_; const detail::ArrayData* data_;
const detail::ResourceManager* resources_;
}; };
template <> // Compares the content of two arrays.
struct Converter<JsonArrayConst> : private detail::VariantAttorney { // Returns true if the two arrays are equal.
static void toJson(JsonVariantConst src, JsonVariant dst) { inline bool operator==(JsonArrayConst lhs, JsonArrayConst rhs) {
variantCopyFrom(getData(dst), getData(src), getPool(dst)); if (!lhs && !rhs)
} return true;
if (!lhs || !rhs)
return false;
static JsonArrayConst fromJson(JsonVariantConst src) { auto a = lhs.begin();
auto data = getData(src); auto b = rhs.begin();
return data ? data->asArray() : 0;
}
static bool checkJson(JsonVariantConst src) { for (;;) {
auto data = getData(src); if (a == b) // same pointer or both null
return data && data->isArray(); return true;
if (a == lhs.end() || b == rhs.end())
return false;
if (*a != *b)
return false;
++a;
++b;
}
} }
};
ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@@ -1,36 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Array/JsonArray.hpp>
#include <ArduinoJson/Object/JsonObject.hpp>
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
inline JsonObject JsonArray::createNestedObject() const {
return add().to<JsonObject>();
}
ARDUINOJSON_END_PUBLIC_NAMESPACE
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TDerived>
inline JsonArray VariantRefBase<TDerived>::createNestedArray() const {
return add().template to<JsonArray>();
}
template <typename TDerived>
inline JsonObject VariantRefBase<TDerived>::createNestedObject() const {
return add().template to<JsonObject>();
}
template <typename TDerived>
inline ElementProxy<TDerived> VariantRefBase<TDerived>::operator[](
size_t index) const {
return ElementProxy<TDerived>(derived(), index);
}
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -1,121 +1,96 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
#include <ArduinoJson/Variant/JsonVariant.hpp> #include <ArduinoJson/Variant/JsonVariant.hpp>
#include <ArduinoJson/Variant/SlotFunctions.hpp>
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
class VariantPtr { template <typename T>
class Ptr {
public: public:
VariantPtr(detail::MemoryPool* pool, detail::VariantData* data) Ptr(T value) : value_(value) {}
: variant_(pool, data) {}
JsonVariant* operator->() { T* operator->() {
return &variant_; return &value_;
} }
JsonVariant& operator*() { T& operator*() {
return variant_; return value_;
} }
private: private:
JsonVariant variant_; T value_;
}; };
class JsonArrayIterator { class JsonArrayIterator {
friend class JsonArray; friend class JsonArray;
public: public:
JsonArrayIterator() : slot_(0) {} JsonArrayIterator() {}
explicit JsonArrayIterator(detail::MemoryPool* pool, explicit JsonArrayIterator(detail::ArrayData::iterator iterator,
detail::VariantSlot* slot) detail::ResourceManager* resources)
: pool_(pool), slot_(slot) {} : iterator_(iterator), resources_(resources) {}
JsonVariant operator*() const { JsonVariant operator*() {
return JsonVariant(pool_, slot_->data()); return JsonVariant(iterator_.data(), resources_);
} }
VariantPtr operator->() { Ptr<JsonVariant> operator->() {
return VariantPtr(pool_, slot_->data()); return operator*();
} }
bool operator==(const JsonArrayIterator& other) const { bool operator==(const JsonArrayIterator& other) const {
return slot_ == other.slot_; return iterator_ == other.iterator_;
} }
bool operator!=(const JsonArrayIterator& other) const { bool operator!=(const JsonArrayIterator& other) const {
return slot_ != other.slot_; return iterator_ != other.iterator_;
} }
JsonArrayIterator& operator++() { JsonArrayIterator& operator++() {
slot_ = slot_->next(); iterator_.next(resources_);
return *this;
}
JsonArrayIterator& operator+=(size_t distance) {
slot_ = slot_->next(distance);
return *this; return *this;
} }
private: private:
detail::MemoryPool* pool_; detail::ArrayData::iterator iterator_;
detail::VariantSlot* slot_; detail::ResourceManager* resources_;
};
class VariantConstPtr {
public:
VariantConstPtr(const detail::VariantData* data) : variant_(data) {}
JsonVariantConst* operator->() {
return &variant_;
}
JsonVariantConst& operator*() {
return variant_;
}
private:
JsonVariantConst variant_;
}; };
class JsonArrayConstIterator { class JsonArrayConstIterator {
friend class JsonArray; friend class JsonArray;
public: public:
JsonArrayConstIterator() : slot_(0) {} JsonArrayConstIterator() {}
explicit JsonArrayConstIterator(const detail::VariantSlot* slot) explicit JsonArrayConstIterator(detail::ArrayData::iterator iterator,
: slot_(slot) {} const detail::ResourceManager* resources)
: iterator_(iterator), resources_(resources) {}
JsonVariantConst operator*() const { JsonVariantConst operator*() const {
return JsonVariantConst(slot_->data()); return JsonVariantConst(iterator_.data(), resources_);
} }
VariantConstPtr operator->() { Ptr<JsonVariantConst> operator->() {
return VariantConstPtr(slot_->data()); return operator*();
} }
bool operator==(const JsonArrayConstIterator& other) const { bool operator==(const JsonArrayConstIterator& other) const {
return slot_ == other.slot_; return iterator_ == other.iterator_;
} }
bool operator!=(const JsonArrayConstIterator& other) const { bool operator!=(const JsonArrayConstIterator& other) const {
return slot_ != other.slot_; return iterator_ != other.iterator_;
} }
JsonArrayConstIterator& operator++() { JsonArrayConstIterator& operator++() {
slot_ = slot_->next(); iterator_.next(resources_);
return *this;
}
JsonArrayConstIterator& operator+=(size_t distance) {
slot_ = slot_->next(distance);
return *this; return *this;
} }
private: private:
const detail::VariantSlot* slot_; detail::ArrayData::iterator iterator_;
const detail::ResourceManager* resources_;
}; };
ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -18,7 +18,7 @@ copyArray(const T& src, JsonVariant dst) {
} }
// Copies values from an array to a JsonArray or a JsonVariant. // Copies values from an array to a JsonArray or a JsonVariant.
// https://arduinojson.org/v6/api/misc/copyarray/ // https://arduinojson.org/v7/api/misc/copyarray/
template <typename T, size_t N, typename TDestination> template <typename T, size_t N, typename TDestination>
inline typename detail::enable_if< inline typename detail::enable_if<
!detail::is_base_of<JsonDocument, TDestination>::value, bool>::type !detail::is_base_of<JsonDocument, TDestination>::value, bool>::type
@@ -27,14 +27,14 @@ copyArray(T (&src)[N], const TDestination& dst) {
} }
// Copies values from an array to a JsonArray or a JsonVariant. // Copies values from an array to a JsonArray or a JsonVariant.
// https://arduinojson.org/v6/api/misc/copyarray/ // https://arduinojson.org/v7/api/misc/copyarray/
template <typename T, typename TDestination> template <typename T, typename TDestination>
inline typename detail::enable_if< inline typename detail::enable_if<
!detail::is_base_of<JsonDocument, TDestination>::value, bool>::type !detail::is_base_of<JsonDocument, TDestination>::value, bool>::type
copyArray(const T* src, size_t len, const TDestination& dst) { copyArray(const T* src, size_t len, const TDestination& dst) {
bool ok = true; bool ok = true;
for (size_t i = 0; i < len; i++) { for (size_t i = 0; i < len; i++) {
ok &= copyArray(src[i], dst.add()); ok &= copyArray(src[i], dst.template add<JsonVariant>());
} }
return ok; return ok;
} }
@@ -47,14 +47,14 @@ inline bool copyArray(const char* src, size_t, const TDestination& dst) {
} }
// Copies values from an array to a JsonDocument. // Copies values from an array to a JsonDocument.
// https://arduinojson.org/v6/api/misc/copyarray/ // https://arduinojson.org/v7/api/misc/copyarray/
template <typename T> template <typename T>
inline bool copyArray(const T& src, JsonDocument& dst) { inline bool copyArray(const T& src, JsonDocument& dst) {
return copyArray(src, dst.to<JsonArray>()); return copyArray(src, dst.to<JsonArray>());
} }
// Copies an array to a JsonDocument. // Copies an array to a JsonDocument.
// https://arduinojson.org/v6/api/misc/copyarray/ // https://arduinojson.org/v7/api/misc/copyarray/
template <typename T> template <typename T>
inline bool copyArray(const T* src, size_t len, JsonDocument& dst) { inline bool copyArray(const T* src, size_t len, JsonDocument& dst) {
return copyArray(src, len, dst.to<JsonArray>()); return copyArray(src, len, dst.to<JsonArray>());
@@ -70,14 +70,14 @@ copyArray(JsonVariantConst src, T& dst) {
} }
// Copies values from a JsonArray or JsonVariant to an array. // Copies values from a JsonArray or JsonVariant to an array.
// https://arduinojson.org/v6/api/misc/copyarray/ // https://arduinojson.org/v7/api/misc/copyarray/
template <typename T, size_t N> template <typename T, size_t N>
inline size_t copyArray(JsonArrayConst src, T (&dst)[N]) { inline size_t copyArray(JsonArrayConst src, T (&dst)[N]) {
return copyArray(src, dst, N); return copyArray(src, dst, N);
} }
// Copies values from a JsonArray or JsonVariant to an array. // Copies values from a JsonArray or JsonVariant to an array.
// https://arduinojson.org/v6/api/misc/copyarray/ // https://arduinojson.org/v7/api/misc/copyarray/
template <typename T> template <typename T>
inline size_t copyArray(JsonArrayConst src, T* dst, size_t len) { inline size_t copyArray(JsonArrayConst src, T* dst, size_t len) {
size_t i = 0; size_t i = 0;
@@ -101,7 +101,7 @@ inline size_t copyArray(JsonVariantConst src, char (&dst)[N]) {
} }
// Copies values from a JsonDocument to an array. // Copies values from a JsonDocument to an array.
// https://arduinojson.org/v6/api/misc/copyarray/ // https://arduinojson.org/v7/api/misc/copyarray/
template <typename TSource, typename T> template <typename TSource, typename T>
inline typename detail::enable_if< inline typename detail::enable_if<
detail::is_array<T>::value && detail::is_array<T>::value &&

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -11,74 +11,108 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
class MemoryPool;
class VariantData; class VariantData;
class VariantSlot; class VariantSlot;
class CollectionData { class CollectionIterator {
VariantSlot* head_; friend class CollectionData;
VariantSlot* tail_;
public: public:
// Must be a POD! CollectionIterator() : slot_(nullptr), currentId_(NULL_SLOT) {}
// - no constructor
// - no destructor
// - no virtual
// - no inheritance
// Array only void next(const ResourceManager* resources);
VariantData* addElement(MemoryPool* pool); bool done() const {
return slot_ == nullptr;
VariantData* getElement(size_t index) const;
VariantData* getOrAddElement(size_t index, MemoryPool* pool);
void removeElement(size_t index);
// Object only
template <typename TAdaptedString>
VariantData* addMember(TAdaptedString key, MemoryPool* pool);
template <typename TAdaptedString>
VariantData* getMember(TAdaptedString key) const;
template <typename TAdaptedString>
VariantData* getOrAddMember(TAdaptedString key, MemoryPool* pool);
template <typename TAdaptedString>
void removeMember(TAdaptedString key) {
removeSlot(getSlot(key));
} }
template <typename TAdaptedString> bool operator==(const CollectionIterator& other) const {
bool containsKey(const TAdaptedString& key) const; return slot_ == other.slot_;
// Generic
void clear();
size_t memoryUsage() const;
size_t size() const;
VariantSlot* addSlot(MemoryPool*);
void removeSlot(VariantSlot* slot);
bool copyFrom(const CollectionData& src, MemoryPool* pool);
VariantSlot* head() const {
return head_;
} }
void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance); bool operator!=(const CollectionIterator& other) const {
return slot_ != other.slot_;
}
VariantData* operator->() {
ARDUINOJSON_ASSERT(slot_ != nullptr);
return data();
}
VariantData& operator*() {
ARDUINOJSON_ASSERT(slot_ != nullptr);
return *data();
}
const VariantData& operator*() const {
ARDUINOJSON_ASSERT(slot_ != nullptr);
return *data();
}
const char* key() const;
bool ownsKey() const;
void setKey(StringNode*);
void setKey(const char*);
VariantData* data() {
return reinterpret_cast<VariantData*>(slot_);
}
const VariantData* data() const {
return reinterpret_cast<const VariantData*>(slot_);
}
private: private:
VariantSlot* getSlot(size_t index) const; CollectionIterator(VariantSlot* slot, SlotId slotId);
template <typename TAdaptedString> VariantSlot* slot_;
VariantSlot* getSlot(TAdaptedString key) const; SlotId currentId_, nextId_;
};
VariantSlot* getPreviousSlot(VariantSlot*) const; class CollectionData {
SlotId head_ = NULL_SLOT;
SlotId tail_ = NULL_SLOT;
public:
// Placement new
static void* operator new(size_t, void* p) noexcept {
return p;
}
static void operator delete(void*, void*) noexcept {}
using iterator = CollectionIterator;
iterator createIterator(const ResourceManager* resources) const {
return iterator(resources->getSlot(head_), head_);
}
size_t size(const ResourceManager*) const;
size_t nesting(const ResourceManager*) const;
void clear(ResourceManager* resources);
static void clear(CollectionData* collection, ResourceManager* resources) {
if (!collection)
return;
collection->clear(resources);
}
void remove(iterator it, ResourceManager* resources);
static void remove(CollectionData* collection, iterator it,
ResourceManager* resources) {
if (collection)
return collection->remove(it, resources);
}
protected:
iterator addSlot(ResourceManager*);
private:
SlotWithId getPreviousSlot(VariantSlot*, const ResourceManager*) const;
void releaseSlot(SlotWithId, ResourceManager*);
}; };
inline const VariantData* collectionToVariant( inline const VariantData* collectionToVariant(

View File

@@ -1,197 +1,133 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
#include <ArduinoJson/Collection/CollectionData.hpp> #include <ArduinoJson/Collection/CollectionData.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp> #include <ArduinoJson/Memory/Alignment.hpp>
#include <ArduinoJson/Strings/StringAdapters.hpp> #include <ArduinoJson/Strings/StringAdapters.hpp>
#include <ArduinoJson/Variant/VariantCompare.hpp>
#include <ArduinoJson/Variant/VariantData.hpp> #include <ArduinoJson/Variant/VariantData.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) { inline CollectionIterator::CollectionIterator(VariantSlot* slot, SlotId slotId)
VariantSlot* slot = pool->allocVariant(); : slot_(slot), currentId_(slotId) {
if (!slot) nextId_ = slot_ ? slot_->next() : NULL_SLOT;
return 0; }
if (tail_) { inline const char* CollectionIterator::key() const {
ARDUINOJSON_ASSERT(pool->owns(tail_)); // Can't alter a linked array/object ARDUINOJSON_ASSERT(slot_ != nullptr);
tail_->setNextNotNull(slot); return slot_->key();
tail_ = slot; }
inline void CollectionIterator::setKey(const char* s) {
ARDUINOJSON_ASSERT(slot_ != nullptr);
ARDUINOJSON_ASSERT(s != nullptr);
return slot_->setKey(s);
}
inline void CollectionIterator::setKey(StringNode* s) {
ARDUINOJSON_ASSERT(slot_ != nullptr);
ARDUINOJSON_ASSERT(s != nullptr);
return slot_->setKey(s);
}
inline bool CollectionIterator::ownsKey() const {
ARDUINOJSON_ASSERT(slot_ != nullptr);
return slot_->ownsKey();
}
inline void CollectionIterator::next(const ResourceManager* resources) {
ARDUINOJSON_ASSERT(currentId_ != NULL_SLOT);
slot_ = resources->getSlot(nextId_);
currentId_ = nextId_;
if (slot_)
nextId_ = slot_->next();
}
inline CollectionData::iterator CollectionData::addSlot(
ResourceManager* resources) {
auto slot = resources->allocSlot();
if (!slot)
return {};
if (tail_ != NULL_SLOT) {
auto tail = resources->getSlot(tail_);
tail->setNext(slot.id());
tail_ = slot.id();
} else { } else {
head_ = slot; head_ = slot.id();
tail_ = slot; tail_ = slot.id();
}
return iterator(slot, slot.id());
} }
slot->clear(); inline void CollectionData::clear(ResourceManager* resources) {
return slot; auto next = head_;
while (next != NULL_SLOT) {
auto currId = next;
auto slot = resources->getSlot(next);
next = slot->next();
releaseSlot(SlotWithId(slot, currId), resources);
} }
inline VariantData* CollectionData::addElement(MemoryPool* pool) { head_ = NULL_SLOT;
return slotData(addSlot(pool)); tail_ = NULL_SLOT;
} }
template <typename TAdaptedString> inline SlotWithId CollectionData::getPreviousSlot(
inline VariantData* CollectionData::addMember(TAdaptedString key, VariantSlot* target, const ResourceManager* resources) const {
MemoryPool* pool) { auto prev = SlotWithId();
VariantSlot* slot = addSlot(pool); auto currentId = head_;
if (!slotSetKey(slot, key, pool)) { while (currentId != NULL_SLOT) {
removeSlot(slot); auto currentSlot = resources->getSlot(currentId);
return 0; if (currentSlot == target)
return prev;
prev = SlotWithId(currentSlot, currentId);
currentId = currentSlot->next();
} }
return slot->data(); return SlotWithId();
} }
inline void CollectionData::clear() { inline void CollectionData::remove(iterator it, ResourceManager* resources) {
head_ = 0; if (it.done())
tail_ = 0;
}
template <typename TAdaptedString>
inline bool CollectionData::containsKey(const TAdaptedString& key) const {
return getSlot(key) != 0;
}
inline bool CollectionData::copyFrom(const CollectionData& src,
MemoryPool* pool) {
clear();
for (VariantSlot* s = src.head_; s; s = s->next()) {
VariantData* var;
if (s->key() != 0) {
JsonString key(s->key(),
s->ownsKey() ? JsonString::Copied : JsonString::Linked);
var = addMember(adaptString(key), pool);
} else {
var = addElement(pool);
}
if (!var)
return false;
if (!var->copyFrom(*s->data(), pool))
return false;
}
return true;
}
template <typename TAdaptedString>
inline VariantSlot* CollectionData::getSlot(TAdaptedString key) const {
if (key.isNull())
return 0;
VariantSlot* slot = head_;
while (slot) {
if (stringEquals(key, adaptString(slot->key())))
break;
slot = slot->next();
}
return slot;
}
inline VariantSlot* CollectionData::getSlot(size_t index) const {
if (!head_)
return 0;
return head_->next(index);
}
inline VariantSlot* CollectionData::getPreviousSlot(VariantSlot* target) const {
VariantSlot* current = head_;
while (current) {
VariantSlot* next = current->next();
if (next == target)
return current;
current = next;
}
return 0;
}
template <typename TAdaptedString>
inline VariantData* CollectionData::getMember(TAdaptedString key) const {
VariantSlot* slot = getSlot(key);
return slot ? slot->data() : 0;
}
template <typename TAdaptedString>
inline VariantData* CollectionData::getOrAddMember(TAdaptedString key,
MemoryPool* pool) {
// ignore null key
if (key.isNull())
return 0;
// search a matching key
VariantSlot* slot = getSlot(key);
if (slot)
return slot->data();
return addMember(key, pool);
}
inline VariantData* CollectionData::getElement(size_t index) const {
VariantSlot* slot = getSlot(index);
return slot ? slot->data() : 0;
}
inline VariantData* CollectionData::getOrAddElement(size_t index,
MemoryPool* pool) {
VariantSlot* slot = head_;
while (slot && index > 0) {
slot = slot->next();
index--;
}
if (!slot)
index++;
while (index > 0) {
slot = addSlot(pool);
index--;
}
return slotData(slot);
}
inline void CollectionData::removeSlot(VariantSlot* slot) {
if (!slot)
return; return;
VariantSlot* prev = getPreviousSlot(slot); auto curr = it.slot_;
VariantSlot* next = slot->next(); auto prev = getPreviousSlot(curr, resources);
auto next = curr->next();
if (prev) if (prev)
prev->setNext(next); prev->setNext(next);
else else
head_ = next; head_ = next;
if (!next) if (next == NULL_SLOT)
tail_ = prev; tail_ = prev.id();
releaseSlot({it.slot_, it.currentId_}, resources);
} }
inline void CollectionData::removeElement(size_t index) { inline size_t CollectionData::nesting(const ResourceManager* resources) const {
removeSlot(getSlot(index)); size_t maxChildNesting = 0;
for (auto it = createIterator(resources); !it.done(); it.next(resources)) {
size_t childNesting = it->nesting(resources);
if (childNesting > maxChildNesting)
maxChildNesting = childNesting;
}
return maxChildNesting + 1;
} }
inline size_t CollectionData::memoryUsage() const { inline size_t CollectionData::size(const ResourceManager* resources) const {
size_t total = 0; size_t count = 0;
for (VariantSlot* s = head_; s; s = s->next()) { for (auto it = createIterator(resources); !it.done(); it.next(resources))
total += sizeof(VariantSlot) + s->data()->memoryUsage(); count++;
if (s->ownsKey()) return count;
total += strlen(s->key()) + 1;
}
return total;
} }
inline size_t CollectionData::size() const { inline void CollectionData::releaseSlot(SlotWithId slot,
return slotSize(head_); ResourceManager* resources) {
} if (slot->ownsKey())
resources->dereferenceString(slot->key());
template <typename T> slot->data()->setNull(resources);
inline void movePointer(T*& p, ptrdiff_t offset) { resources->freeSlot(slot);
if (!p)
return;
p = reinterpret_cast<T*>(
reinterpret_cast<void*>(reinterpret_cast<char*>(p) + offset));
ARDUINOJSON_ASSERT(isAligned(p));
}
inline void CollectionData::movePointers(ptrdiff_t stringDistance,
ptrdiff_t variantDistance) {
movePointer(head_, variantDistance);
movePointer(tail_, variantDistance);
for (VariantSlot* slot = head_; slot; slot = slot->next())
slot->movePointers(stringDistance, variantDistance);
} }
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -59,35 +59,75 @@
# define ARDUINOJSON_USE_DOUBLE 1 # define ARDUINOJSON_USE_DOUBLE 1
#endif #endif
// Pointer size: a heuristic to set sensible defaults
#ifndef ARDUINOJSON_SIZEOF_POINTER
# if defined(__SIZEOF_POINTER__)
# define ARDUINOJSON_SIZEOF_POINTER __SIZEOF_POINTER__
# elif defined(_WIN64) && _WIN64
# define ARDUINOJSON_SIZEOF_POINTER 8 // 64 bits
# else
# define ARDUINOJSON_SIZEOF_POINTER 4 // assume 32 bits otherwise
# endif
#endif
// Store integral values with long (0) or long long (1) // Store integral values with long (0) or long long (1)
#ifndef ARDUINOJSON_USE_LONG_LONG #ifndef ARDUINOJSON_USE_LONG_LONG
# if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ >= 4 || \ # if ARDUINOJSON_SIZEOF_POINTER >= 4 // 32 & 64 bits systems
defined(_MSC_VER)
# define ARDUINOJSON_USE_LONG_LONG 1 # define ARDUINOJSON_USE_LONG_LONG 1
# endif # else
#endif
#ifndef ARDUINOJSON_USE_LONG_LONG
# define ARDUINOJSON_USE_LONG_LONG 0 # define ARDUINOJSON_USE_LONG_LONG 0
# endif # endif
#endif
// Limit nesting as the stack is likely to be small // Limit nesting as the stack is likely to be small
#ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT #ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT
# define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10 # define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10
#endif #endif
// Number of bits to store the pointer to next node // Number of bytes to store the variant identifier
// (saves RAM but limits the number of values in a document) #ifndef ARDUINOJSON_SLOT_ID_SIZE
#ifndef ARDUINOJSON_SLOT_OFFSET_SIZE # if ARDUINOJSON_SIZEOF_POINTER <= 2
# if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ <= 2 # define ARDUINOJSON_SLOT_ID_SIZE 1 // up to 255 slots
// Address space == 16-bit => max 127 values # elif ARDUINOJSON_SIZEOF_POINTER == 4
# define ARDUINOJSON_SLOT_OFFSET_SIZE 1 # define ARDUINOJSON_SLOT_ID_SIZE 2 // up to 65535 slots
# elif defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ >= 8 || \
defined(_WIN64) && _WIN64
// Address space == 64-bit => max 2147483647 values
# define ARDUINOJSON_SLOT_OFFSET_SIZE 4
# else # else
// Address space == 32-bit => max 32767 values # define ARDUINOJSON_SLOT_ID_SIZE 4 // up to 4294967295 slots
# define ARDUINOJSON_SLOT_OFFSET_SIZE 2 # endif
#endif
// Capacity of each variant pool (in slots)
#ifndef ARDUINOJSON_POOL_CAPACITY
# if ARDUINOJSON_SIZEOF_POINTER <= 2
# define ARDUINOJSON_POOL_CAPACITY 16 // 128 bytes
# elif ARDUINOJSON_SIZEOF_POINTER == 4
# define ARDUINOJSON_POOL_CAPACITY 64 // 1024 bytes
# else
# define ARDUINOJSON_POOL_CAPACITY 128 // 3072 bytes
# endif
#endif
// Initial capacity of the pool list
#ifndef ARDUINOJSON_INITIAL_POOL_COUNT
# define ARDUINOJSON_INITIAL_POOL_COUNT 4
#endif
// Automatically call shrinkToFit() from deserializeXxx()
// Disabled by default on 8-bit platforms because it's not worth the increase in
// code size
#ifndef ARDUINOJSON_AUTO_SHRINK
# if ARDUINOJSON_SIZEOF_POINTER <= 2
# define ARDUINOJSON_AUTO_SHRINK 0
# else
# define ARDUINOJSON_AUTO_SHRINK 1
# endif
#endif
// Number of bytes to store the length of a string
#ifndef ARDUINOJSON_STRING_LENGTH_SIZE
# if ARDUINOJSON_SIZEOF_POINTER <= 2
# define ARDUINOJSON_STRING_LENGTH_SIZE 1 // up to 255 characters
# else
# define ARDUINOJSON_STRING_LENGTH_SIZE 2 // up to 65535 characters
# endif # endif
#endif #endif
@@ -195,10 +235,6 @@
# define ARDUINOJSON_TAB " " # define ARDUINOJSON_TAB " "
#endif #endif
#ifndef ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
# define ARDUINOJSON_ENABLE_STRING_DEDUPLICATION 1
#endif
#ifndef ARDUINOJSON_STRING_BUFFER_SIZE #ifndef ARDUINOJSON_STRING_BUFFER_SIZE
# define ARDUINOJSON_STRING_BUFFER_SIZE 32 # define ARDUINOJSON_STRING_BUFFER_SIZE 32
#endif #endif

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

View File

@@ -1,17 +1,24 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
#include <ArduinoJson/Namespace.hpp> #include <ArduinoJson/Variant/JsonVariant.hpp>
#include <ArduinoJson/Variant/VariantAttorney.hpp>
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
namespace DeserializationOption { namespace DeserializationOption {
class Filter { class Filter {
public: public:
explicit Filter(JsonVariantConst v) : variant_(v) {} #if ARDUINOJSON_AUTO_SHRINK
explicit Filter(JsonDocument& doc) : variant_(doc) {
doc.shrinkToFit();
}
#endif
explicit Filter(JsonVariantConst variant) : variant_(variant) {}
bool allow() const { bool allow() const {
return variant_; return variant_;

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -19,7 +19,7 @@ struct Reader {
int read() { int read() {
// clang-format off // clang-format off
return source_->read(); // Error here? See https://arduinojson.org/v6/invalid-input/ return source_->read(); // Error here? See https://arduinojson.org/v7/invalid-input/
// clang-format on // clang-format on
} }

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -15,7 +15,7 @@ struct Reader<TSource,
explicit Reader(Stream& stream) : stream_(&stream) {} explicit Reader(Stream& stream) : stream_(&stream) {}
int read() { int read() {
// don't use stream_.read() as it ignores the timeout // don't use stream_->read() as it ignores the timeout
char c; char c;
return stream_->readBytes(&c, 1) ? static_cast<unsigned char>(c) : -1; return stream_->readBytes(&c, 1) ? static_cast<unsigned char>(c) : -1;
} }

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -8,7 +8,6 @@
#include <ArduinoJson/Deserialization/DeserializationOptions.hpp> #include <ArduinoJson/Deserialization/DeserializationOptions.hpp>
#include <ArduinoJson/Deserialization/Reader.hpp> #include <ArduinoJson/Deserialization/Reader.hpp>
#include <ArduinoJson/Polyfills/utility.hpp> #include <ArduinoJson/Polyfills/utility.hpp>
#include <ArduinoJson/StringStorage/StringStorage.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
@@ -23,44 +22,62 @@ struct first_or_void<T, Rest...> {
using type = T; using type = T;
}; };
template <template <typename, typename> class TDeserializer, typename TReader, // A meta-function that returns true if T is a valid destination type for
typename TWriter> // deserialize()
TDeserializer<TReader, TWriter> makeDeserializer(MemoryPool* pool, template <class T, class = void>
TReader reader, struct is_deserialize_destination : false_type {};
TWriter writer) {
ARDUINOJSON_ASSERT(pool != 0); template <class T>
return TDeserializer<TReader, TWriter>(pool, reader, writer); struct is_deserialize_destination<
T, typename enable_if<is_same<decltype(VariantAttorney::getResourceManager(
detail::declval<T&>())),
ResourceManager*>::value>::type> : true_type {
};
template <typename TDestination>
inline void shrinkJsonDocument(TDestination&) {
// no-op by default
} }
template <template <typename, typename> class TDeserializer, typename TStream, #if ARDUINOJSON_AUTO_SHRINK
typename... Args, inline void shrinkJsonDocument(JsonDocument& doc) {
doc.shrinkToFit();
}
#endif
template <template <typename> class TDeserializer, typename TDestination,
typename TReader, typename TOptions>
DeserializationError doDeserialize(TDestination&& dst, TReader reader,
TOptions options) {
auto data = VariantAttorney::getOrCreateData(dst);
if (!data)
return DeserializationError::NoMemory;
auto resources = VariantAttorney::getResourceManager(dst);
dst.clear();
auto err = TDeserializer<TReader>(resources, reader)
.parse(*data, options.filter, options.nestingLimit);
shrinkJsonDocument(dst);
return err;
}
template <template <typename> class TDeserializer, typename TDestination,
typename TStream, typename... Args,
typename = typename enable_if< // issue #1897 typename = typename enable_if< // issue #1897
!is_integral<typename first_or_void<Args...>::type>::value>::type> !is_integral<typename first_or_void<Args...>::type>::value>::type>
DeserializationError deserialize(JsonDocument& doc, TStream&& input, DeserializationError deserialize(TDestination&& dst, TStream&& input,
Args... args) { Args... args) {
auto reader = makeReader(detail::forward<TStream>(input)); return doDeserialize<TDeserializer>(
auto data = VariantAttorney::getData(doc); dst, makeReader(detail::forward<TStream>(input)),
auto pool = VariantAttorney::getPool(doc); makeDeserializationOptions(args...));
auto options = makeDeserializationOptions(args...);
doc.clear();
return makeDeserializer<TDeserializer>(pool, reader,
makeStringStorage(input, pool))
.parse(*data, options.filter, options.nestingLimit);
} }
template <template <typename, typename> class TDeserializer, typename TChar, template <template <typename> class TDeserializer, typename TDestination,
typename Size, typename... Args, typename TChar, typename Size, typename... Args,
typename = typename enable_if<is_integral<Size>::value>::type> typename = typename enable_if<is_integral<Size>::value>::type>
DeserializationError deserialize(JsonDocument& doc, TChar* input, DeserializationError deserialize(TDestination&& dst, TChar* input,
Size inputSize, Args... args) { Size inputSize, Args... args) {
auto reader = makeReader(input, size_t(inputSize)); return doDeserialize<TDeserializer>(dst, makeReader(input, size_t(inputSize)),
auto data = VariantAttorney::getData(doc); makeDeserializationOptions(args...));
auto pool = VariantAttorney::getPool(doc);
auto options = makeDeserializationOptions(args...);
doc.clear();
return makeDeserializer<TDeserializer>(pool, reader,
makeStringStorage(input, pool))
.parse(*data, options.filter, options.nestingLimit);
} }
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -1,168 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Document/JsonDocument.hpp>
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
// Helper to implement the "base-from-member" idiom
// (we need to store the allocator before constructing JsonDocument)
template <typename TAllocator>
class AllocatorOwner {
public:
AllocatorOwner() {}
AllocatorOwner(TAllocator a) : allocator_(a) {}
void* allocate(size_t size) {
return allocator_.allocate(size);
}
void deallocate(void* ptr) {
if (ptr)
allocator_.deallocate(ptr);
}
void* reallocate(void* ptr, size_t new_size) {
return allocator_.reallocate(ptr, new_size);
}
TAllocator& allocator() {
return allocator_;
}
private:
TAllocator allocator_;
};
// A JsonDocument that uses the provided allocator to allocate its memory pool.
// https://arduinojson.org/v6/api/basicjsondocument/
template <typename TAllocator>
class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument {
public:
explicit BasicJsonDocument(size_t capa, TAllocator alloc = TAllocator())
: AllocatorOwner<TAllocator>(alloc), JsonDocument(allocPool(capa)) {}
// Copy-constructor
BasicJsonDocument(const BasicJsonDocument& src)
: AllocatorOwner<TAllocator>(src), JsonDocument() {
copyAssignFrom(src);
}
// Move-constructor
BasicJsonDocument(BasicJsonDocument&& src) : AllocatorOwner<TAllocator>(src) {
moveAssignFrom(src);
}
BasicJsonDocument(const JsonDocument& src) {
copyAssignFrom(src);
}
// Construct from variant, array, or object
template <typename T>
BasicJsonDocument(const T& src,
typename detail::enable_if<
detail::is_same<T, JsonVariant>::value ||
detail::is_same<T, JsonVariantConst>::value ||
detail::is_same<T, JsonArray>::value ||
detail::is_same<T, JsonArrayConst>::value ||
detail::is_same<T, JsonObject>::value ||
detail::is_same<T, JsonObjectConst>::value>::type* = 0)
: JsonDocument(allocPool(src.memoryUsage())) {
set(src);
}
// disambiguate
BasicJsonDocument(JsonVariant src)
: JsonDocument(allocPool(src.memoryUsage())) {
set(src);
}
~BasicJsonDocument() {
freePool();
}
BasicJsonDocument& operator=(const BasicJsonDocument& src) {
copyAssignFrom(src);
return *this;
}
BasicJsonDocument& operator=(BasicJsonDocument&& src) {
moveAssignFrom(src);
return *this;
}
template <typename T>
BasicJsonDocument& operator=(const T& src) {
size_t requiredSize = src.memoryUsage();
if (requiredSize > capacity())
reallocPool(requiredSize);
set(src);
return *this;
}
// Reduces the capacity of the memory pool to match the current usage.
// https://arduinojson.org/v6/api/basicjsondocument/shrinktofit/
void shrinkToFit() {
ptrdiff_t bytes_reclaimed = pool_.squash();
if (bytes_reclaimed == 0)
return;
void* old_ptr = pool_.buffer();
void* new_ptr = this->reallocate(old_ptr, pool_.capacity());
ptrdiff_t ptr_offset =
static_cast<char*>(new_ptr) - static_cast<char*>(old_ptr);
pool_.movePointers(ptr_offset);
data_.movePointers(ptr_offset, ptr_offset - bytes_reclaimed);
}
// Reclaims the memory leaked when removing and replacing values.
// https://arduinojson.org/v6/api/jsondocument/garbagecollect/
bool garbageCollect() {
// make a temporary clone and move assign
BasicJsonDocument tmp(*this);
if (!tmp.capacity())
return false;
moveAssignFrom(tmp);
return true;
}
using AllocatorOwner<TAllocator>::allocator;
private:
detail::MemoryPool allocPool(size_t requiredSize) {
size_t capa = detail::addPadding(requiredSize);
return {reinterpret_cast<char*>(this->allocate(capa)), capa};
}
void reallocPool(size_t requiredSize) {
size_t capa = detail::addPadding(requiredSize);
if (capa == pool_.capacity())
return;
freePool();
replacePool(allocPool(detail::addPadding(requiredSize)));
}
void freePool() {
this->deallocate(getPool()->buffer());
}
void copyAssignFrom(const JsonDocument& src) {
reallocPool(src.capacity());
set(src);
}
void moveAssignFrom(BasicJsonDocument& src) {
freePool();
data_ = src.data_;
pool_ = src.pool_;
src.data_.setNull();
src.pool_ = {0, 0};
}
};
ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@@ -1,32 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Document/BasicJsonDocument.hpp>
#include <stdlib.h> // malloc, free
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
// The allocator of DynamicJsonDocument.
struct DefaultAllocator {
void* allocate(size_t size) {
return malloc(size);
}
void deallocate(void* ptr) {
free(ptr);
}
void* reallocate(void* ptr, size_t new_size) {
return realloc(ptr, new_size);
}
};
// A JsonDocument with a memory pool in the heap.
// https://arduinojson.org/v6/api/dynamicjsondocument/
typedef BasicJsonDocument<DefaultAllocator> DynamicJsonDocument;
ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@@ -1,107 +1,142 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
#include <ArduinoJson/Array/ElementProxy.hpp> #include <ArduinoJson/Array/ElementProxy.hpp>
#include <ArduinoJson/Memory/MemoryPool.hpp> #include <ArduinoJson/Memory/Allocator.hpp>
#include <ArduinoJson/Memory/ResourceManager.hpp>
#include <ArduinoJson/Object/JsonObject.hpp> #include <ArduinoJson/Object/JsonObject.hpp>
#include <ArduinoJson/Object/MemberProxy.hpp> #include <ArduinoJson/Object/MemberProxy.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp> #include <ArduinoJson/Polyfills/utility.hpp>
#include <ArduinoJson/Variant/JsonVariantConst.hpp> #include <ArduinoJson/Variant/JsonVariantConst.hpp>
#include <ArduinoJson/Variant/VariantTo.hpp> #include <ArduinoJson/Variant/VariantTo.hpp>
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
// A JSON document. // A JSON document.
// https://arduinojson.org/v6/api/jsondocument/ // https://arduinojson.org/v7/api/jsondocument/
class JsonDocument : public detail::VariantOperators<const JsonDocument&> { class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
friend class detail::VariantAttorney; friend class detail::VariantAttorney;
public: public:
JsonDocument(const JsonDocument&) = delete; explicit JsonDocument(Allocator* alloc = detail::DefaultAllocator::instance())
JsonDocument& operator=(const JsonDocument&) = delete; : resources_(alloc) {}
// Copy-constructor
JsonDocument(const JsonDocument& src) : JsonDocument(src.allocator()) {
set(src);
}
// Move-constructor
JsonDocument(JsonDocument&& src) : JsonDocument() {
swap(*this, src);
}
// Construct from variant, array, or object
template <typename T>
JsonDocument(const T& src,
Allocator* alloc = detail::DefaultAllocator::instance(),
typename detail::enable_if<
detail::is_same<T, JsonVariant>::value ||
detail::is_same<T, JsonVariantConst>::value ||
detail::is_same<T, JsonArray>::value ||
detail::is_same<T, JsonArrayConst>::value ||
detail::is_same<T, JsonObject>::value ||
detail::is_same<T, JsonObjectConst>::value>::type* = 0)
: JsonDocument(alloc) {
set(src);
}
JsonDocument& operator=(JsonDocument src) {
swap(*this, src);
return *this;
}
template <typename T>
JsonDocument& operator=(const T& src) {
set(src);
return *this;
}
Allocator* allocator() const {
return resources_.allocator();
}
// Reduces the capacity of the memory pool to match the current usage.
// https://arduinojson.org/v7/api/jsondocument/shrinktofit/
void shrinkToFit() {
resources_.shrinkToFit();
}
// Casts the root to the specified type. // Casts the root to the specified type.
// https://arduinojson.org/v6/api/jsondocument/as/ // https://arduinojson.org/v7/api/jsondocument/as/
template <typename T> template <typename T>
T as() { T as() {
return getVariant().template as<T>(); return getVariant().template as<T>();
} }
// Casts the root to the specified type. // Casts the root to the specified type.
// https://arduinojson.org/v6/api/jsondocument/as/ // https://arduinojson.org/v7/api/jsondocument/as/
template <typename T> template <typename T>
T as() const { T as() const {
return getVariant().template as<T>(); return getVariant().template as<T>();
} }
// Empties the document and resets the memory pool // Empties the document and resets the memory pool
// https://arduinojson.org/v6/api/jsondocument/clear/ // https://arduinojson.org/v7/api/jsondocument/clear/
void clear() { void clear() {
pool_.clear(); resources_.clear();
data_.setNull(); data_.reset();
} }
// Returns true if the root is of the specified type. // Returns true if the root is of the specified type.
// https://arduinojson.org/v6/api/jsondocument/is/ // https://arduinojson.org/v7/api/jsondocument/is/
template <typename T> template <typename T>
bool is() { bool is() {
return getVariant().template is<T>(); return getVariant().template is<T>();
} }
// Returns true if the root is of the specified type. // Returns true if the root is of the specified type.
// https://arduinojson.org/v6/api/jsondocument/is/ // https://arduinojson.org/v7/api/jsondocument/is/
template <typename T> template <typename T>
bool is() const { bool is() const {
return getVariant().template is<T>(); return getVariant().template is<T>();
} }
// Returns true if the root is null. // Returns true if the root is null.
// https://arduinojson.org/v6/api/jsondocument/isnull/ // https://arduinojson.org/v7/api/jsondocument/isnull/
bool isNull() const { bool isNull() const {
return getVariant().isNull(); return getVariant().isNull();
} }
// Returns the number of used bytes in the memory pool.
// https://arduinojson.org/v6/api/jsondocument/memoryusage/
size_t memoryUsage() const {
return pool_.size();
}
// Returns trues if the memory pool was too small. // Returns trues if the memory pool was too small.
// https://arduinojson.org/v6/api/jsondocument/overflowed/ // https://arduinojson.org/v7/api/jsondocument/overflowed/
bool overflowed() const { bool overflowed() const {
return pool_.overflowed(); return resources_.overflowed();
} }
// Returns the depth (nesting level) of the array. // Returns the depth (nesting level) of the array.
// https://arduinojson.org/v6/api/jsondocument/nesting/ // https://arduinojson.org/v7/api/jsondocument/nesting/
size_t nesting() const { size_t nesting() const {
return variantNesting(&data_); return data_.nesting(&resources_);
}
// Returns the capacity of the memory pool.
// https://arduinojson.org/v6/api/jsondocument/capacity/
size_t capacity() const {
return pool_.capacity();
} }
// Returns the number of elements in the root array or object. // Returns the number of elements in the root array or object.
// https://arduinojson.org/v6/api/jsondocument/size/ // https://arduinojson.org/v7/api/jsondocument/size/
size_t size() const { size_t size() const {
return data_.size(); return data_.size(&resources_);
} }
// Copies the specified document. // Copies the specified document.
// https://arduinojson.org/v6/api/jsondocument/set/ // https://arduinojson.org/v7/api/jsondocument/set/
bool set(const JsonDocument& src) { bool set(const JsonDocument& src) {
return to<JsonVariant>().set(src.as<JsonVariantConst>()); return to<JsonVariant>().set(src.as<JsonVariantConst>());
} }
// Replaces the root with the specified value. // Replaces the root with the specified value.
// https://arduinojson.org/v6/api/jsondocument/set/ // https://arduinojson.org/v7/api/jsondocument/set/
template <typename T> template <typename T>
typename detail::enable_if<!detail::is_base_of<JsonDocument, T>::value, typename detail::enable_if<!detail::is_base_of<JsonDocument, T>::value,
bool>::type bool>::type
@@ -110,69 +145,29 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
} }
// Clears the document and converts it to the specified type. // Clears the document and converts it to the specified type.
// https://arduinojson.org/v6/api/jsondocument/to/ // https://arduinojson.org/v7/api/jsondocument/to/
template <typename T> template <typename T>
typename detail::VariantTo<T>::type to() { typename detail::VariantTo<T>::type to() {
clear(); clear();
return getVariant().template to<T>(); return getVariant().template to<T>();
} }
// Creates an array and appends it to the root array.
// https://arduinojson.org/v6/api/jsondocument/createnestedarray/
JsonArray createNestedArray() {
return add().to<JsonArray>();
}
// Creates an array and adds it to the root object.
// https://arduinojson.org/v6/api/jsondocument/createnestedarray/
template <typename TChar>
JsonArray createNestedArray(TChar* key) {
return operator[](key).template to<JsonArray>();
}
// Creates an array and adds it to the root object.
// https://arduinojson.org/v6/api/jsondocument/createnestedarray/
template <typename TString>
JsonArray createNestedArray(const TString& key) {
return operator[](key).template to<JsonArray>();
}
// Creates an object and appends it to the root array.
// https://arduinojson.org/v6/api/jsondocument/createnestedobject/
JsonObject createNestedObject() {
return add().to<JsonObject>();
}
// Creates an object and adds it to the root object.
// https://arduinojson.org/v6/api/jsondocument/createnestedobject/
template <typename TChar>
JsonObject createNestedObject(TChar* key) {
return operator[](key).template to<JsonObject>();
}
// Creates an object and adds it to the root object.
// https://arduinojson.org/v6/api/jsondocument/createnestedobject/
template <typename TString>
JsonObject createNestedObject(const TString& key) {
return operator[](key).template to<JsonObject>();
}
// Returns true if the root object contains the specified key. // Returns true if the root object contains the specified key.
// https://arduinojson.org/v6/api/jsondocument/containskey/ // https://arduinojson.org/v7/api/jsondocument/containskey/
template <typename TChar> template <typename TChar>
bool containsKey(TChar* key) const { bool containsKey(TChar* key) const {
return data_.getMember(detail::adaptString(key)) != 0; return data_.getMember(detail::adaptString(key), &resources_) != 0;
} }
// Returns true if the root object contains the specified key. // Returns true if the root object contains the specified key.
// https://arduinojson.org/v6/api/jsondocument/containskey/ // https://arduinojson.org/v7/api/jsondocument/containskey/
template <typename TString> template <typename TString>
bool containsKey(const TString& key) const { bool containsKey(const TString& key) const {
return data_.getMember(detail::adaptString(key)) != 0; return data_.getMember(detail::adaptString(key), &resources_) != 0;
} }
// Gets or sets a root object's member. // Gets or sets a root object's member.
// https://arduinojson.org/v6/api/jsondocument/subscript/ // https://arduinojson.org/v7/api/jsondocument/subscript/
template <typename TString> template <typename TString>
FORCE_INLINE typename detail::enable_if< FORCE_INLINE typename detail::enable_if<
detail::IsString<TString>::value, detail::IsString<TString>::value,
@@ -182,7 +177,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
} }
// Gets or sets a root object's member. // Gets or sets a root object's member.
// https://arduinojson.org/v6/api/jsondocument/subscript/ // https://arduinojson.org/v7/api/jsondocument/subscript/
template <typename TChar> template <typename TChar>
FORCE_INLINE typename detail::enable_if< FORCE_INLINE typename detail::enable_if<
detail::IsString<TChar*>::value, detail::IsString<TChar*>::value,
@@ -192,80 +187,92 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
} }
// Gets a root object's member. // Gets a root object's member.
// https://arduinojson.org/v6/api/jsondocument/subscript/ // https://arduinojson.org/v7/api/jsondocument/subscript/
template <typename TString> template <typename TString>
FORCE_INLINE typename detail::enable_if<detail::IsString<TString>::value, FORCE_INLINE typename detail::enable_if<detail::IsString<TString>::value,
JsonVariantConst>::type JsonVariantConst>::type
operator[](const TString& key) const { operator[](const TString& key) const {
return JsonVariantConst(data_.getMember(detail::adaptString(key))); return JsonVariantConst(
data_.getMember(detail::adaptString(key), &resources_), &resources_);
} }
// Gets a root object's member. // Gets a root object's member.
// https://arduinojson.org/v6/api/jsondocument/subscript/ // https://arduinojson.org/v7/api/jsondocument/subscript/
template <typename TChar> template <typename TChar>
FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value, FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value,
JsonVariantConst>::type JsonVariantConst>::type
operator[](TChar* key) const { operator[](TChar* key) const {
return JsonVariantConst(data_.getMember(detail::adaptString(key))); return JsonVariantConst(
data_.getMember(detail::adaptString(key), &resources_), &resources_);
} }
// Gets or sets a root array's element. // Gets or sets a root array's element.
// https://arduinojson.org/v6/api/jsondocument/subscript/ // https://arduinojson.org/v7/api/jsondocument/subscript/
FORCE_INLINE detail::ElementProxy<JsonDocument&> operator[](size_t index) { FORCE_INLINE detail::ElementProxy<JsonDocument&> operator[](size_t index) {
return {*this, index}; return {*this, index};
} }
// Gets a root array's member. // Gets a root array's member.
// https://arduinojson.org/v6/api/jsondocument/subscript/ // https://arduinojson.org/v7/api/jsondocument/subscript/
FORCE_INLINE JsonVariantConst operator[](size_t index) const { FORCE_INLINE JsonVariantConst operator[](size_t index) const {
return JsonVariantConst(data_.getElement(index)); return JsonVariantConst(data_.getElement(index, &resources_), &resources_);
}
// Appends a new (empty) element to the root array.
// Returns a reference to the new element.
// https://arduinojson.org/v7/api/jsondocument/add/
template <typename T>
typename detail::enable_if<!detail::is_same<T, JsonVariant>::value, T>::type
add() {
return add<JsonVariant>().to<T>();
} }
// Appends a new (null) element to the root array. // Appends a new (null) element to the root array.
// Returns a reference to the new element. // Returns a reference to the new element.
// https://arduinojson.org/v6/api/jsondocument/add/ // https://arduinojson.org/v7/api/jsondocument/add/
FORCE_INLINE JsonVariant add() { template <typename T>
return JsonVariant(&pool_, data_.addElement(&pool_)); typename detail::enable_if<detail::is_same<T, JsonVariant>::value, T>::type
add() {
return JsonVariant(data_.addElement(&resources_), &resources_);
} }
// Appends a value to the root array. // Appends a value to the root array.
// https://arduinojson.org/v6/api/jsondocument/add/ // https://arduinojson.org/v7/api/jsondocument/add/
template <typename TValue> template <typename TValue>
FORCE_INLINE bool add(const TValue& value) { FORCE_INLINE bool add(const TValue& value) {
return add().set(value); return add<JsonVariant>().set(value);
} }
// Appends a value to the root array. // Appends a value to the root array.
// https://arduinojson.org/v6/api/jsondocument/add/ // https://arduinojson.org/v7/api/jsondocument/add/
template <typename TChar> template <typename TChar>
FORCE_INLINE bool add(TChar* value) { FORCE_INLINE bool add(TChar* value) {
return add().set(value); return add<JsonVariant>().set(value);
} }
// Removes an element of the root array. // Removes an element of the root array.
// ⚠️ Doesn't release the memory associated with the removed element. // https://arduinojson.org/v7/api/jsondocument/remove/
// https://arduinojson.org/v6/api/jsondocument/remove/
FORCE_INLINE void remove(size_t index) { FORCE_INLINE void remove(size_t index) {
data_.remove(index); detail::VariantData::removeElement(getData(), index, getResourceManager());
} }
// Removes a member of the root object. // Removes a member of the root object.
// ⚠️ Doesn't release the memory associated with the removed element. // https://arduinojson.org/v7/api/jsondocument/remove/
// https://arduinojson.org/v6/api/jsondocument/remove/
template <typename TChar> template <typename TChar>
FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value>::type FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value>::type
remove(TChar* key) { remove(TChar* key) {
data_.remove(detail::adaptString(key)); detail::VariantData::removeMember(getData(), detail::adaptString(key),
getResourceManager());
} }
// Removes a member of the root object. // Removes a member of the root object.
// ⚠️ Doesn't release the memory associated with the removed element. // https://arduinojson.org/v7/api/jsondocument/remove/
// https://arduinojson.org/v6/api/jsondocument/remove/
template <typename TString> template <typename TString>
FORCE_INLINE FORCE_INLINE
typename detail::enable_if<detail::IsString<TString>::value>::type typename detail::enable_if<detail::IsString<TString>::value>::type
remove(const TString& key) { remove(const TString& key) {
data_.remove(detail::adaptString(key)); detail::VariantData::removeMember(getData(), detail::adaptString(key),
getResourceManager());
} }
FORCE_INLINE operator JsonVariant() { FORCE_INLINE operator JsonVariant() {
@@ -276,33 +283,74 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
return getVariant(); return getVariant();
} }
protected: friend void swap(JsonDocument& a, JsonDocument& b) {
JsonDocument() : pool_(0, 0) {} swap(a.resources_, b.resources_);
swap_(a.data_, b.data_);
JsonDocument(detail::MemoryPool pool) : pool_(pool) {}
JsonDocument(char* buf, size_t capa) : pool_(buf, capa) {}
~JsonDocument() {}
void replacePool(detail::MemoryPool pool) {
pool_ = pool;
} }
// DEPRECATED: use add<JsonVariant>() instead
ARDUINOJSON_DEPRECATED("use add<JsonVariant>() instead")
JsonVariant add() {
return add<JsonVariant>();
}
// DEPRECATED: use add<JsonArray>() instead
ARDUINOJSON_DEPRECATED("use add<JsonArray>() instead")
JsonArray createNestedArray() {
return add<JsonArray>();
}
// DEPRECATED: use doc[key].to<JsonArray>() instead
template <typename TChar>
ARDUINOJSON_DEPRECATED("use doc[key].to<JsonArray>() instead")
JsonArray createNestedArray(TChar* key) {
return operator[](key).template to<JsonArray>();
}
// DEPRECATED: use doc[key].to<JsonArray>() instead
template <typename TString>
ARDUINOJSON_DEPRECATED("use doc[key].to<JsonArray>() instead")
JsonArray createNestedArray(const TString& key) {
return operator[](key).template to<JsonArray>();
}
// DEPRECATED: use add<JsonObject>() instead
ARDUINOJSON_DEPRECATED("use add<JsonObject>() instead")
JsonObject createNestedObject() {
return add<JsonObject>();
}
// DEPRECATED: use doc[key].to<JsonObject>() instead
template <typename TChar>
ARDUINOJSON_DEPRECATED("use doc[key].to<JsonObject>() instead")
JsonObject createNestedObject(TChar* key) {
return operator[](key).template to<JsonObject>();
}
// DEPRECATED: use doc[key].to<JsonObject>() instead
template <typename TString>
ARDUINOJSON_DEPRECATED("use doc[key].to<JsonObject>() instead")
JsonObject createNestedObject(const TString& key) {
return operator[](key).template to<JsonObject>();
}
// DEPRECATED: always returns zero
ARDUINOJSON_DEPRECATED("always returns zero")
size_t memoryUsage() const {
return 0;
}
private:
JsonVariant getVariant() { JsonVariant getVariant() {
return JsonVariant(&pool_, &data_); return JsonVariant(&data_, &resources_);
} }
JsonVariantConst getVariant() const { JsonVariantConst getVariant() const {
return JsonVariantConst(&data_); return JsonVariantConst(&data_, &resources_);
} }
detail::MemoryPool pool_; detail::ResourceManager* getResourceManager() {
detail::VariantData data_; return &resources_;
protected:
detail::MemoryPool* getPool() {
return &pool_;
} }
detail::VariantData* getData() { detail::VariantData* getData() {
@@ -316,6 +364,9 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
detail::VariantData* getOrCreateData() { detail::VariantData* getOrCreateData() {
return &data_; return &data_;
} }
detail::ResourceManager resources_;
detail::VariantData data_;
}; };
inline void convertToJson(const JsonDocument& src, JsonVariant dst) { inline void convertToJson(const JsonDocument& src, JsonVariant dst) {

View File

@@ -1,61 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Document/JsonDocument.hpp>
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
// A JsonDocument with a memory pool on the stack.
template <size_t desiredCapacity>
class StaticJsonDocument : public JsonDocument {
static const size_t capacity_ =
detail::AddPadding<detail::Max<1, desiredCapacity>::value>::value;
public:
StaticJsonDocument() : JsonDocument(buffer_, capacity_) {}
StaticJsonDocument(const StaticJsonDocument& src)
: JsonDocument(buffer_, capacity_) {
set(src);
}
template <typename T>
StaticJsonDocument(
const T& src,
typename detail::enable_if<
detail::is_convertible<T, JsonVariantConst>::value>::type* = 0)
: JsonDocument(buffer_, capacity_) {
set(src);
}
// disambiguate
StaticJsonDocument(JsonVariant src) : JsonDocument(buffer_, capacity_) {
set(src);
}
StaticJsonDocument& operator=(const StaticJsonDocument& src) {
set(src);
return *this;
}
template <typename T>
StaticJsonDocument& operator=(const T& src) {
set(src);
return *this;
}
// Reclaims the memory leaked when removing and replacing values.
// https://arduinojson.org/v6/api/jsondocument/garbagecollect/
void garbageCollect() {
StaticJsonDocument tmp(*this);
set(tmp);
}
private:
char buffer_[capacity_];
};
ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -9,7 +9,7 @@
#include <ArduinoJson/Json/Latch.hpp> #include <ArduinoJson/Json/Latch.hpp>
#include <ArduinoJson/Json/Utf16.hpp> #include <ArduinoJson/Json/Utf16.hpp>
#include <ArduinoJson/Json/Utf8.hpp> #include <ArduinoJson/Json/Utf8.hpp>
#include <ArduinoJson/Memory/MemoryPool.hpp> #include <ArduinoJson/Memory/ResourceManager.hpp>
#include <ArduinoJson/Numbers/parseNumber.hpp> #include <ArduinoJson/Numbers/parseNumber.hpp>
#include <ArduinoJson/Polyfills/assert.hpp> #include <ArduinoJson/Polyfills/assert.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp> #include <ArduinoJson/Polyfills/type_traits.hpp>
@@ -18,15 +18,14 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TReader, typename TStringStorage> template <typename TReader>
class JsonDeserializer { class JsonDeserializer {
public: public:
JsonDeserializer(MemoryPool* pool, TReader reader, JsonDeserializer(ResourceManager* resources, TReader reader)
TStringStorage stringStorage) : stringBuilder_(resources),
: stringStorage_(stringStorage),
foundSomething_(false), foundSomething_(false),
latch_(reader), latch_(reader),
pool_(pool) {} resources_(resources) {}
template <typename TFilter> template <typename TFilter>
DeserializationError parse(VariantData& variant, TFilter filter, DeserializationError parse(VariantData& variant, TFilter filter,
@@ -35,7 +34,7 @@ class JsonDeserializer {
err = parseVariant(variant, filter, nestingLimit); err = parseVariant(variant, filter, nestingLimit);
if (!err && latch_.last() != 0 && !variant.isEnclosed()) { if (!err && latch_.last() != 0 && variant.isFloat()) {
// We don't detect trailing characters earlier, so we need to check now // We don't detect trailing characters earlier, so we need to check now
return DeserializationError::InvalidInput; return DeserializationError::InvalidInput;
} }
@@ -147,7 +146,7 @@ class JsonDeserializer {
template <typename TFilter> template <typename TFilter>
DeserializationError::Code parseArray( DeserializationError::Code parseArray(
CollectionData& array, TFilter filter, ArrayData& array, TFilter filter,
DeserializationOption::NestingLimit nestingLimit) { DeserializationOption::NestingLimit nestingLimit) {
DeserializationError::Code err; DeserializationError::Code err;
@@ -167,18 +166,18 @@ class JsonDeserializer {
if (eat(']')) if (eat(']'))
return DeserializationError::Ok; return DeserializationError::Ok;
TFilter memberFilter = filter[0UL]; TFilter elementFilter = filter[0UL];
// Read each value // Read each value
for (;;) { for (;;) {
if (memberFilter.allow()) { if (elementFilter.allow()) {
// Allocate slot in array // Allocate slot in array
VariantData* value = array.addElement(pool_); VariantData* value = array.addElement(resources_);
if (!value) if (!value)
return DeserializationError::NoMemory; return DeserializationError::NoMemory;
// 1 - Parse value // 1 - Parse value
err = parseVariant(*value, memberFilter, nestingLimit.decrement()); err = parseVariant(*value, elementFilter, nestingLimit.decrement());
if (err) if (err)
return err; return err;
} else { } else {
@@ -233,7 +232,7 @@ class JsonDeserializer {
template <typename TFilter> template <typename TFilter>
DeserializationError::Code parseObject( DeserializationError::Code parseObject(
CollectionData& object, TFilter filter, ObjectData& object, TFilter filter,
DeserializationOption::NestingLimit nestingLimit) { DeserializationOption::NestingLimit nestingLimit) {
DeserializationError::Code err; DeserializationError::Code err;
@@ -269,29 +268,26 @@ class JsonDeserializer {
if (!eat(':')) if (!eat(':'))
return DeserializationError::InvalidInput; return DeserializationError::InvalidInput;
JsonString key = stringStorage_.str(); JsonString key = stringBuilder_.str();
TFilter memberFilter = filter[key.c_str()]; TFilter memberFilter = filter[key.c_str()];
if (memberFilter.allow()) { if (memberFilter.allow()) {
VariantData* variant = object.getMember(adaptString(key.c_str())); auto member = object.getMember(adaptString(key.c_str()), resources_);
if (!variant) { if (!member) {
// Save key in memory pool. // Save key in memory pool.
// This MUST be done before adding the slot. auto savedKey = stringBuilder_.save();
key = stringStorage_.save();
// Allocate slot in object // Allocate slot in object
VariantSlot* slot = object.addSlot(pool_); member = object.addMember(savedKey, resources_);
if (!slot) if (!member)
return DeserializationError::NoMemory; return DeserializationError::NoMemory;
} else {
slot->setKey(key); member->setNull(resources_);
variant = slot->data();
} }
// Parse value // Parse value
err = parseVariant(*variant, memberFilter, nestingLimit.decrement()); err = parseVariant(*member, memberFilter, nestingLimit.decrement());
if (err) if (err)
return err; return err;
} else { } else {
@@ -377,7 +373,7 @@ class JsonDeserializer {
} }
DeserializationError::Code parseKey() { DeserializationError::Code parseKey() {
stringStorage_.startString(); stringBuilder_.startString();
if (isQuote(current())) { if (isQuote(current())) {
return parseQuotedString(); return parseQuotedString();
} else { } else {
@@ -388,13 +384,13 @@ class JsonDeserializer {
DeserializationError::Code parseStringValue(VariantData& variant) { DeserializationError::Code parseStringValue(VariantData& variant) {
DeserializationError::Code err; DeserializationError::Code err;
stringStorage_.startString(); stringBuilder_.startString();
err = parseQuotedString(); err = parseQuotedString();
if (err) if (err)
return err; return err;
variant.setString(stringStorage_.save()); variant.setOwnedString(stringBuilder_.save());
return DeserializationError::Ok; return DeserializationError::Ok;
} }
@@ -430,9 +426,9 @@ class JsonDeserializer {
if (err) if (err)
return err; return err;
if (codepoint.append(codeunit)) if (codepoint.append(codeunit))
Utf8::encodeCodepoint(codepoint.value(), stringStorage_); Utf8::encodeCodepoint(codepoint.value(), stringBuilder_);
#else #else
stringStorage_.append('\\'); stringBuilder_.append('\\');
#endif #endif
continue; continue;
} }
@@ -444,10 +440,10 @@ class JsonDeserializer {
move(); move();
} }
stringStorage_.append(c); stringBuilder_.append(c);
} }
if (!stringStorage_.isValid()) if (!stringBuilder_.isValid())
return DeserializationError::NoMemory; return DeserializationError::NoMemory;
return DeserializationError::Ok; return DeserializationError::Ok;
@@ -460,14 +456,14 @@ class JsonDeserializer {
if (canBeInNonQuotedString(c)) { // no quotes if (canBeInNonQuotedString(c)) { // no quotes
do { do {
move(); move();
stringStorage_.append(c); stringBuilder_.append(c);
c = current(); c = current();
} while (canBeInNonQuotedString(c)); } while (canBeInNonQuotedString(c));
} else { } else {
return DeserializationError::InvalidInput; return DeserializationError::InvalidInput;
} }
if (!stringStorage_.isValid()) if (!stringBuilder_.isValid())
return DeserializationError::NoMemory; return DeserializationError::NoMemory;
return DeserializationError::Ok; return DeserializationError::Ok;
@@ -659,10 +655,10 @@ class JsonDeserializer {
return DeserializationError::Ok; return DeserializationError::Ok;
} }
TStringStorage stringStorage_; StringBuilder stringBuilder_;
bool foundSomething_; bool foundSomething_;
Latch<TReader> latch_; Latch<TReader> latch_;
MemoryPool* pool_; ResourceManager* resources_;
char buffer_[64]; // using a member instead of a local variable because it char buffer_[64]; // using a member instead of a local variable because it
// ended in the recursive path after compiler inlined the // ended in the recursive path after compiler inlined the
// code // code
@@ -673,21 +669,27 @@ ARDUINOJSON_END_PRIVATE_NAMESPACE
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
// Parses a JSON input, filters, and puts the result in a JsonDocument. // Parses a JSON input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/json/deserializejson/ // https://arduinojson.org/v7/api/json/deserializejson/
template <typename... Args> template <typename TDestination, typename... Args>
DeserializationError deserializeJson(JsonDocument& doc, Args&&... args) { typename detail::enable_if<
detail::is_deserialize_destination<TDestination>::value,
DeserializationError>::type
deserializeJson(TDestination&& dst, Args&&... args) {
using namespace detail; using namespace detail;
return deserialize<JsonDeserializer>(doc, detail::forward<Args>(args)...); return deserialize<JsonDeserializer>(detail::forward<TDestination>(dst),
}
// Parses a JSON input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/json/deserializejson/
template <typename TChar, typename... Args>
DeserializationError deserializeJson(JsonDocument& doc, TChar* input,
Args&&... args) {
using namespace detail;
return deserialize<JsonDeserializer>(doc, input,
detail::forward<Args>(args)...); detail::forward<Args>(args)...);
} }
// Parses a JSON input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v7/api/json/deserializejson/
template <typename TDestination, typename TChar, typename... Args>
typename detail::enable_if<
detail::is_deserialize_destination<TDestination>::value,
DeserializationError>::type
deserializeJson(TDestination&& dst, TChar* input, Args&&... args) {
using namespace detail;
return deserialize<JsonDeserializer>(detail::forward<TDestination>(dst),
input, detail::forward<Args>(args)...);
}
ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -7,27 +7,28 @@
#include <ArduinoJson/Json/TextFormatter.hpp> #include <ArduinoJson/Json/TextFormatter.hpp>
#include <ArduinoJson/Serialization/measure.hpp> #include <ArduinoJson/Serialization/measure.hpp>
#include <ArduinoJson/Serialization/serialize.hpp> #include <ArduinoJson/Serialization/serialize.hpp>
#include <ArduinoJson/Variant/Visitor.hpp> #include <ArduinoJson/Variant/VariantDataVisitor.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TWriter> template <typename TWriter>
class JsonSerializer : public Visitor<size_t> { class JsonSerializer : public VariantDataVisitor<size_t> {
public: public:
static const bool producesText = true; static const bool producesText = true;
JsonSerializer(TWriter writer) : formatter_(writer) {} JsonSerializer(TWriter writer, const ResourceManager* resources)
: formatter_(writer), resources_(resources) {}
FORCE_INLINE size_t visitArray(const CollectionData& array) { FORCE_INLINE size_t visit(const ArrayData& array) {
write('['); write('[');
const VariantSlot* slot = array.head(); auto it = array.createIterator(resources_);
while (slot != 0) { while (!it.done()) {
slot->data()->accept(*this); it->accept(*this);
slot = slot->next(); it.next(resources_);
if (slot == 0) if (it.done())
break; break;
write(','); write(',');
@@ -37,18 +38,18 @@ class JsonSerializer : public Visitor<size_t> {
return bytesWritten(); return bytesWritten();
} }
size_t visitObject(const CollectionData& object) { size_t visit(const ObjectData& object) {
write('{'); write('{');
const VariantSlot* slot = object.head(); auto it = object.createIterator(resources_);
while (slot != 0) { while (!it.done()) {
formatter_.writeString(slot->key()); formatter_.writeString(it.key());
write(':'); write(':');
slot->data()->accept(*this); it->accept(*this);
slot = slot->next(); it.next(resources_);
if (slot == 0) if (it.done())
break; break;
write(','); write(',');
@@ -58,42 +59,42 @@ class JsonSerializer : public Visitor<size_t> {
return bytesWritten(); return bytesWritten();
} }
size_t visitFloat(JsonFloat value) { size_t visit(JsonFloat value) {
formatter_.writeFloat(value); formatter_.writeFloat(value);
return bytesWritten(); return bytesWritten();
} }
size_t visitString(const char* value) { size_t visit(const char* value) {
formatter_.writeString(value); formatter_.writeString(value);
return bytesWritten(); return bytesWritten();
} }
size_t visitString(const char* value, size_t n) { size_t visit(JsonString value) {
formatter_.writeString(value, n); formatter_.writeString(value.c_str(), value.size());
return bytesWritten(); return bytesWritten();
} }
size_t visitRawJson(const char* data, size_t n) { size_t visit(RawString value) {
formatter_.writeRaw(data, n); formatter_.writeRaw(value.data(), value.size());
return bytesWritten(); return bytesWritten();
} }
size_t visitSignedInteger(JsonInteger value) { size_t visit(JsonInteger value) {
formatter_.writeInteger(value); formatter_.writeInteger(value);
return bytesWritten(); return bytesWritten();
} }
size_t visitUnsignedInteger(JsonUInt value) { size_t visit(JsonUInt value) {
formatter_.writeInteger(value); formatter_.writeInteger(value);
return bytesWritten(); return bytesWritten();
} }
size_t visitBoolean(bool value) { size_t visit(bool value) {
formatter_.writeBoolean(value); formatter_.writeBoolean(value);
return bytesWritten(); return bytesWritten();
} }
size_t visitNull() { size_t visit(nullptr_t) {
formatter_.writeRaw("null"); formatter_.writeRaw("null");
return bytesWritten(); return bytesWritten();
} }
@@ -113,6 +114,9 @@ class JsonSerializer : public Visitor<size_t> {
private: private:
TextFormatter<TWriter> formatter_; TextFormatter<TWriter> formatter_;
protected:
const ResourceManager* resources_;
}; };
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE
@@ -120,7 +124,7 @@ ARDUINOJSON_END_PRIVATE_NAMESPACE
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
// Produces a minified JSON document. // Produces a minified JSON document.
// https://arduinojson.org/v6/api/json/serializejson/ // https://arduinojson.org/v7/api/json/serializejson/
template <typename TDestination> template <typename TDestination>
size_t serializeJson(JsonVariantConst source, TDestination& destination) { size_t serializeJson(JsonVariantConst source, TDestination& destination) {
using namespace detail; using namespace detail;
@@ -128,7 +132,7 @@ size_t serializeJson(JsonVariantConst source, TDestination& destination) {
} }
// Produces a minified JSON document. // Produces a minified JSON document.
// https://arduinojson.org/v6/api/json/serializejson/ // https://arduinojson.org/v7/api/json/serializejson/
inline size_t serializeJson(JsonVariantConst source, void* buffer, inline size_t serializeJson(JsonVariantConst source, void* buffer,
size_t bufferSize) { size_t bufferSize) {
using namespace detail; using namespace detail;
@@ -136,7 +140,7 @@ inline size_t serializeJson(JsonVariantConst source, void* buffer,
} }
// Computes the length of the document that serializeJson() produces. // Computes the length of the document that serializeJson() produces.
// https://arduinojson.org/v6/api/json/measurejson/ // https://arduinojson.org/v7/api/json/measurejson/
inline size_t measureJson(JsonVariantConst source) { inline size_t measureJson(JsonVariantConst source) {
using namespace detail; using namespace detail;
return measure<JsonSerializer>(source); return measure<JsonSerializer>(source);

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -16,19 +16,20 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
typedef JsonSerializer<TWriter> base; typedef JsonSerializer<TWriter> base;
public: public:
PrettyJsonSerializer(TWriter writer) : base(writer), nesting_(0) {} PrettyJsonSerializer(TWriter writer, const ResourceManager* resources)
: base(writer, resources), nesting_(0) {}
size_t visitArray(const CollectionData& array) { size_t visit(const ArrayData& array) {
const VariantSlot* slot = array.head(); auto it = array.createIterator(base::resources_);
if (slot) { if (!it.done()) {
base::write("[\r\n"); base::write("[\r\n");
nesting_++; nesting_++;
while (slot != 0) { while (!it.done()) {
indent(); indent();
slot->data()->accept(*this); it->accept(*this);
slot = slot->next(); it.next(base::resources_);
base::write(slot ? ",\r\n" : "\r\n"); base::write(it.done() ? "\r\n" : ",\r\n");
} }
nesting_--; nesting_--;
indent(); indent();
@@ -39,19 +40,19 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
return this->bytesWritten(); return this->bytesWritten();
} }
size_t visitObject(const CollectionData& object) { size_t visit(const ObjectData& object) {
const VariantSlot* slot = object.head(); auto it = object.createIterator(base::resources_);
if (slot) { if (!it.done()) {
base::write("{\r\n"); base::write("{\r\n");
nesting_++; nesting_++;
while (slot != 0) { while (!it.done()) {
indent(); indent();
base::visitString(slot->key()); base::visit(it.key());
base::write(": "); base::write(": ");
slot->data()->accept(*this); it->accept(*this);
slot = slot->next(); it.next(base::resources_);
base::write(slot ? ",\r\n" : "\r\n"); base::write(it.done() ? "\r\n" : ",\r\n");
} }
nesting_--; nesting_--;
indent(); indent();
@@ -62,6 +63,8 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
return this->bytesWritten(); return this->bytesWritten();
} }
using base::visit;
private: private:
void indent() { void indent() {
for (uint8_t i = 0; i < nesting_; i++) for (uint8_t i = 0; i < nesting_; i++)
@@ -76,7 +79,7 @@ ARDUINOJSON_END_PRIVATE_NAMESPACE
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
// Produces JsonDocument to create a prettified JSON document. // Produces JsonDocument to create a prettified JSON document.
// https://arduinojson.org/v6/api/json/serializejsonpretty/ // https://arduinojson.org/v7/api/json/serializejsonpretty/
template <typename TDestination> template <typename TDestination>
size_t serializeJsonPretty(JsonVariantConst source, TDestination& destination) { size_t serializeJsonPretty(JsonVariantConst source, TDestination& destination) {
using namespace ArduinoJson::detail; using namespace ArduinoJson::detail;
@@ -84,7 +87,7 @@ size_t serializeJsonPretty(JsonVariantConst source, TDestination& destination) {
} }
// Produces JsonDocument to create a prettified JSON document. // Produces JsonDocument to create a prettified JSON document.
// https://arduinojson.org/v6/api/json/serializejsonpretty/ // https://arduinojson.org/v7/api/json/serializejsonpretty/
inline size_t serializeJsonPretty(JsonVariantConst source, void* buffer, inline size_t serializeJsonPretty(JsonVariantConst source, void* buffer,
size_t bufferSize) { size_t bufferSize) {
using namespace ArduinoJson::detail; using namespace ArduinoJson::detail;
@@ -92,7 +95,7 @@ inline size_t serializeJsonPretty(JsonVariantConst source, void* buffer,
} }
// Computes the length of the document that serializeJsonPretty() produces. // Computes the length of the document that serializeJsonPretty() produces.
// https://arduinojson.org/v6/api/json/measurejsonpretty/ // https://arduinojson.org/v7/api/json/measurejsonpretty/
inline size_t measureJsonPretty(JsonVariantConst source) { inline size_t measureJsonPretty(JsonVariantConst source) {
using namespace ArduinoJson::detail; using namespace ArduinoJson::detail;
return measure<PrettyJsonSerializer>(source); return measure<PrettyJsonSerializer>(source);

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

View File

@@ -0,0 +1,49 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Namespace.hpp>
#include <stdlib.h> // malloc, free
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
class Allocator {
public:
virtual void* allocate(size_t size) = 0;
virtual void deallocate(void* ptr) = 0;
virtual void* reallocate(void* ptr, size_t new_size) = 0;
protected:
~Allocator() = default;
};
namespace detail {
class DefaultAllocator : public Allocator {
public:
void* allocate(size_t size) override {
return malloc(size);
}
void deallocate(void* ptr) override {
free(ptr);
}
void* reallocate(void* ptr, size_t new_size) override {
return realloc(ptr, new_size);
}
static Allocator* instance() {
static DefaultAllocator allocator;
return &allocator;
}
private:
DefaultAllocator() = default;
~DefaultAllocator() = default;
};
} // namespace detail
ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@@ -1,253 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Memory/Alignment.hpp>
#include <ArduinoJson/Polyfills/assert.hpp>
#include <ArduinoJson/Polyfills/mpl/max.hpp>
#include <ArduinoJson/Strings/StringAdapters.hpp>
#include <ArduinoJson/Variant/VariantSlot.hpp>
#include <string.h> // memmove
#define JSON_STRING_SIZE(SIZE) (SIZE + 1)
// Computes the size required to store an array in a JsonDocument.
// https://arduinojson.org/v6/how-to/determine-the-capacity-of-the-jsondocument/
#define JSON_ARRAY_SIZE(NUMBER_OF_ELEMENTS) \
((NUMBER_OF_ELEMENTS) * sizeof(ArduinoJson::detail::VariantSlot))
// Returns the size (in bytes) of an object with n elements.
// Can be very handy to determine the size of a StaticMemoryPool.
#define JSON_OBJECT_SIZE(NUMBER_OF_ELEMENTS) \
((NUMBER_OF_ELEMENTS) * sizeof(ArduinoJson::detail::VariantSlot))
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
// begin_ end_
// v v
// +-------------+--------------+--------------+
// | strings... | (free) | ...variants |
// +-------------+--------------+--------------+
// ^ ^
// left_ right_
class MemoryPool {
public:
MemoryPool(char* buf, size_t capa)
: begin_(buf),
left_(buf),
right_(buf ? buf + capa : 0),
end_(buf ? buf + capa : 0),
overflowed_(false) {
ARDUINOJSON_ASSERT(isAligned(begin_));
ARDUINOJSON_ASSERT(isAligned(right_));
ARDUINOJSON_ASSERT(isAligned(end_));
}
void* buffer() {
return begin_; // NOLINT(clang-analyzer-unix.Malloc)
// movePointers() alters this pointer
}
// Gets the capacity of the memoryPool in bytes
size_t capacity() const {
return size_t(end_ - begin_);
}
size_t size() const {
return size_t(left_ - begin_ + end_ - right_);
}
bool overflowed() const {
return overflowed_;
}
VariantSlot* allocVariant() {
return allocRight<VariantSlot>();
}
template <typename TAdaptedString>
const char* saveString(TAdaptedString str) {
if (str.isNull())
return 0;
#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
const char* existingCopy = findString(str);
if (existingCopy)
return existingCopy;
#endif
size_t n = str.size();
char* newCopy = allocString(n + 1);
if (newCopy) {
stringGetChars(str, newCopy, n);
newCopy[n] = 0; // force null-terminator
}
return newCopy;
}
void getFreeZone(char** zoneStart, size_t* zoneSize) const {
*zoneStart = left_;
*zoneSize = size_t(right_ - left_);
}
const char* saveStringFromFreeZone(size_t len) {
#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
const char* dup = findString(adaptString(left_, len));
if (dup)
return dup;
#endif
const char* str = left_;
left_ += len;
*left_++ = 0;
checkInvariants();
return str;
}
void markAsOverflowed() {
overflowed_ = true;
}
void clear() {
left_ = begin_;
right_ = end_;
overflowed_ = false;
}
bool canAlloc(size_t bytes) const {
return left_ + bytes <= right_;
}
bool owns(void* p) const {
return begin_ <= p && p < end_;
}
// Workaround for missing placement new
void* operator new(size_t, void* p) {
return p;
}
// Squash the free space between strings and variants
//
// begin_ end_
// v v
// +-------------+--------------+
// | strings... | ...variants |
// +-------------+--------------+
// ^
// left_ right_
//
// This funcion is called before a realloc.
ptrdiff_t squash() {
char* new_right = addPadding(left_);
if (new_right >= right_)
return 0;
size_t right_size = static_cast<size_t>(end_ - right_);
memmove(new_right, right_, right_size);
ptrdiff_t bytes_reclaimed = right_ - new_right;
right_ = new_right;
end_ = new_right + right_size;
return bytes_reclaimed;
}
// Move all pointers together
// This funcion is called after a realloc.
void movePointers(ptrdiff_t offset) {
begin_ += offset;
left_ += offset;
right_ += offset;
end_ += offset;
}
private:
void checkInvariants() {
ARDUINOJSON_ASSERT(begin_ <= left_);
ARDUINOJSON_ASSERT(left_ <= right_);
ARDUINOJSON_ASSERT(right_ <= end_);
ARDUINOJSON_ASSERT(isAligned(right_));
}
#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
template <typename TAdaptedString>
const char* findString(const TAdaptedString& str) const {
size_t n = str.size();
for (char* next = begin_; next + n < left_; ++next) {
if (next[n] == '\0' && stringEquals(str, adaptString(next, n)))
return next;
// jump to next terminator
while (*next)
++next;
}
return 0;
}
#endif
char* allocString(size_t n) {
if (!canAlloc(n)) {
overflowed_ = true;
return 0;
}
char* s = left_;
left_ += n;
checkInvariants();
return s;
}
template <typename T>
T* allocRight() {
return reinterpret_cast<T*>(allocRight(sizeof(T)));
}
void* allocRight(size_t bytes) {
if (!canAlloc(bytes)) {
overflowed_ = true;
return 0;
}
right_ -= bytes;
return right_;
}
char *begin_, *left_, *right_, *end_;
bool overflowed_;
};
template <typename TAdaptedString, typename TCallback>
bool storeString(MemoryPool* pool, TAdaptedString str,
StringStoragePolicy::Copy, TCallback callback) {
const char* copy = pool->saveString(str);
JsonString storedString(copy, str.size(), JsonString::Copied);
callback(storedString);
return copy != 0;
}
template <typename TAdaptedString, typename TCallback>
bool storeString(MemoryPool*, TAdaptedString str, StringStoragePolicy::Link,
TCallback callback) {
JsonString storedString(str.data(), str.size(), JsonString::Linked);
callback(storedString);
return !str.isNull();
}
template <typename TAdaptedString, typename TCallback>
bool storeString(MemoryPool* pool, TAdaptedString str,
StringStoragePolicy::LinkOrCopy policy, TCallback callback) {
if (policy.link)
return storeString(pool, str, StringStoragePolicy::Link(), callback);
else
return storeString(pool, str, StringStoragePolicy::Copy(), callback);
}
template <typename TAdaptedString, typename TCallback>
bool storeString(MemoryPool* pool, TAdaptedString str, TCallback callback) {
return storeString(pool, str, str.storagePolicy(), callback);
}
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -0,0 +1,127 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Memory/Allocator.hpp>
#include <ArduinoJson/Memory/StringPool.hpp>
#include <ArduinoJson/Memory/VariantPoolList.hpp>
#include <ArduinoJson/Polyfills/assert.hpp>
#include <ArduinoJson/Polyfills/utility.hpp>
#include <ArduinoJson/Strings/StringAdapters.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
class VariantSlot;
class VariantPool;
class ResourceManager {
public:
ResourceManager(Allocator* allocator = DefaultAllocator::instance())
: allocator_(allocator), overflowed_(false) {}
~ResourceManager() {
stringPool_.clear(allocator_);
variantPools_.clear(allocator_);
}
ResourceManager(const ResourceManager&) = delete;
ResourceManager& operator=(const ResourceManager& src) = delete;
friend void swap(ResourceManager& a, ResourceManager& b) {
swap(a.stringPool_, b.stringPool_);
swap(a.variantPools_, b.variantPools_);
swap_(a.allocator_, b.allocator_);
swap_(a.overflowed_, b.overflowed_);
}
Allocator* allocator() const {
return allocator_;
}
size_t size() const {
return VariantPool::slotsToBytes(variantPools_.usage()) +
stringPool_.size();
}
bool overflowed() const {
return overflowed_;
}
SlotWithId allocSlot() {
auto p = variantPools_.allocSlot(allocator_);
if (!p)
overflowed_ = true;
return p;
}
void freeSlot(SlotWithId id) {
variantPools_.freeSlot(id);
}
VariantSlot* getSlot(SlotId id) const {
return variantPools_.getSlot(id);
}
template <typename TAdaptedString>
StringNode* saveString(TAdaptedString str) {
if (str.isNull())
return 0;
auto node = stringPool_.add(str, allocator_);
if (!node)
overflowed_ = true;
return node;
}
void saveString(StringNode* node) {
stringPool_.add(node);
}
template <typename TAdaptedString>
StringNode* getString(const TAdaptedString& str) const {
return stringPool_.get(str);
}
StringNode* createString(size_t length) {
auto node = StringNode::create(length, allocator_);
if (!node)
overflowed_ = true;
return node;
}
StringNode* resizeString(StringNode* node, size_t length) {
node = StringNode::resize(node, length, allocator_);
if (!node)
overflowed_ = true;
return node;
}
void destroyString(StringNode* node) {
StringNode::destroy(node, allocator_);
}
void dereferenceString(const char* s) {
stringPool_.dereference(s, allocator_);
}
void clear() {
variantPools_.clear(allocator_);
overflowed_ = false;
stringPool_.clear(allocator_);
}
void shrinkToFit() {
variantPools_.shrinkToFit(allocator_);
}
private:
Allocator* allocator_;
bool overflowed_;
StringPool stringPool_;
VariantPoolList variantPools_;
};
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -0,0 +1,80 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Memory/ResourceManager.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
class StringBuilder {
public:
static const size_t initialCapacity = 31;
StringBuilder(ResourceManager* resources) : resources_(resources) {}
~StringBuilder() {
if (node_)
resources_->destroyString(node_);
}
void startString() {
size_ = 0;
if (!node_)
node_ = resources_->createString(initialCapacity);
}
StringNode* save() {
ARDUINOJSON_ASSERT(node_ != nullptr);
node_->data[size_] = 0;
StringNode* node = resources_->getString(adaptString(node_->data, size_));
if (!node) {
node = resources_->resizeString(node_, size_);
ARDUINOJSON_ASSERT(node != nullptr); // realloc to smaller can't fail
resources_->saveString(node);
node_ = nullptr; // next time we need a new string
} else {
node->references++;
}
return node;
}
void append(const char* s) {
while (*s)
append(*s++);
}
void append(const char* s, size_t n) {
while (n-- > 0) // TODO: memcpy
append(*s++);
}
void append(char c) {
if (node_ && size_ == node_->length)
node_ = resources_->resizeString(node_, size_ * 2U + 1);
if (node_)
node_->data[size_++] = c;
}
bool isValid() const {
return node_ != nullptr;
}
size_t size() const {
return size_;
}
JsonString str() const {
ARDUINOJSON_ASSERT(node_ != nullptr);
node_->data[size_] = 0;
return JsonString(node_->data, size_, JsonString::Copied);
}
private:
ResourceManager* resources_;
StringNode* node_ = nullptr;
size_t size_ = 0;
};
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -0,0 +1,73 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Memory/Allocator.hpp>
#include <ArduinoJson/Namespace.hpp>
#include <ArduinoJson/Polyfills/assert.hpp>
#include <ArduinoJson/Polyfills/integer.hpp>
#include <ArduinoJson/Polyfills/limits.hpp>
#include <stddef.h> // offsetof
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
struct StringNode {
// Use the same type as SlotId to store the reference count
// (there can never be more references than slots)
using references_type = uint_t<ARDUINOJSON_SLOT_ID_SIZE * 8>::type;
using length_type = uint_t<ARDUINOJSON_STRING_LENGTH_SIZE * 8>::type;
struct StringNode* next;
references_type references;
length_type length;
char data[1];
static constexpr size_t maxLength = numeric_limits<length_type>::highest();
static constexpr size_t sizeForLength(size_t n) {
return n + 1 + offsetof(StringNode, data);
}
static StringNode* create(size_t length, Allocator* allocator) {
if (length > maxLength)
return nullptr;
auto node = reinterpret_cast<StringNode*>(
allocator->allocate(sizeForLength(length)));
if (node) {
node->length = length_type(length);
node->references = 1;
}
return node;
}
static StringNode* resize(StringNode* node, size_t length,
Allocator* allocator) {
ARDUINOJSON_ASSERT(node != nullptr);
StringNode* newNode;
if (length <= maxLength)
newNode = reinterpret_cast<StringNode*>(
allocator->reallocate(node, sizeForLength(length)));
else
newNode = nullptr;
if (newNode)
newNode->length = length_type(length);
else
allocator->deallocate(node);
return newNode;
}
static void destroy(StringNode* node, Allocator* allocator) {
allocator->deallocate(node);
}
};
// Returns the size (in bytes) of an string with n characters.
constexpr size_t sizeofString(size_t n) {
return StringNode::sizeForLength(n);
}
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -0,0 +1,105 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Memory/Allocator.hpp>
#include <ArduinoJson/Memory/StringNode.hpp>
#include <ArduinoJson/Polyfills/assert.hpp>
#include <ArduinoJson/Polyfills/utility.hpp>
#include <ArduinoJson/Strings/StringAdapters.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
class VariantSlot;
class VariantPool;
class StringPool {
public:
StringPool() = default;
StringPool(const StringPool&) = delete;
void operator=(StringPool&& src) = delete;
~StringPool() {
ARDUINOJSON_ASSERT(strings_ == nullptr);
}
friend void swap(StringPool& a, StringPool& b) {
swap_(a.strings_, b.strings_);
}
void clear(Allocator* allocator) {
while (strings_) {
auto node = strings_;
strings_ = node->next;
StringNode::destroy(node, allocator);
}
}
size_t size() const {
size_t total = 0;
for (auto node = strings_; node; node = node->next)
total += sizeofString(node->length);
return total;
}
template <typename TAdaptedString>
StringNode* add(TAdaptedString str, Allocator* allocator) {
ARDUINOJSON_ASSERT(str.isNull() == false);
auto node = get(str);
if (node) {
node->references++;
return node;
}
size_t n = str.size();
node = StringNode::create(n, allocator);
if (!node)
return nullptr;
stringGetChars(str, node->data, n);
node->data[n] = 0; // force NUL terminator
add(node);
return node;
}
void add(StringNode* node) {
ARDUINOJSON_ASSERT(node != nullptr);
node->next = strings_;
strings_ = node;
}
template <typename TAdaptedString>
StringNode* get(const TAdaptedString& str) const {
for (auto node = strings_; node; node = node->next) {
if (stringEquals(str, adaptString(node->data, node->length)))
return node;
}
return nullptr;
}
void dereference(const char* s, Allocator* allocator) {
StringNode* prev = nullptr;
for (auto node = strings_; node; node = node->next) {
if (node->data == s) {
if (--node->references == 0) {
if (prev)
prev->next = node->next;
else
strings_ = node->next;
StringNode::destroy(node, allocator);
}
return;
}
prev = node;
}
}
private:
StringNode* strings_ = nullptr;
};
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -0,0 +1,63 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Memory/ResourceManager.hpp>
#include <ArduinoJson/Polyfills/assert.hpp>
#include <ArduinoJson/Polyfills/integer.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
class VariantSlot;
using SlotId = uint_t<ARDUINOJSON_SLOT_ID_SIZE * 8>::type;
using SlotCount = SlotId;
const SlotId NULL_SLOT = SlotId(-1);
class SlotWithId {
public:
SlotWithId() : slot_(nullptr), id_(NULL_SLOT) {}
SlotWithId(VariantSlot* slot, SlotId id) : slot_(slot), id_(id) {
ARDUINOJSON_ASSERT((slot == nullptr) == (id == NULL_SLOT));
}
SlotId id() const {
return id_;
}
operator VariantSlot*() {
return slot_;
}
VariantSlot* operator->() {
ARDUINOJSON_ASSERT(slot_ != nullptr);
return slot_;
}
private:
VariantSlot* slot_;
SlotId id_;
};
class VariantPool {
public:
void create(SlotCount cap, Allocator* allocator);
void destroy(Allocator* allocator);
SlotWithId allocSlot();
VariantSlot* getSlot(SlotId id) const;
void clear();
void shrinkToFit(Allocator*);
SlotCount usage() const;
static SlotCount bytesToSlots(size_t);
static size_t slotsToBytes(SlotCount);
private:
SlotCount capacity_;
SlotCount usage_;
VariantSlot* slots_;
};
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -0,0 +1,81 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Memory/VariantPool.hpp>
#include <ArduinoJson/Variant/VariantSlot.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
inline void VariantPool::create(SlotCount cap, Allocator* allocator) {
ARDUINOJSON_ASSERT(cap > 0);
slots_ =
reinterpret_cast<VariantSlot*>(allocator->allocate(slotsToBytes(cap)));
capacity_ = slots_ ? cap : 0;
usage_ = 0;
}
inline void VariantPool::destroy(Allocator* allocator) {
if (slots_)
allocator->deallocate(slots_);
slots_ = nullptr;
capacity_ = 0;
usage_ = 0;
}
inline void VariantPool::shrinkToFit(Allocator* allocator) {
auto newSlots = reinterpret_cast<VariantSlot*>(
allocator->reallocate(slots_, slotsToBytes(usage_)));
if (newSlots) {
slots_ = newSlots;
capacity_ = usage_;
}
}
inline SlotWithId VariantPool::allocSlot() {
if (!slots_)
return {};
if (usage_ >= capacity_)
return {};
auto index = usage_++;
auto slot = &slots_[index];
return {new (slot) VariantSlot, SlotId(index)};
}
inline VariantSlot* VariantPool::getSlot(SlotId id) const {
ARDUINOJSON_ASSERT(id < usage_);
return &slots_[id];
}
inline SlotCount VariantPool::usage() const {
return usage_;
}
inline void VariantPool::clear() {
usage_ = 0;
}
inline SlotCount VariantPool::bytesToSlots(size_t n) {
return static_cast<SlotCount>(n / sizeof(VariantSlot));
}
inline size_t VariantPool::slotsToBytes(SlotCount n) {
return n * sizeof(VariantSlot);
}
inline SlotWithId VariantPoolList::allocFromFreeList() {
ARDUINOJSON_ASSERT(freeList_ != NULL_SLOT);
auto id = freeList_;
auto slot = getSlot(freeList_);
freeList_ = slot->next();
return {new (slot) VariantSlot, id};
}
inline void VariantPoolList::freeSlot(SlotWithId slot) {
slot->setNext(freeList_);
freeList_ = slot.id();
}
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -0,0 +1,189 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Memory/VariantPool.hpp>
#include <ArduinoJson/Polyfills/assert.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
using PoolCount = SlotId;
class VariantPoolList {
public:
VariantPoolList() = default;
~VariantPoolList() {
ARDUINOJSON_ASSERT(count_ == 0);
}
friend void swap(VariantPoolList& a, VariantPoolList& b) {
bool aUsedPreallocated = a.pools_ == a.preallocatedPools_;
bool bUsedPreallocated = b.pools_ == b.preallocatedPools_;
// Who is using preallocated pools?
if (aUsedPreallocated && bUsedPreallocated) {
// both of us => swap preallocated pools
for (PoolCount i = 0; i < ARDUINOJSON_INITIAL_POOL_COUNT; i++)
swap_(a.preallocatedPools_[i], b.preallocatedPools_[i]);
} else if (bUsedPreallocated) {
// only b => copy b's preallocated pools and give him a's pointer
for (PoolCount i = 0; i < b.count_; i++)
a.preallocatedPools_[i] = b.preallocatedPools_[i];
b.pools_ = a.pools_;
a.pools_ = a.preallocatedPools_;
} else if (aUsedPreallocated) {
// only a => copy a's preallocated pools and give him b's pointer
for (PoolCount i = 0; i < a.count_; i++)
b.preallocatedPools_[i] = a.preallocatedPools_[i];
a.pools_ = b.pools_;
b.pools_ = b.preallocatedPools_;
} else {
// neither => swap pointers
swap_(a.pools_, b.pools_);
}
swap_(a.count_, b.count_);
swap_(a.capacity_, b.capacity_);
swap_(a.freeList_, b.freeList_);
}
VariantPoolList& operator=(VariantPoolList&& src) {
ARDUINOJSON_ASSERT(count_ == 0);
if (src.pools_ == src.preallocatedPools_) {
memcpy(preallocatedPools_, src.preallocatedPools_,
sizeof(preallocatedPools_));
pools_ = preallocatedPools_;
} else {
pools_ = src.pools_;
src.pools_ = nullptr;
}
count_ = src.count_;
capacity_ = src.capacity_;
src.count_ = 0;
src.capacity_ = 0;
return *this;
}
SlotWithId allocSlot(Allocator* allocator) {
// try to allocate from free list
if (freeList_ != NULL_SLOT) {
return allocFromFreeList();
}
// try to allocate from last pool (other pools are full)
if (count_) {
auto slot = allocFromLastPool();
if (slot)
return slot;
}
// create a new pool and try again
auto pool = addPool(allocator);
if (!pool)
return {};
return allocFromLastPool();
}
void freeSlot(SlotWithId slot);
VariantSlot* getSlot(SlotId id) const {
if (id == NULL_SLOT)
return nullptr;
auto poolIndex = SlotId(id / ARDUINOJSON_POOL_CAPACITY);
auto indexInPool = SlotId(id % ARDUINOJSON_POOL_CAPACITY);
ARDUINOJSON_ASSERT(poolIndex < count_);
return pools_[poolIndex].getSlot(indexInPool);
}
void clear(Allocator* allocator) {
for (PoolCount i = 0; i < count_; i++)
pools_[i].destroy(allocator);
count_ = 0;
freeList_ = NULL_SLOT;
if (pools_ != preallocatedPools_) {
allocator->deallocate(pools_);
pools_ = preallocatedPools_;
capacity_ = ARDUINOJSON_INITIAL_POOL_COUNT;
}
}
SlotCount usage() const {
SlotCount total = 0;
for (PoolCount i = 0; i < count_; i++)
total = SlotCount(total + pools_[i].usage());
return total;
}
void shrinkToFit(Allocator* allocator) {
if (count_ > 0)
pools_[count_ - 1].shrinkToFit(allocator);
if (pools_ != preallocatedPools_ && count_ != capacity_) {
pools_ = static_cast<VariantPool*>(
allocator->reallocate(pools_, count_ * sizeof(VariantPool)));
ARDUINOJSON_ASSERT(pools_ != nullptr); // realloc to smaller can't fail
capacity_ = count_;
}
}
private:
SlotWithId allocFromFreeList();
SlotWithId allocFromLastPool() {
ARDUINOJSON_ASSERT(count_ > 0);
auto poolIndex = SlotId(count_ - 1);
auto slot = pools_[poolIndex].allocSlot();
if (!slot)
return {};
return {slot, SlotId(poolIndex * ARDUINOJSON_POOL_CAPACITY + slot.id())};
}
VariantPool* addPool(Allocator* allocator) {
if (count_ == capacity_ && !increaseCapacity(allocator))
return nullptr;
auto pool = &pools_[count_++];
SlotCount poolCapacity = ARDUINOJSON_POOL_CAPACITY;
if (count_ == maxPools) // last pool is smaller because of NULL_SLOT
poolCapacity--;
pool->create(poolCapacity, allocator);
return pool;
}
bool increaseCapacity(Allocator* allocator) {
if (capacity_ == maxPools)
return false;
void* newPools;
auto newCapacity = PoolCount(capacity_ * 2);
if (pools_ == preallocatedPools_) {
newPools = allocator->allocate(newCapacity * sizeof(VariantPool));
if (!newPools)
return false;
memcpy(newPools, preallocatedPools_, sizeof(preallocatedPools_));
} else {
newPools =
allocator->reallocate(pools_, newCapacity * sizeof(VariantPool));
if (!newPools)
return false;
}
pools_ = static_cast<VariantPool*>(newPools);
capacity_ = newCapacity;
return true;
}
VariantPool preallocatedPools_[ARDUINOJSON_INITIAL_POOL_COUNT];
VariantPool* pools_ = preallocatedPools_;
PoolCount count_ = 0;
PoolCount capacity_ = ARDUINOJSON_INITIAL_POOL_COUNT;
SlotId freeList_ = NULL_SLOT;
public:
static const PoolCount maxPools =
PoolCount(NULL_SLOT / ARDUINOJSON_POOL_CAPACITY + 1);
};
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -51,6 +51,8 @@ class SerializedValue<TChar*> {
size_t size_; size_t size_;
}; };
using RawString = SerializedValue<const char*>;
template <typename T> template <typename T>
inline SerializedValue<T> serialized(T str) { inline SerializedValue<T> serialized(T str) {
return SerializedValue<T>(str); return SerializedValue<T>(str);

View File

@@ -1,11 +1,11 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
#include <ArduinoJson/Deserialization/deserialize.hpp> #include <ArduinoJson/Deserialization/deserialize.hpp>
#include <ArduinoJson/Memory/MemoryPool.hpp> #include <ArduinoJson/Memory/ResourceManager.hpp>
#include <ArduinoJson/MsgPack/endianess.hpp> #include <ArduinoJson/MsgPack/endianess.hpp>
#include <ArduinoJson/MsgPack/ieee754.hpp> #include <ArduinoJson/MsgPack/ieee754.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp> #include <ArduinoJson/Polyfills/type_traits.hpp>
@@ -13,14 +13,13 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TReader, typename TStringStorage> template <typename TReader>
class MsgPackDeserializer { class MsgPackDeserializer {
public: public:
MsgPackDeserializer(MemoryPool* pool, TReader reader, MsgPackDeserializer(ResourceManager* resources, TReader reader)
TStringStorage stringStorage) : resources_(resources),
: pool_(pool),
reader_(reader), reader_(reader),
stringStorage_(stringStorage), stringBuilder_(resources),
foundSomething_(false) {} foundSomething_(false) {}
template <typename TFilter> template <typename TFilter>
@@ -371,14 +370,14 @@ class MsgPackDeserializer {
if (err) if (err)
return err; return err;
variant->setString(stringStorage_.save()); variant->setOwnedString(stringBuilder_.save());
return DeserializationError::Ok; return DeserializationError::Ok;
} }
DeserializationError::Code readString(size_t n) { DeserializationError::Code readString(size_t n) {
DeserializationError::Code err; DeserializationError::Code err;
stringStorage_.startString(); stringBuilder_.startString();
for (; n; --n) { for (; n; --n) {
uint8_t c; uint8_t c;
@@ -386,10 +385,10 @@ class MsgPackDeserializer {
if (err) if (err)
return err; return err;
stringStorage_.append(static_cast<char>(c)); stringBuilder_.append(static_cast<char>(c));
} }
if (!stringStorage_.isValid()) if (!stringBuilder_.isValid())
return DeserializationError::NoMemory; return DeserializationError::NoMemory;
return DeserializationError::Ok; return DeserializationError::Ok;
@@ -420,7 +419,7 @@ class MsgPackDeserializer {
bool allowArray = filter.allowArray(); bool allowArray = filter.allowArray();
CollectionData* array; ArrayData* array;
if (allowArray) { if (allowArray) {
ARDUINOJSON_ASSERT(variant != 0); ARDUINOJSON_ASSERT(variant != 0);
array = &variant->toArray(); array = &variant->toArray();
@@ -428,21 +427,21 @@ class MsgPackDeserializer {
array = 0; array = 0;
} }
TFilter memberFilter = filter[0U]; TFilter elementFilter = filter[0U];
for (; n; --n) { for (; n; --n) {
VariantData* value; VariantData* value;
if (memberFilter.allow()) { if (elementFilter.allow()) {
ARDUINOJSON_ASSERT(array != 0); ARDUINOJSON_ASSERT(array != 0);
value = array->addElement(pool_); value = array->addElement(resources_);
if (!value) if (!value)
return DeserializationError::NoMemory; return DeserializationError::NoMemory;
} else { } else {
value = 0; value = 0;
} }
err = parseVariant(value, memberFilter, nestingLimit.decrement()); err = parseVariant(value, elementFilter, nestingLimit.decrement());
if (err) if (err)
return err; return err;
} }
@@ -473,7 +472,7 @@ class MsgPackDeserializer {
if (nestingLimit.reached()) if (nestingLimit.reached())
return DeserializationError::TooDeep; return DeserializationError::TooDeep;
CollectionData* object; ObjectData* object;
if (filter.allowObject()) { if (filter.allowObject()) {
ARDUINOJSON_ASSERT(variant != 0); ARDUINOJSON_ASSERT(variant != 0);
object = &variant->toObject(); object = &variant->toObject();
@@ -486,7 +485,7 @@ class MsgPackDeserializer {
if (err) if (err)
return err; return err;
JsonString key = stringStorage_.str(); JsonString key = stringBuilder_.str();
TFilter memberFilter = filter[key.c_str()]; TFilter memberFilter = filter[key.c_str()];
VariantData* member; VariantData* member;
@@ -494,16 +493,11 @@ class MsgPackDeserializer {
ARDUINOJSON_ASSERT(object != 0); ARDUINOJSON_ASSERT(object != 0);
// Save key in memory pool. // Save key in memory pool.
// This MUST be done before adding the slot. auto savedKey = stringBuilder_.save();
key = stringStorage_.save();
VariantSlot* slot = object->addSlot(pool_); member = object->addMember(savedKey, resources_);
if (!slot) if (!member)
return DeserializationError::NoMemory; return DeserializationError::NoMemory;
slot->setKey(key);
member = slot->data();
} else { } else {
member = 0; member = 0;
} }
@@ -554,9 +548,9 @@ class MsgPackDeserializer {
return skipBytes(size + 1U); return skipBytes(size + 1U);
} }
MemoryPool* pool_; ResourceManager* resources_;
TReader reader_; TReader reader_;
TStringStorage stringStorage_; StringBuilder stringBuilder_;
bool foundSomething_; bool foundSomething_;
}; };
@@ -565,20 +559,27 @@ ARDUINOJSON_END_PRIVATE_NAMESPACE
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
// Parses a MessagePack input and puts the result in a JsonDocument. // Parses a MessagePack input and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/ // https://arduinojson.org/v7/api/msgpack/deserializemsgpack/
template <typename... Args> template <typename TDestination, typename... Args>
DeserializationError deserializeMsgPack(JsonDocument& doc, Args&&... args) { typename detail::enable_if<
detail::is_deserialize_destination<TDestination>::value,
DeserializationError>::type
deserializeMsgPack(TDestination&& dst, Args&&... args) {
using namespace detail; using namespace detail;
return deserialize<MsgPackDeserializer>(doc, detail::forward<Args>(args)...); return deserialize<MsgPackDeserializer>(detail::forward<TDestination>(dst),
detail::forward<Args>(args)...);
} }
// Parses a MessagePack input and puts the result in a JsonDocument. // Parses a MessagePack input and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/ // https://arduinojson.org/v7/api/msgpack/deserializemsgpack/
template <typename TChar, typename... Args> template <typename TDestination, typename TChar, typename... Args>
DeserializationError deserializeMsgPack(JsonDocument& doc, TChar* input, typename detail::enable_if<
Args&&... args) { detail::is_deserialize_destination<TDestination>::value,
DeserializationError>::type
deserializeMsgPack(TDestination&& dst, TChar* input, Args&&... args) {
using namespace detail; using namespace detail;
return deserialize<MsgPackDeserializer>(doc, input, return deserialize<MsgPackDeserializer>(detail::forward<TDestination>(dst),
input,
detail::forward<Args>(args)...); detail::forward<Args>(args)...);
} }

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -15,18 +15,21 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TWriter> template <typename TWriter>
class MsgPackSerializer : public Visitor<size_t> { class MsgPackSerializer : public VariantDataVisitor<size_t> {
public: public:
static const bool producesText = false; static const bool producesText = false;
MsgPackSerializer(TWriter writer) : writer_(writer) {} MsgPackSerializer(TWriter writer, const ResourceManager* resources)
: writer_(writer), resources_(resources) {}
template <typename T> template <typename T>
typename enable_if<sizeof(T) == 4, size_t>::type visitFloat(T value32) { typename enable_if<is_floating_point<T>::value && sizeof(T) == 4,
size_t>::type
visit(T value32) {
if (canConvertNumber<JsonInteger>(value32)) { if (canConvertNumber<JsonInteger>(value32)) {
JsonInteger truncatedValue = JsonInteger(value32); JsonInteger truncatedValue = JsonInteger(value32);
if (value32 == T(truncatedValue)) if (value32 == T(truncatedValue))
return visitSignedInteger(truncatedValue); return visit(truncatedValue);
} }
writeByte(0xCA); writeByte(0xCA);
writeInteger(value32); writeInteger(value32);
@@ -35,17 +38,18 @@ class MsgPackSerializer : public Visitor<size_t> {
template <typename T> template <typename T>
ARDUINOJSON_NO_SANITIZE("float-cast-overflow") ARDUINOJSON_NO_SANITIZE("float-cast-overflow")
typename enable_if<sizeof(T) == 8, size_t>::type visitFloat(T value64) { typename enable_if<is_floating_point<T>::value && sizeof(T) == 8,
size_t>::type visit(T value64) {
float value32 = float(value64); float value32 = float(value64);
if (value32 == value64) if (value32 == value64)
return visitFloat(value32); return visit(value32);
writeByte(0xCB); writeByte(0xCB);
writeInteger(value64); writeInteger(value64);
return bytesWritten(); return bytesWritten();
} }
size_t visitArray(const CollectionData& array) { size_t visit(const ArrayData& array) {
size_t n = array.size(); size_t n = array.size(resources_);
if (n < 0x10) { if (n < 0x10) {
writeByte(uint8_t(0x90 + n)); writeByte(uint8_t(0x90 + n));
} else if (n < 0x10000) { } else if (n < 0x10000) {
@@ -55,14 +59,15 @@ class MsgPackSerializer : public Visitor<size_t> {
writeByte(0xDD); writeByte(0xDD);
writeInteger(uint32_t(n)); writeInteger(uint32_t(n));
} }
for (const VariantSlot* slot = array.head(); slot; slot = slot->next()) { for (auto it = array.createIterator(resources_); !it.done();
slot->data()->accept(*this); it.next(resources_)) {
it->accept(*this);
} }
return bytesWritten(); return bytesWritten();
} }
size_t visitObject(const CollectionData& object) { size_t visit(const ObjectData& object) {
size_t n = object.size(); size_t n = object.size(resources_);
if (n < 0x10) { if (n < 0x10) {
writeByte(uint8_t(0x80 + n)); writeByte(uint8_t(0x80 + n));
} else if (n < 0x10000) { } else if (n < 0x10000) {
@@ -72,20 +77,23 @@ class MsgPackSerializer : public Visitor<size_t> {
writeByte(0xDF); writeByte(0xDF);
writeInteger(uint32_t(n)); writeInteger(uint32_t(n));
} }
for (const VariantSlot* slot = object.head(); slot; slot = slot->next()) { for (auto it = object.createIterator(resources_); !it.done();
visitString(slot->key()); it.next(resources_)) {
slot->data()->accept(*this); visit(it.key());
it->accept(*this);
} }
return bytesWritten(); return bytesWritten();
} }
size_t visitString(const char* value) { size_t visit(const char* value) {
return visitString(value, strlen(value)); return visit(JsonString(value));
} }
size_t visitString(const char* value, size_t n) { size_t visit(JsonString value) {
ARDUINOJSON_ASSERT(value != NULL); ARDUINOJSON_ASSERT(value != NULL);
auto n = value.size();
if (n < 0x20) { if (n < 0x20) {
writeByte(uint8_t(0xA0 + n)); writeByte(uint8_t(0xA0 + n));
} else if (n < 0x100) { } else if (n < 0x100) {
@@ -98,18 +106,18 @@ class MsgPackSerializer : public Visitor<size_t> {
writeByte(0xDB); writeByte(0xDB);
writeInteger(uint32_t(n)); writeInteger(uint32_t(n));
} }
writeBytes(reinterpret_cast<const uint8_t*>(value), n); writeBytes(reinterpret_cast<const uint8_t*>(value.c_str()), n);
return bytesWritten(); return bytesWritten();
} }
size_t visitRawJson(const char* data, size_t size) { size_t visit(RawString value) {
writeBytes(reinterpret_cast<const uint8_t*>(data), size); writeBytes(reinterpret_cast<const uint8_t*>(value.data()), value.size());
return bytesWritten(); return bytesWritten();
} }
size_t visitSignedInteger(JsonInteger value) { size_t visit(JsonInteger value) {
if (value > 0) { if (value > 0) {
visitUnsignedInteger(static_cast<JsonUInt>(value)); visit(static_cast<JsonUInt>(value));
} else if (value >= -0x20) { } else if (value >= -0x20) {
writeInteger(int8_t(value)); writeInteger(int8_t(value));
} else if (value >= -0x80) { } else if (value >= -0x80) {
@@ -137,7 +145,7 @@ class MsgPackSerializer : public Visitor<size_t> {
return bytesWritten(); return bytesWritten();
} }
size_t visitUnsignedInteger(JsonUInt value) { size_t visit(JsonUInt value) {
if (value <= 0x7F) { if (value <= 0x7F) {
writeInteger(uint8_t(value)); writeInteger(uint8_t(value));
} else if (value <= 0xFF) { } else if (value <= 0xFF) {
@@ -165,12 +173,12 @@ class MsgPackSerializer : public Visitor<size_t> {
return bytesWritten(); return bytesWritten();
} }
size_t visitBoolean(bool value) { size_t visit(bool value) {
writeByte(value ? 0xC3 : 0xC2); writeByte(value ? 0xC3 : 0xC2);
return bytesWritten(); return bytesWritten();
} }
size_t visitNull() { size_t visit(nullptr_t) {
writeByte(0xC0); writeByte(0xC0);
return bytesWritten(); return bytesWritten();
} }
@@ -195,6 +203,7 @@ class MsgPackSerializer : public Visitor<size_t> {
} }
CountingDecorator<TWriter> writer_; CountingDecorator<TWriter> writer_;
const ResourceManager* resources_;
}; };
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE
@@ -202,7 +211,7 @@ ARDUINOJSON_END_PRIVATE_NAMESPACE
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
// Produces a MessagePack document. // Produces a MessagePack document.
// https://arduinojson.org/v6/api/msgpack/serializemsgpack/ // https://arduinojson.org/v7/api/msgpack/serializemsgpack/
template <typename TDestination> template <typename TDestination>
inline size_t serializeMsgPack(JsonVariantConst source, TDestination& output) { inline size_t serializeMsgPack(JsonVariantConst source, TDestination& output) {
using namespace ArduinoJson::detail; using namespace ArduinoJson::detail;
@@ -210,7 +219,7 @@ inline size_t serializeMsgPack(JsonVariantConst source, TDestination& output) {
} }
// Produces a MessagePack document. // Produces a MessagePack document.
// https://arduinojson.org/v6/api/msgpack/serializemsgpack/ // https://arduinojson.org/v7/api/msgpack/serializemsgpack/
inline size_t serializeMsgPack(JsonVariantConst source, void* output, inline size_t serializeMsgPack(JsonVariantConst source, void* output,
size_t size) { size_t size) {
using namespace ArduinoJson::detail; using namespace ArduinoJson::detail;
@@ -218,7 +227,7 @@ inline size_t serializeMsgPack(JsonVariantConst source, void* output,
} }
// Computes the length of the document that serializeMsgPack() produces. // Computes the length of the document that serializeMsgPack() produces.
// https://arduinojson.org/v6/api/msgpack/measuremsgpack/ // https://arduinojson.org/v7/api/msgpack/measuremsgpack/
inline size_t measureMsgPack(JsonVariantConst source) { inline size_t measureMsgPack(JsonVariantConst source) {
using namespace ArduinoJson::detail; using namespace ArduinoJson::detail;
return measure<MsgPackSerializer>(source); return measure<MsgPackSerializer>(source);

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -11,15 +11,15 @@
#ifndef ARDUINOJSON_VERSION_NAMESPACE #ifndef ARDUINOJSON_VERSION_NAMESPACE
# define ARDUINOJSON_VERSION_NAMESPACE \ # define ARDUINOJSON_VERSION_NAMESPACE \
ARDUINOJSON_CONCAT4( \ ARDUINOJSON_CONCAT4(ARDUINOJSON_VERSION_MACRO, \
ARDUINOJSON_VERSION_MACRO, \ ARDUINOJSON_BIN2ALPHA(ARDUINOJSON_ENABLE_PROGMEM, \
ARDUINOJSON_BIN2ALPHA( \ ARDUINOJSON_USE_LONG_LONG, \
ARDUINOJSON_ENABLE_PROGMEM, ARDUINOJSON_USE_LONG_LONG, \ ARDUINOJSON_USE_DOUBLE, 1), \
ARDUINOJSON_USE_DOUBLE, ARDUINOJSON_ENABLE_STRING_DEDUPLICATION), \ ARDUINOJSON_BIN2ALPHA(ARDUINOJSON_ENABLE_NAN, \
ARDUINOJSON_BIN2ALPHA( \ ARDUINOJSON_ENABLE_INFINITY, \
ARDUINOJSON_ENABLE_NAN, ARDUINOJSON_ENABLE_INFINITY, \ ARDUINOJSON_ENABLE_COMMENTS, \
ARDUINOJSON_ENABLE_COMMENTS, ARDUINOJSON_DECODE_UNICODE), \ ARDUINOJSON_DECODE_UNICODE), \
ARDUINOJSON_SLOT_OFFSET_SIZE) ARDUINOJSON_SLOT_ID_SIZE)
#endif #endif

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -25,4 +25,4 @@ ARDUINOJSON_END_PUBLIC_NAMESPACE
static_assert(sizeof(T) <= sizeof(ArduinoJson::JsonInteger), \ static_assert(sizeof(T) <= sizeof(ArduinoJson::JsonInteger), \
"To use 64-bit integers with ArduinoJson, you must set " \ "To use 64-bit integers with ArduinoJson, you must set " \
"ARDUINOJSON_USE_LONG_LONG to 1. See " \ "ARDUINOJSON_USE_LONG_LONG to 1. See " \
"https://arduinojson.org/v6/api/config/use_long_long/"); "https://arduinojson.org/v7/api/config/use_long_long/");

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -147,6 +147,6 @@ template <typename T>
inline T parseNumber(const char* s) { inline T parseNumber(const char* s) {
VariantData value; VariantData value;
parseNumber(s, value); parseNumber(s, value);
return Converter<T>::fromJson(JsonVariantConst(&value)); return Converter<T>::fromJson(JsonVariantConst(&value, nullptr));
} }
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -12,7 +12,7 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
class JsonArray; class JsonArray;
// A reference to an object in a JsonDocument. // A reference to an object in a JsonDocument.
// https://arduinojson.org/v6/api/jsonobject/ // https://arduinojson.org/v7/api/jsonobject/
class JsonObject : public detail::VariantOperators<JsonObject> { class JsonObject : public detail::VariantOperators<JsonObject> {
friend class detail::VariantAttorney; friend class detail::VariantAttorney;
@@ -20,93 +20,88 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
typedef JsonObjectIterator iterator; typedef JsonObjectIterator iterator;
// Creates an unbound reference. // Creates an unbound reference.
FORCE_INLINE JsonObject() : data_(0), pool_(0) {} FORCE_INLINE JsonObject() : data_(0), resources_(0) {}
// INTERNAL USE ONLY // INTERNAL USE ONLY
FORCE_INLINE JsonObject(detail::MemoryPool* buf, detail::CollectionData* data) FORCE_INLINE JsonObject(detail::ObjectData* data,
: data_(data), pool_(buf) {} detail::ResourceManager* resource)
: data_(data), resources_(resource) {}
operator JsonVariant() const { operator JsonVariant() const {
void* data = data_; // prevent warning cast-align void* data = data_; // prevent warning cast-align
return JsonVariant(pool_, reinterpret_cast<detail::VariantData*>(data)); return JsonVariant(reinterpret_cast<detail::VariantData*>(data),
resources_);
} }
operator JsonObjectConst() const { operator JsonObjectConst() const {
return JsonObjectConst(data_); return JsonObjectConst(data_, resources_);
} }
operator JsonVariantConst() const { operator JsonVariantConst() const {
return JsonVariantConst(collectionToVariant(data_)); return JsonVariantConst(collectionToVariant(data_), resources_);
} }
// Returns true if the reference is unbound. // Returns true if the reference is unbound.
// https://arduinojson.org/v6/api/jsonobject/isnull/ // https://arduinojson.org/v7/api/jsonobject/isnull/
FORCE_INLINE bool isNull() const { FORCE_INLINE bool isNull() const {
return data_ == 0; return data_ == 0;
} }
// Returns true if the reference is bound. // Returns true if the reference is bound.
// https://arduinojson.org/v6/api/jsonobject/isnull/ // https://arduinojson.org/v7/api/jsonobject/isnull/
FORCE_INLINE operator bool() const { FORCE_INLINE operator bool() const {
return data_ != 0; return data_ != 0;
} }
// Returns the number of bytes occupied by the object.
// https://arduinojson.org/v6/api/jsonobject/memoryusage/
FORCE_INLINE size_t memoryUsage() const {
return data_ ? data_->memoryUsage() : 0;
}
// Returns the depth (nesting level) of the object. // Returns the depth (nesting level) of the object.
// https://arduinojson.org/v6/api/jsonobject/nesting/ // https://arduinojson.org/v7/api/jsonobject/nesting/
FORCE_INLINE size_t nesting() const { FORCE_INLINE size_t nesting() const {
return variantNesting(collectionToVariant(data_)); return detail::VariantData::nesting(collectionToVariant(data_), resources_);
} }
// Returns the number of members in the object. // Returns the number of members in the object.
// https://arduinojson.org/v6/api/jsonobject/size/ // https://arduinojson.org/v7/api/jsonobject/size/
FORCE_INLINE size_t size() const { FORCE_INLINE size_t size() const {
return data_ ? data_->size() : 0; return data_ ? data_->size(resources_) : 0;
} }
// Returns an iterator to the first key-value pair of the object. // Returns an iterator to the first key-value pair of the object.
// https://arduinojson.org/v6/api/jsonobject/begin/ // https://arduinojson.org/v7/api/jsonobject/begin/
FORCE_INLINE iterator begin() const { FORCE_INLINE iterator begin() const {
if (!data_) if (!data_)
return iterator(); return iterator();
return iterator(pool_, data_->head()); return iterator(data_->createIterator(resources_), resources_);
} }
// Returns an iterator following the last key-value pair of the object. // Returns an iterator following the last key-value pair of the object.
// https://arduinojson.org/v6/api/jsonobject/end/ // https://arduinojson.org/v7/api/jsonobject/end/
FORCE_INLINE iterator end() const { FORCE_INLINE iterator end() const {
return iterator(); return iterator();
} }
// Removes all the members of the object. // Removes all the members of the object.
// ⚠️ Doesn't release the memory associated with the removed members. // https://arduinojson.org/v7/api/jsonobject/clear/
// https://arduinojson.org/v6/api/jsonobject/clear/
void clear() const { void clear() const {
if (!data_) detail::ObjectData::clear(data_, resources_);
return;
data_->clear();
} }
// Copies an object. // Copies an object.
// https://arduinojson.org/v6/api/jsonobject/set/ // https://arduinojson.org/v7/api/jsonobject/set/
FORCE_INLINE bool set(JsonObjectConst src) { FORCE_INLINE bool set(JsonObjectConst src) {
if (!data_ || !src.data_) if (!data_ || !src.data_)
return false; return false;
return data_->copyFrom(*src.data_, pool_);
clear();
for (auto kvp : src) {
if (!operator[](kvp.key()).set(kvp.value()))
return false;
} }
// Compares the content of two objects. return true;
FORCE_INLINE bool operator==(JsonObject rhs) const {
return JsonObjectConst(data_) == JsonObjectConst(rhs.data_);
} }
// Gets or sets the member with specified key. // Gets or sets the member with specified key.
// https://arduinojson.org/v6/api/jsonobject/subscript/ // https://arduinojson.org/v7/api/jsonobject/subscript/
template <typename TString> template <typename TString>
FORCE_INLINE FORCE_INLINE
typename detail::enable_if<detail::IsString<TString>::value, typename detail::enable_if<detail::IsString<TString>::value,
@@ -116,7 +111,7 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
} }
// Gets or sets the member with specified key. // Gets or sets the member with specified key.
// https://arduinojson.org/v6/api/jsonobject/subscript/ // https://arduinojson.org/v7/api/jsonobject/subscript/
template <typename TChar> template <typename TChar>
FORCE_INLINE FORCE_INLINE
typename detail::enable_if<detail::IsString<TChar*>::value, typename detail::enable_if<detail::IsString<TChar*>::value,
@@ -126,75 +121,84 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
} }
// Removes the member at the specified iterator. // Removes the member at the specified iterator.
// ⚠️ Doesn't release the memory associated with the removed member. // https://arduinojson.org/v7/api/jsonobject/remove/
// https://arduinojson.org/v6/api/jsonobject/remove/
FORCE_INLINE void remove(iterator it) const { FORCE_INLINE void remove(iterator it) const {
if (!data_) detail::ObjectData::remove(data_, it.iterator_, resources_);
return;
data_->removeSlot(it.slot_);
} }
// Removes the member with the specified key. // Removes the member with the specified key.
// ⚠️ Doesn't release the memory associated with the removed member. // https://arduinojson.org/v7/api/jsonobject/remove/
// https://arduinojson.org/v6/api/jsonobject/remove/
template <typename TString> template <typename TString>
FORCE_INLINE void remove(const TString& key) const { FORCE_INLINE void remove(const TString& key) const {
removeMember(detail::adaptString(key)); detail::ObjectData::removeMember(data_, detail::adaptString(key),
resources_);
} }
// Removes the member with the specified key. // Removes the member with the specified key.
// ⚠️ Doesn't release the memory associated with the removed member. // https://arduinojson.org/v7/api/jsonobject/remove/
// https://arduinojson.org/v6/api/jsonobject/remove/
template <typename TChar> template <typename TChar>
FORCE_INLINE void remove(TChar* key) const { FORCE_INLINE void remove(TChar* key) const {
removeMember(detail::adaptString(key)); detail::ObjectData::removeMember(data_, detail::adaptString(key),
resources_);
} }
// Returns true if the object contains the specified key. // Returns true if the object contains the specified key.
// https://arduinojson.org/v6/api/jsonobject/containskey/ // https://arduinojson.org/v7/api/jsonobject/containskey/
template <typename TString> template <typename TString>
FORCE_INLINE FORCE_INLINE
typename detail::enable_if<detail::IsString<TString>::value, bool>::type typename detail::enable_if<detail::IsString<TString>::value, bool>::type
containsKey(const TString& key) const { containsKey(const TString& key) const {
return getMember(detail::adaptString(key)) != 0; return detail::ObjectData::getMember(data_, detail::adaptString(key),
resources_) != 0;
} }
// Returns true if the object contains the specified key. // Returns true if the object contains the specified key.
// https://arduinojson.org/v6/api/jsonobject/containskey/ // https://arduinojson.org/v7/api/jsonobject/containskey/
template <typename TChar> template <typename TChar>
FORCE_INLINE FORCE_INLINE
typename detail::enable_if<detail::IsString<TChar*>::value, bool>::type typename detail::enable_if<detail::IsString<TChar*>::value, bool>::type
containsKey(TChar* key) const { containsKey(TChar* key) const {
return getMember(detail::adaptString(key)) != 0; return detail::ObjectData::getMember(data_, detail::adaptString(key),
resources_) != 0;
} }
// Creates an array and adds it to the object. // DEPRECATED: use obj[key].to<JsonArray>() instead
// https://arduinojson.org/v6/api/jsonobject/createnestedarray/
template <typename TString>
FORCE_INLINE JsonArray createNestedArray(const TString& key) const;
// Creates an array and adds it to the object.
// https://arduinojson.org/v6/api/jsonobject/createnestedarray/
template <typename TChar> template <typename TChar>
FORCE_INLINE JsonArray createNestedArray(TChar* key) const; ARDUINOJSON_DEPRECATED("use obj[key].to<JsonArray>() instead")
JsonArray createNestedArray(TChar* key) const {
return operator[](key).template to<JsonArray>();
}
// Creates an object and adds it to the object. // DEPRECATED: use obj[key].to<JsonArray>() instead
// https://arduinojson.org/v6/api/jsonobject/createnestedobject/
template <typename TString> template <typename TString>
JsonObject createNestedObject(const TString& key) const { ARDUINOJSON_DEPRECATED("use obj[key].to<JsonArray>() instead")
JsonArray createNestedArray(const TString& key) const {
return operator[](key).template to<JsonArray>();
}
// DEPRECATED: use obj[key].to<JsonObject>() instead
template <typename TChar>
ARDUINOJSON_DEPRECATED("use obj[key].to<JsonObject>() instead")
JsonObject createNestedObject(TChar* key) {
return operator[](key).template to<JsonObject>(); return operator[](key).template to<JsonObject>();
} }
// Creates an object and adds it to the object. // DEPRECATED: use obj[key].to<JsonObject>() instead
// https://arduinojson.org/v6/api/jsonobject/createnestedobject/ template <typename TString>
template <typename TChar> ARDUINOJSON_DEPRECATED("use obj[key].to<JsonObject>() instead")
JsonObject createNestedObject(TChar* key) const { JsonObject createNestedObject(const TString& key) {
return operator[](key).template to<JsonObject>(); return operator[](key).template to<JsonObject>();
} }
// DEPRECATED: always returns zero
ARDUINOJSON_DEPRECATED("always returns zero")
size_t memoryUsage() const {
return 0;
}
private: private:
detail::MemoryPool* getPool() const { detail::ResourceManager* getResourceManager() const {
return pool_; return resources_;
} }
detail::VariantData* getData() const { detail::VariantData* getData() const {
@@ -205,47 +209,8 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
return detail::collectionToVariant(data_); return detail::collectionToVariant(data_);
} }
template <typename TAdaptedString> detail::ObjectData* data_;
inline detail::VariantData* getMember(TAdaptedString key) const { detail::ResourceManager* resources_;
if (!data_)
return 0;
return data_->getMember(key);
}
template <typename TAdaptedString>
void removeMember(TAdaptedString key) const {
if (!data_)
return;
data_->removeMember(key);
}
detail::CollectionData* data_;
detail::MemoryPool* pool_;
};
template <>
struct Converter<JsonObject> : private detail::VariantAttorney {
static void toJson(JsonVariantConst src, JsonVariant dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst));
}
static JsonObject fromJson(JsonVariant src) {
auto data = getData(src);
auto pool = getPool(src);
return JsonObject(pool, data != 0 ? data->asObject() : 0);
}
static detail::InvalidConversion<JsonVariantConst, JsonObject> fromJson(
JsonVariantConst);
static bool checkJson(JsonVariantConst) {
return false;
}
static bool checkJson(JsonVariant src) {
auto data = getData(src);
return data && data->isObject();
}
}; };
ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -10,7 +10,7 @@
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
// A read-only reference to an object in a JsonDocument. // A read-only reference to an object in a JsonDocument.
// https://arduinojson.org/v6/api/jsonobjectconst/ // https://arduinojson.org/v7/api/jsonobjectconst/
class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> { class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
friend class JsonObject; friend class JsonObject;
friend class detail::VariantAttorney; friend class detail::VariantAttorney;
@@ -22,103 +22,94 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
JsonObjectConst() : data_(0) {} JsonObjectConst() : data_(0) {}
// INTERNAL USE ONLY // INTERNAL USE ONLY
JsonObjectConst(const detail::CollectionData* data) : data_(data) {} JsonObjectConst(const detail::ObjectData* data,
const detail::ResourceManager* resources)
: data_(data), resources_(resources) {}
operator JsonVariantConst() const { operator JsonVariantConst() const {
return JsonVariantConst(collectionToVariant(data_)); return JsonVariantConst(getData(), resources_);
} }
// Returns true if the reference is unbound. // Returns true if the reference is unbound.
// https://arduinojson.org/v6/api/jsonobjectconst/isnull/ // https://arduinojson.org/v7/api/jsonobjectconst/isnull/
FORCE_INLINE bool isNull() const { FORCE_INLINE bool isNull() const {
return data_ == 0; return data_ == 0;
} }
// Returns true if the reference is bound. // Returns true if the reference is bound.
// https://arduinojson.org/v6/api/jsonobjectconst/isnull/ // https://arduinojson.org/v7/api/jsonobjectconst/isnull/
FORCE_INLINE operator bool() const { FORCE_INLINE operator bool() const {
return data_ != 0; return data_ != 0;
} }
// Returns the number of bytes occupied by the object.
// https://arduinojson.org/v6/api/jsonobjectconst/memoryusage/
FORCE_INLINE size_t memoryUsage() const {
return data_ ? data_->memoryUsage() : 0;
}
// Returns the depth (nesting level) of the object. // Returns the depth (nesting level) of the object.
// https://arduinojson.org/v6/api/jsonobjectconst/nesting/ // https://arduinojson.org/v7/api/jsonobjectconst/nesting/
FORCE_INLINE size_t nesting() const { FORCE_INLINE size_t nesting() const {
return variantNesting(collectionToVariant(data_)); return detail::VariantData::nesting(getData(), resources_);
} }
// Returns the number of members in the object. // Returns the number of members in the object.
// https://arduinojson.org/v6/api/jsonobjectconst/size/ // https://arduinojson.org/v7/api/jsonobjectconst/size/
FORCE_INLINE size_t size() const { FORCE_INLINE size_t size() const {
return data_ ? data_->size() : 0; return data_ ? data_->size(resources_) : 0;
} }
// Returns an iterator to the first key-value pair of the object. // Returns an iterator to the first key-value pair of the object.
// https://arduinojson.org/v6/api/jsonobjectconst/begin/ // https://arduinojson.org/v7/api/jsonobjectconst/begin/
FORCE_INLINE iterator begin() const { FORCE_INLINE iterator begin() const {
if (!data_) if (!data_)
return iterator(); return iterator();
return iterator(data_->head()); return iterator(data_->createIterator(resources_), resources_);
} }
// Returns an iterator following the last key-value pair of the object. // Returns an iterator following the last key-value pair of the object.
// https://arduinojson.org/v6/api/jsonobjectconst/end/ // https://arduinojson.org/v7/api/jsonobjectconst/end/
FORCE_INLINE iterator end() const { FORCE_INLINE iterator end() const {
return iterator(); return iterator();
} }
// Returns true if the object contains the specified key. // Returns true if the object contains the specified key.
// https://arduinojson.org/v6/api/jsonobjectconst/containskey/ // https://arduinojson.org/v7/api/jsonobjectconst/containskey/
template <typename TString> template <typename TString>
FORCE_INLINE bool containsKey(const TString& key) const { FORCE_INLINE bool containsKey(const TString& key) const {
return getMember(detail::adaptString(key)) != 0; return detail::ObjectData::getMember(data_, detail::adaptString(key),
resources_) != 0;
} }
// Returns true if the object contains the specified key. // Returns true if the object contains the specified key.
// https://arduinojson.org/v6/api/jsonobjectconst/containskey/ // https://arduinojson.org/v7/api/jsonobjectconst/containskey/
template <typename TChar> template <typename TChar>
FORCE_INLINE bool containsKey(TChar* key) const { FORCE_INLINE bool containsKey(TChar* key) const {
return getMember(detail::adaptString(key)) != 0; return detail::ObjectData::getMember(data_, detail::adaptString(key),
resources_) != 0;
} }
// Gets the member with specified key. // Gets the member with specified key.
// https://arduinojson.org/v6/api/jsonobjectconst/subscript/ // https://arduinojson.org/v7/api/jsonobjectconst/subscript/
template <typename TString> template <typename TString>
FORCE_INLINE typename detail::enable_if<detail::IsString<TString>::value, FORCE_INLINE typename detail::enable_if<detail::IsString<TString>::value,
JsonVariantConst>::type JsonVariantConst>::type
operator[](const TString& key) const { operator[](const TString& key) const {
return JsonVariantConst(getMember(detail::adaptString(key))); return JsonVariantConst(detail::ObjectData::getMember(
data_, detail::adaptString(key), resources_),
resources_);
} }
// Gets the member with specified key. // Gets the member with specified key.
// https://arduinojson.org/v6/api/jsonobjectconst/subscript/ // https://arduinojson.org/v7/api/jsonobjectconst/subscript/
template <typename TChar> template <typename TChar>
FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value, FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value,
JsonVariantConst>::type JsonVariantConst>::type
operator[](TChar* key) const { operator[](TChar* key) const {
return JsonVariantConst(getMember(detail::adaptString(key))); return JsonVariantConst(detail::ObjectData::getMember(
data_, detail::adaptString(key), resources_),
resources_);
} }
// Compares objects. // DEPRECATED: always returns zero
FORCE_INLINE bool operator==(JsonObjectConst rhs) const { ARDUINOJSON_DEPRECATED("always returns zero")
if (data_ == rhs.data_) size_t memoryUsage() const {
return true; return 0;
if (!data_ || !rhs.data_)
return false;
size_t count = 0;
for (iterator it = begin(); it != end(); ++it) {
if (it->value() != rhs[it->key()])
return false;
count++;
}
return count == rhs.size();
} }
private: private:
@@ -126,31 +117,27 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
return collectionToVariant(data_); return collectionToVariant(data_);
} }
template <typename TAdaptedString> const detail::ObjectData* data_;
const detail::VariantData* getMember(TAdaptedString key) const { const detail::ResourceManager* resources_;
if (!data_)
return 0;
return data_->getMember(key);
}
const detail::CollectionData* data_;
}; };
template <> inline bool operator==(JsonObjectConst lhs, JsonObjectConst rhs) {
struct Converter<JsonObjectConst> : private detail::VariantAttorney { if (!lhs && !rhs) // both are null
static void toJson(JsonVariantConst src, JsonVariant dst) { return true;
variantCopyFrom(getData(dst), getData(src), getPool(dst));
}
static JsonObjectConst fromJson(JsonVariantConst src) { if (!lhs || !rhs) // only one is null
auto data = getData(src); return false;
return data != 0 ? data->asObject() : 0;
}
static bool checkJson(JsonVariantConst src) { size_t count = 0;
auto data = getData(src); for (auto kvp : lhs) {
return data && data->isObject(); auto rhsValue = rhs[kvp.key()];
if (rhsValue.isUnbound())
return false;
if (kvp.value() != rhsValue)
return false;
count++;
}
return count == rhs.size();
} }
};
ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@@ -1,85 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Array/JsonArray.hpp>
#include <ArduinoJson/Object/JsonObject.hpp>
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
template <typename TString>
inline JsonArray JsonObject::createNestedArray(const TString& key) const {
return operator[](key).template to<JsonArray>();
}
template <typename TChar>
inline JsonArray JsonObject::createNestedArray(TChar* key) const {
return operator[](key).template to<JsonArray>();
}
ARDUINOJSON_END_PUBLIC_NAMESPACE
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TDerived>
template <typename TString>
inline JsonArray VariantRefBase<TDerived>::createNestedArray(
const TString& key) const {
return operator[](key).template to<JsonArray>();
}
template <typename TDerived>
template <typename TChar>
inline JsonArray VariantRefBase<TDerived>::createNestedArray(TChar* key) const {
return operator[](key).template to<JsonArray>();
}
template <typename TDerived>
template <typename TString>
inline JsonObject VariantRefBase<TDerived>::createNestedObject(
const TString& key) const {
return operator[](key).template to<JsonObject>();
}
template <typename TDerived>
template <typename TChar>
inline JsonObject VariantRefBase<TDerived>::createNestedObject(
TChar* key) const {
return operator[](key).template to<JsonObject>();
}
template <typename TDerived>
template <typename TString>
inline typename enable_if<IsString<TString>::value, bool>::type
VariantRefBase<TDerived>::containsKey(const TString& key) const {
return variantGetMember(VariantAttorney::getData(derived()),
adaptString(key)) != 0;
}
template <typename TDerived>
template <typename TChar>
inline typename enable_if<IsString<TChar*>::value, bool>::type
VariantRefBase<TDerived>::containsKey(TChar* key) const {
return variantGetMember(VariantAttorney::getData(derived()),
adaptString(key)) != 0;
}
template <typename TDerived>
template <typename TString>
inline typename enable_if<IsString<TString*>::value,
MemberProxy<TDerived, TString*>>::type
VariantRefBase<TDerived>::operator[](TString* key) const {
return MemberProxy<TDerived, TString*>(derived(), key);
}
template <typename TDerived>
template <typename TString>
inline typename enable_if<IsString<TString>::value,
MemberProxy<TDerived, TString>>::type
VariantRefBase<TDerived>::operator[](const TString& key) const {
return MemberProxy<TDerived, TString>(derived(), key);
}
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -1,123 +1,81 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
#include <ArduinoJson/Object/JsonPair.hpp> #include <ArduinoJson/Object/JsonPair.hpp>
#include <ArduinoJson/Variant/SlotFunctions.hpp>
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
class JsonPairPtr {
public:
JsonPairPtr(detail::MemoryPool* pool, detail::VariantSlot* slot)
: pair_(pool, slot) {}
const JsonPair* operator->() const {
return &pair_;
}
const JsonPair& operator*() const {
return pair_;
}
private:
JsonPair pair_;
};
class JsonObjectIterator { class JsonObjectIterator {
friend class JsonObject; friend class JsonObject;
public: public:
JsonObjectIterator() : slot_(0) {} JsonObjectIterator() {}
explicit JsonObjectIterator(detail::MemoryPool* pool, explicit JsonObjectIterator(detail::ObjectData::iterator iterator,
detail::VariantSlot* slot) detail::ResourceManager* resources)
: pool_(pool), slot_(slot) {} : iterator_(iterator), resources_(resources) {}
JsonPair operator*() const { JsonPair operator*() const {
return JsonPair(pool_, slot_); return JsonPair(iterator_, resources_);
} }
JsonPairPtr operator->() { Ptr<JsonPair> operator->() {
return JsonPairPtr(pool_, slot_); return operator*();
} }
bool operator==(const JsonObjectIterator& other) const { bool operator==(const JsonObjectIterator& other) const {
return slot_ == other.slot_; return iterator_ == other.iterator_;
} }
bool operator!=(const JsonObjectIterator& other) const { bool operator!=(const JsonObjectIterator& other) const {
return slot_ != other.slot_; return iterator_ != other.iterator_;
} }
JsonObjectIterator& operator++() { JsonObjectIterator& operator++() {
slot_ = slot_->next(); iterator_.next(resources_);
return *this;
}
JsonObjectIterator& operator+=(size_t distance) {
slot_ = slot_->next(distance);
return *this; return *this;
} }
private: private:
detail::MemoryPool* pool_; detail::ObjectData::iterator iterator_;
detail::VariantSlot* slot_; detail::ResourceManager* resources_;
};
class JsonPairConstPtr {
public:
JsonPairConstPtr(const detail::VariantSlot* slot) : pair_(slot) {}
const JsonPairConst* operator->() const {
return &pair_;
}
const JsonPairConst& operator*() const {
return pair_;
}
private:
JsonPairConst pair_;
}; };
class JsonObjectConstIterator { class JsonObjectConstIterator {
friend class JsonObject; friend class JsonObject;
public: public:
JsonObjectConstIterator() : slot_(0) {} JsonObjectConstIterator() {}
explicit JsonObjectConstIterator(const detail::VariantSlot* slot) explicit JsonObjectConstIterator(detail::ObjectData::iterator iterator,
: slot_(slot) {} const detail::ResourceManager* resources)
: iterator_(iterator), resources_(resources) {}
JsonPairConst operator*() const { JsonPairConst operator*() const {
return JsonPairConst(slot_); return JsonPairConst(iterator_, resources_);
} }
JsonPairConstPtr operator->() { Ptr<JsonPairConst> operator->() {
return JsonPairConstPtr(slot_); return operator*();
} }
bool operator==(const JsonObjectConstIterator& other) const { bool operator==(const JsonObjectConstIterator& other) const {
return slot_ == other.slot_; return iterator_ == other.iterator_;
} }
bool operator!=(const JsonObjectConstIterator& other) const { bool operator!=(const JsonObjectConstIterator& other) const {
return slot_ != other.slot_; return iterator_ != other.iterator_;
} }
JsonObjectConstIterator& operator++() { JsonObjectConstIterator& operator++() {
slot_ = slot_->next(); iterator_.next(resources_);
return *this;
}
JsonObjectConstIterator& operator+=(size_t distance) {
slot_ = slot_->next(distance);
return *this; return *this;
} }
private: private:
const detail::VariantSlot* slot_; detail::ObjectData::iterator iterator_;
const detail::ResourceManager* resources_;
}; };
ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org // ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2024, Benoit BLANCHON
// MIT License // MIT License
#pragma once #pragma once
@@ -11,58 +11,60 @@
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
// A key-value pair. // A key-value pair.
// https://arduinojson.org/v6/api/jsonobject/begin_end/ // https://arduinojson.org/v7/api/jsonobject/begin_end/
class JsonPair { class JsonPair {
public: public:
// INTERNAL USE ONLY // INTERNAL USE ONLY
JsonPair(detail::MemoryPool* pool, detail::VariantSlot* slot) { JsonPair(detail::ObjectData::iterator iterator,
if (slot) { detail::ResourceManager* resources)
key_ = JsonString(slot->key(), slot->ownsKey() ? JsonString::Copied : iterator_(iterator), resources_(resources) {}
: JsonString::Linked);
value_ = JsonVariant(pool, slot->data());
}
}
// Returns the key. // Returns the key.
JsonString key() const { JsonString key() const {
return key_; if (!iterator_.done())
return JsonString(iterator_.key(), iterator_.ownsKey()
? JsonString::Copied
: JsonString::Linked);
else
return JsonString();
} }
// Returns the value. // Returns the value.
JsonVariant value() const { JsonVariant value() {
return value_; return JsonVariant(iterator_.data(), resources_);
} }
private: private:
JsonString key_; detail::ObjectData::iterator iterator_;
JsonVariant value_; detail::ResourceManager* resources_;
}; };
// A read-only key-value pair. // A read-only key-value pair.
// https://arduinojson.org/v6/api/jsonobjectconst/begin_end/ // https://arduinojson.org/v7/api/jsonobjectconst/begin_end/
class JsonPairConst { class JsonPairConst {
public: public:
JsonPairConst(const detail::VariantSlot* slot) { JsonPairConst(detail::ObjectData::iterator iterator,
if (slot) { const detail::ResourceManager* resources)
key_ = JsonString(slot->key(), slot->ownsKey() ? JsonString::Copied : iterator_(iterator), resources_(resources) {}
: JsonString::Linked);
value_ = JsonVariantConst(slot->data());
}
}
// Returns the key. // Returns the key.
JsonString key() const { JsonString key() const {
return key_; if (!iterator_.done())
return JsonString(iterator_.key(), iterator_.ownsKey()
? JsonString::Copied
: JsonString::Linked);
else
return JsonString();
} }
// Returns the value. // Returns the value.
JsonVariantConst value() const { JsonVariantConst value() const {
return value_; return JsonVariantConst(iterator_.data(), resources_);
} }
private: private:
JsonString key_; detail::ObjectData::iterator iterator_;
JsonVariantConst value_; const detail::ResourceManager* resources_;
}; };
ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_END_PUBLIC_NAMESPACE

Some files were not shown because too many files have changed in this diff Show More