Compare commits
10 Commits
achalmers/
...
v0.16.0
Author | SHA1 | Date | |
---|---|---|---|
d11d363f19 | |||
f22ad7c4e7 | |||
1913519f68 | |||
4b9d4fd45b | |||
78e6816b06 | |||
6607ea1663 | |||
644a8ef3ca | |||
e3e132c0d5 | |||
be3fed8427 | |||
cefa6f85fe |
@ -1,3 +1,3 @@
|
||||
[codespell]
|
||||
ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo
|
||||
ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo,absolutey
|
||||
skip: **/target,node_modules,build,**/Cargo.lock
|
||||
|
50
.github/workflows/cargo-build.yml
vendored
50
.github/workflows/cargo-build.yml
vendored
@ -1,50 +0,0 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- '**.rs'
|
||||
- '**/Cargo.toml'
|
||||
- '**/Cargo.lock'
|
||||
- '**/rust-toolchain.toml'
|
||||
- .github/workflows/cargo-build.yml
|
||||
pull_request:
|
||||
paths:
|
||||
- '**.rs'
|
||||
- '**/Cargo.toml'
|
||||
- '**/Cargo.lock'
|
||||
- '**/rust-toolchain.toml'
|
||||
- .github/workflows/cargo-build.yml
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
name: cargo build
|
||||
jobs:
|
||||
cargobuild:
|
||||
name: cargo build
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
dir: ['src/wasm-lib']
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install latest rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
override: true
|
||||
|
||||
- name: install dependencies
|
||||
if: matrix.dir == 'src-tauri'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
|
||||
- name: Rust Cache
|
||||
uses: Swatinem/rust-cache@v2.6.1
|
||||
|
||||
- name: Run cargo build
|
||||
run: |
|
||||
cd "${{ matrix.dir }}"
|
||||
cargo build --all
|
||||
shell: bash
|
6
.github/workflows/cargo-clippy.yml
vendored
6
.github/workflows/cargo-clippy.yml
vendored
@ -9,12 +9,6 @@ on:
|
||||
- '**.rs'
|
||||
- .github/workflows/cargo-clippy.yml
|
||||
pull_request:
|
||||
paths:
|
||||
- '**/Cargo.toml'
|
||||
- '**/Cargo.lock'
|
||||
- '**/rust-toolchain.toml'
|
||||
- '**.rs'
|
||||
- .github/workflows/cargo-build.yml
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "untitled-app",
|
||||
"version": "0.15.6",
|
||||
"version": "0.16.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@codemirror/autocomplete": "^6.10.2",
|
||||
|
2
src-tauri/Cargo.lock
generated
2
src-tauri/Cargo.lock
generated
@ -3876,7 +3876,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "tauri-plugin-fs-extra"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#d95a1b382f512a0be748e7a89e0f8fc4278010e2"
|
||||
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#6db4320e98a4278d605dd05d4d87e1433939a7cd"
|
||||
dependencies = [
|
||||
"log",
|
||||
"serde",
|
||||
|
@ -7,7 +7,7 @@
|
||||
},
|
||||
"package": {
|
||||
"productName": "zoo-modeling-app",
|
||||
"version": "0.15.6"
|
||||
"version": "0.16.0"
|
||||
},
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
|
@ -59,6 +59,7 @@ const router = createBrowserRouter([
|
||||
{
|
||||
loader: fileLoader,
|
||||
id: paths.FILE,
|
||||
path: paths.FILE + '/:id',
|
||||
element: (
|
||||
<Auth>
|
||||
<FileMachineProvider>
|
||||
@ -74,8 +75,11 @@ const router = createBrowserRouter([
|
||||
),
|
||||
children: [
|
||||
{
|
||||
path: paths.FILE + '/:id',
|
||||
loader: onboardingRedirectLoader,
|
||||
index: true,
|
||||
element: <></>,
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
path: makeUrlPathRelative(paths.SETTINGS),
|
||||
|
@ -30,7 +30,7 @@ describe('NetworkHealthIndicator tests', () => {
|
||||
fireEvent.click(screen.getByTestId('network-toggle'))
|
||||
|
||||
expect(screen.getByTestId('network')).toHaveTextContent(
|
||||
NETWORK_HEALTH_TEXT[NetworkHealthState.Issue]
|
||||
NETWORK_HEALTH_TEXT[NetworkHealthState.Ok]
|
||||
)
|
||||
})
|
||||
|
||||
|
@ -6,8 +6,7 @@ import {
|
||||
ConnectingTypeGroup,
|
||||
DisconnectingType,
|
||||
engineCommandManager,
|
||||
EngineCommandManagerEvents,
|
||||
EngineConnectionEvents,
|
||||
EngineConnectionState,
|
||||
EngineConnectionStateType,
|
||||
ErrorType,
|
||||
initialConnectingTypeGroupState,
|
||||
@ -82,35 +81,37 @@ const overallConnectionStateIcon: Record<
|
||||
}
|
||||
|
||||
export function useNetworkStatus() {
|
||||
const [steps, setSteps] = useState(
|
||||
structuredClone(initialConnectingTypeGroupState)
|
||||
)
|
||||
const [steps, setSteps] = useState(initialConnectingTypeGroupState)
|
||||
const [internetConnected, setInternetConnected] = useState<boolean>(true)
|
||||
const [overallState, setOverallState] = useState<NetworkHealthState>(
|
||||
NetworkHealthState.Disconnected
|
||||
NetworkHealthState.Ok
|
||||
)
|
||||
const [pingPongHealth, setPingPongHealth] = useState<'OK' | 'BAD'>('BAD')
|
||||
const [hasCopied, setHasCopied] = useState<boolean>(false)
|
||||
|
||||
const [error, setError] = useState<ErrorType | undefined>(undefined)
|
||||
|
||||
const hasIssue = (i: [ConnectingType, boolean | undefined]) =>
|
||||
i[1] === undefined ? i[1] : !i[1]
|
||||
const issues: Record<ConnectingTypeGroup, boolean> = {
|
||||
[ConnectingTypeGroup.WebSocket]: steps[ConnectingTypeGroup.WebSocket].some(
|
||||
(a: [ConnectingType, boolean | undefined]) => a[1] === false
|
||||
),
|
||||
[ConnectingTypeGroup.ICE]: steps[ConnectingTypeGroup.ICE].some(
|
||||
(a: [ConnectingType, boolean | undefined]) => a[1] === false
|
||||
),
|
||||
[ConnectingTypeGroup.WebRTC]: steps[ConnectingTypeGroup.WebRTC].some(
|
||||
(a: [ConnectingType, boolean | undefined]) => a[1] === false
|
||||
),
|
||||
}
|
||||
|
||||
const [issues, setIssues] = useState<
|
||||
Record<ConnectingTypeGroup, boolean | undefined>
|
||||
>({
|
||||
[ConnectingTypeGroup.WebSocket]: undefined,
|
||||
[ConnectingTypeGroup.ICE]: undefined,
|
||||
[ConnectingTypeGroup.WebRTC]: undefined,
|
||||
})
|
||||
const hasIssues: boolean =
|
||||
issues[ConnectingTypeGroup.WebSocket] ||
|
||||
issues[ConnectingTypeGroup.ICE] ||
|
||||
issues[ConnectingTypeGroup.WebRTC]
|
||||
|
||||
const [hasIssues, setHasIssues] = useState<boolean | undefined>(undefined)
|
||||
useEffect(() => {
|
||||
setOverallState(
|
||||
!internetConnected
|
||||
? NetworkHealthState.Disconnected
|
||||
: hasIssues || hasIssues === undefined
|
||||
: hasIssues
|
||||
? NetworkHealthState.Issue
|
||||
: NetworkHealthState.Ok
|
||||
)
|
||||
@ -133,59 +134,19 @@ export function useNetworkStatus() {
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
console.log(pingPongHealth)
|
||||
}, [pingPongHealth])
|
||||
|
||||
useEffect(() => {
|
||||
const issues = {
|
||||
[ConnectingTypeGroup.WebSocket]: steps[
|
||||
ConnectingTypeGroup.WebSocket
|
||||
].reduce(
|
||||
(acc: boolean | undefined, a) =>
|
||||
acc === true || acc === undefined ? acc : hasIssue(a),
|
||||
false
|
||||
),
|
||||
[ConnectingTypeGroup.ICE]: steps[ConnectingTypeGroup.ICE].reduce(
|
||||
(acc: boolean | undefined, a) =>
|
||||
acc === true || acc === undefined ? acc : hasIssue(a),
|
||||
false
|
||||
),
|
||||
[ConnectingTypeGroup.WebRTC]: steps[ConnectingTypeGroup.WebRTC].reduce(
|
||||
(acc: boolean | undefined, a) =>
|
||||
acc === true || acc === undefined ? acc : hasIssue(a),
|
||||
false
|
||||
),
|
||||
}
|
||||
setIssues(issues)
|
||||
}, [steps])
|
||||
|
||||
useEffect(() => {
|
||||
setHasIssues(
|
||||
issues[ConnectingTypeGroup.WebSocket] ||
|
||||
issues[ConnectingTypeGroup.ICE] ||
|
||||
issues[ConnectingTypeGroup.WebRTC]
|
||||
)
|
||||
}, [issues])
|
||||
|
||||
useEffect(() => {
|
||||
const onPingPongChange = ({ detail: state }: CustomEvent) => {
|
||||
setPingPongHealth(state)
|
||||
}
|
||||
|
||||
const onConnectionStateChange = ({
|
||||
detail: engineConnectionState,
|
||||
}: CustomEvent) => {
|
||||
setSteps((steps) => {
|
||||
let nextSteps = structuredClone(steps)
|
||||
engineCommandManager.onConnectionStateChange(
|
||||
(engineConnectionState: EngineConnectionState) => {
|
||||
let hasSetAStep = false
|
||||
|
||||
if (
|
||||
engineConnectionState.type === EngineConnectionStateType.Connecting
|
||||
) {
|
||||
const groups = Object.values(nextSteps)
|
||||
const groups = Object.values(steps)
|
||||
for (let group of groups) {
|
||||
for (let step of group) {
|
||||
if (step[0] !== engineConnectionState.value.type) continue
|
||||
step[1] = true
|
||||
hasSetAStep = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -193,7 +154,7 @@ export function useNetworkStatus() {
|
||||
if (
|
||||
engineConnectionState.type === EngineConnectionStateType.Disconnecting
|
||||
) {
|
||||
const groups = Object.values(nextSteps)
|
||||
const groups = Object.values(steps)
|
||||
for (let group of groups) {
|
||||
for (let step of group) {
|
||||
if (
|
||||
@ -204,6 +165,7 @@ export function useNetworkStatus() {
|
||||
?.type === step[0]
|
||||
) {
|
||||
step[1] = false
|
||||
hasSetAStep = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -214,50 +176,11 @@ export function useNetworkStatus() {
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the state of all steps if we have disconnected.
|
||||
if (
|
||||
engineConnectionState.type === EngineConnectionStateType.Disconnected
|
||||
) {
|
||||
return structuredClone(initialConnectingTypeGroupState)
|
||||
if (hasSetAStep) {
|
||||
setSteps(steps)
|
||||
}
|
||||
|
||||
return nextSteps
|
||||
})
|
||||
}
|
||||
|
||||
const onEngineAvailable = ({ detail: engineConnection }: CustomEvent) => {
|
||||
engineConnection.addEventListener(
|
||||
EngineConnectionEvents.PingPongChanged,
|
||||
onPingPongChange as EventListener
|
||||
)
|
||||
engineConnection.addEventListener(
|
||||
EngineConnectionEvents.ConnectionStateChanged,
|
||||
onConnectionStateChange as EventListener
|
||||
)
|
||||
}
|
||||
|
||||
engineCommandManager.addEventListener(
|
||||
EngineCommandManagerEvents.EngineAvailable,
|
||||
onEngineAvailable as EventListener
|
||||
}
|
||||
)
|
||||
|
||||
return () => {
|
||||
engineCommandManager.removeEventListener(
|
||||
EngineCommandManagerEvents.EngineAvailable,
|
||||
onEngineAvailable as EventListener
|
||||
)
|
||||
|
||||
// When the component is unmounted these should be assigned, but it's possible
|
||||
// the component mounts and unmounts before engine is available.
|
||||
engineCommandManager.engineConnection?.addEventListener(
|
||||
EngineConnectionEvents.PingPongChanged,
|
||||
onPingPongChange as EventListener
|
||||
)
|
||||
engineCommandManager.engineConnection?.addEventListener(
|
||||
EngineConnectionEvents.ConnectionStateChanged,
|
||||
onConnectionStateChange as EventListener
|
||||
)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return {
|
||||
@ -269,7 +192,6 @@ export function useNetworkStatus() {
|
||||
error,
|
||||
setHasCopied,
|
||||
hasCopied,
|
||||
pingPongHealth,
|
||||
}
|
||||
}
|
||||
|
||||
@ -334,18 +256,18 @@ export const NetworkHealthIndicator = () => {
|
||||
size="lg"
|
||||
icon={
|
||||
hasIssueToIcon[
|
||||
String(issues[name as ConnectingTypeGroup])
|
||||
issues[name as ConnectingTypeGroup].toString()
|
||||
]
|
||||
}
|
||||
iconClassName={
|
||||
hasIssueToIconColors[
|
||||
String(issues[name as ConnectingTypeGroup])
|
||||
issues[name as ConnectingTypeGroup].toString()
|
||||
].icon
|
||||
}
|
||||
bgClassName={
|
||||
'rounded-sm ' +
|
||||
hasIssueToIconColors[
|
||||
String(issues[name as ConnectingTypeGroup])
|
||||
issues[name as ConnectingTypeGroup].toString()
|
||||
].bg
|
||||
}
|
||||
/>
|
||||
|
@ -32,7 +32,6 @@ export const Stream = ({ className = '' }: { className?: string }) => {
|
||||
const { state } = useModelingContext()
|
||||
const { isExecuting } = useKclContext()
|
||||
const { overallState } = useNetworkStatus()
|
||||
|
||||
const isNetworkOkay = overallState === NetworkHealthState.Ok
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { PathToNode, Program, SourceRange } from 'lang/wasm'
|
||||
import { VITE_KC_API_WS_MODELING_URL } from 'env'
|
||||
import { VITE_KC_API_WS_MODELING_URL, VITE_KC_CONNECTION_TIMEOUT_MS } from 'env'
|
||||
import { Models } from '@kittycad/lib'
|
||||
import { exportSave } from 'lib/exportSave'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
@ -8,9 +8,6 @@ import { sceneInfra } from 'clientSideScene/sceneInfra'
|
||||
|
||||
let lastMessage = ''
|
||||
|
||||
// TODO(paultag): This ought to be tweakable.
|
||||
const pingIntervalMs = 10000
|
||||
|
||||
interface CommandInfo {
|
||||
commandType: CommandTypes
|
||||
range: SourceRange
|
||||
@ -40,6 +37,11 @@ export interface ArtifactMap {
|
||||
[key: string]: ResultCommand | PendingCommand | FailedCommand
|
||||
}
|
||||
|
||||
interface NewTrackArgs {
|
||||
conn: EngineConnection
|
||||
mediaStream: MediaStream
|
||||
}
|
||||
|
||||
// This looks funny, I know. This is needed because node and the browser
|
||||
// disagree as to the type. In a browser it's a number, but in node it's a
|
||||
// "Timeout".
|
||||
@ -156,28 +158,10 @@ export type EngineConnectionState =
|
||||
| State<EngineConnectionStateType.Disconnecting, DisconnectingValue>
|
||||
| State<EngineConnectionStateType.Disconnected, void>
|
||||
|
||||
export type PingPongState = 'OK' | 'BAD'
|
||||
|
||||
export enum EngineConnectionEvents {
|
||||
// Fires for each ping-pong success or failure.
|
||||
PingPongChanged = 'ping-pong-changed', // (state: PingPongState) => void
|
||||
|
||||
// For now, this is only used by the NetworkHealthIndicator.
|
||||
// We can eventually use it for more, but one step at a time.
|
||||
ConnectionStateChanged = 'connection-state-changed', // (state: EngineConnectionState) => void
|
||||
|
||||
// These are used for the EngineCommandManager and were created
|
||||
// before onConnectionStateChange existed.
|
||||
ConnectionStarted = 'connection-started', // (engineConnection: EngineConnection) => void
|
||||
Opened = 'opened', // (engineConnection: EngineConnection) => void
|
||||
Closed = 'closed', // (engineConnection: EngineConnection) => void
|
||||
NewTrack = 'new-track', // (track: NewTrackArgs) => void
|
||||
}
|
||||
|
||||
// EngineConnection encapsulates the connection(s) to the Engine
|
||||
// for the EngineCommandManager; namely, the underlying WebSocket
|
||||
// and WebRTC connections.
|
||||
class EngineConnection extends EventTarget {
|
||||
class EngineConnection {
|
||||
websocket?: WebSocket
|
||||
pc?: RTCPeerConnection
|
||||
unreliableDataChannel?: RTCDataChannel
|
||||
@ -211,12 +195,7 @@ class EngineConnection extends EventTarget {
|
||||
}
|
||||
}
|
||||
this._state = next
|
||||
|
||||
this.dispatchEvent(
|
||||
new CustomEvent(EngineConnectionEvents.ConnectionStateChanged, {
|
||||
detail: this._state,
|
||||
})
|
||||
)
|
||||
this.onConnectionStateChange(this._state)
|
||||
}
|
||||
|
||||
private failedConnTimeout: Timeout | null
|
||||
@ -224,39 +203,74 @@ class EngineConnection extends EventTarget {
|
||||
readonly url: string
|
||||
private readonly token?: string
|
||||
|
||||
// For now, this is only used by the NetworkHealthIndicator.
|
||||
// We can eventually use it for more, but one step at a time.
|
||||
private onConnectionStateChange: (state: EngineConnectionState) => void
|
||||
|
||||
// These are used for the EngineCommandManager and were created
|
||||
// before onConnectionStateChange existed.
|
||||
private onEngineConnectionOpen: (engineConnection: EngineConnection) => void
|
||||
private onConnectionStarted: (engineConnection: EngineConnection) => void
|
||||
private onClose: (engineConnection: EngineConnection) => void
|
||||
private onNewTrack: (track: NewTrackArgs) => void
|
||||
|
||||
// TODO: actual type is ClientMetrics
|
||||
private webrtcStatsCollector?: () => Promise<ClientMetrics>
|
||||
|
||||
private pingPongSpan: { ping?: Date; pong?: Date }
|
||||
|
||||
constructor({ url, token }: { url: string; token?: string }) {
|
||||
super()
|
||||
|
||||
constructor({
|
||||
url,
|
||||
token,
|
||||
onConnectionStateChange = () => {},
|
||||
onNewTrack = () => {},
|
||||
onEngineConnectionOpen = () => {},
|
||||
onConnectionStarted = () => {},
|
||||
onClose = () => {},
|
||||
}: {
|
||||
url: string
|
||||
token?: string
|
||||
onConnectionStateChange?: (state: EngineConnectionState) => void
|
||||
onEngineConnectionOpen?: (engineConnection: EngineConnection) => void
|
||||
onConnectionStarted?: (engineConnection: EngineConnection) => void
|
||||
onClose?: (engineConnection: EngineConnection) => void
|
||||
onNewTrack?: (track: NewTrackArgs) => void
|
||||
}) {
|
||||
this.url = url
|
||||
this.token = token
|
||||
this.failedConnTimeout = null
|
||||
this.onConnectionStateChange = onConnectionStateChange
|
||||
this.onEngineConnectionOpen = onEngineConnectionOpen
|
||||
this.onConnectionStarted = onConnectionStarted
|
||||
|
||||
this.pingPongSpan = { ping: undefined, pong: undefined }
|
||||
this.onClose = onClose
|
||||
this.onNewTrack = onNewTrack
|
||||
|
||||
// TODO(paultag): This ought to be tweakable.
|
||||
const pingIntervalMs = 10000
|
||||
|
||||
// Without an interval ping, our connection will timeout.
|
||||
setInterval(() => {
|
||||
let pingInterval = setInterval(() => {
|
||||
switch (this.state.type as EngineConnectionStateType) {
|
||||
case EngineConnectionStateType.ConnectionEstablished:
|
||||
this.send({ type: 'ping' })
|
||||
this.pingPongSpan.ping = new Date()
|
||||
break
|
||||
case EngineConnectionStateType.Disconnecting:
|
||||
case EngineConnectionStateType.Disconnected:
|
||||
// Reconnect if we have disconnected.
|
||||
if (!this.isConnecting()) this.connect()
|
||||
clearInterval(pingInterval)
|
||||
break
|
||||
default:
|
||||
if (this.isConnecting()) break
|
||||
// Means we never could do an initial connection. Reconnect everything.
|
||||
if (!this.pingPongSpan.ping) this.connect()
|
||||
break
|
||||
}
|
||||
}, pingIntervalMs)
|
||||
|
||||
const connectionTimeoutMs = VITE_KC_CONNECTION_TIMEOUT_MS
|
||||
let connectRetryInterval = setInterval(() => {
|
||||
if (this.state.type !== EngineConnectionStateType.Disconnected) return
|
||||
|
||||
// Only try reconnecting when completely disconnected.
|
||||
clearInterval(connectRetryInterval)
|
||||
console.log('Trying to reconnect')
|
||||
this.connect()
|
||||
}, connectionTimeoutMs)
|
||||
}
|
||||
|
||||
isConnecting() {
|
||||
@ -338,11 +352,7 @@ class EngineConnection extends EventTarget {
|
||||
// dance is it safest to connect the video tracks / stream
|
||||
case 'connected':
|
||||
// Let the browser attach to the video stream now
|
||||
this.dispatchEvent(
|
||||
new CustomEvent(EngineConnectionEvents.NewTrack, {
|
||||
detail: { conn: this, mediaStream: this.mediaStream! },
|
||||
})
|
||||
)
|
||||
this.onNewTrack({ conn: this, mediaStream: this.mediaStream! })
|
||||
break
|
||||
case 'failed':
|
||||
this.disconnectAll()
|
||||
@ -458,9 +468,7 @@ class EngineConnection extends EventTarget {
|
||||
// Everything is now connected.
|
||||
this.state = { type: EngineConnectionStateType.ConnectionEstablished }
|
||||
|
||||
this.dispatchEvent(
|
||||
new CustomEvent(EngineConnectionEvents.Opened, { detail: this })
|
||||
)
|
||||
this.onEngineConnectionOpen(this)
|
||||
})
|
||||
|
||||
this.unreliableDataChannel.addEventListener('close', (event) => {
|
||||
@ -502,10 +510,6 @@ class EngineConnection extends EventTarget {
|
||||
},
|
||||
}
|
||||
|
||||
// Send an initial ping
|
||||
this.send({ type: 'ping' })
|
||||
this.pingPongSpan.ping = new Date()
|
||||
|
||||
// This is required for when KCMA is running stand-alone / within Tauri.
|
||||
// Otherwise when run in a browser, the token is sent implicitly via
|
||||
// the Cookie header.
|
||||
@ -571,34 +575,12 @@ failed cmd type was ${artifactThatFailed?.commandType}`
|
||||
let resp = message.resp
|
||||
|
||||
// If there's no body to the response, we can bail here.
|
||||
// !resp.type is usually "pong" response for our "ping"
|
||||
if (!resp || !resp.type) {
|
||||
return
|
||||
}
|
||||
|
||||
switch (resp.type) {
|
||||
case 'pong':
|
||||
this.pingPongSpan.pong = new Date()
|
||||
if (this.pingPongSpan.ping && this.pingPongSpan.pong) {
|
||||
if (
|
||||
Math.abs(
|
||||
this.pingPongSpan.pong.valueOf() -
|
||||
this.pingPongSpan.ping.valueOf()
|
||||
) >= pingIntervalMs
|
||||
) {
|
||||
this.dispatchEvent(
|
||||
new CustomEvent(EngineConnectionEvents.PingPongChanged, {
|
||||
detail: 'BAD',
|
||||
})
|
||||
)
|
||||
} else {
|
||||
this.dispatchEvent(
|
||||
new CustomEvent(EngineConnectionEvents.PingPongChanged, {
|
||||
detail: 'OK',
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
break
|
||||
case 'ice_server_info':
|
||||
let ice_servers = resp.data?.ice_servers
|
||||
|
||||
@ -745,11 +727,27 @@ failed cmd type was ${artifactThatFailed?.commandType}`
|
||||
}
|
||||
})
|
||||
|
||||
this.dispatchEvent(
|
||||
new CustomEvent(EngineConnectionEvents.ConnectionStarted, {
|
||||
detail: this,
|
||||
})
|
||||
)
|
||||
const connectionTimeoutMs = VITE_KC_CONNECTION_TIMEOUT_MS
|
||||
if (this.failedConnTimeout) {
|
||||
clearTimeout(this.failedConnTimeout)
|
||||
this.failedConnTimeout = null
|
||||
}
|
||||
this.failedConnTimeout = setTimeout(() => {
|
||||
if (this.isReady()) {
|
||||
return
|
||||
}
|
||||
this.failedConnTimeout = null
|
||||
this.state = {
|
||||
type: EngineConnectionStateType.Disconnecting,
|
||||
value: {
|
||||
type: DisconnectingType.Timeout,
|
||||
},
|
||||
}
|
||||
this.disconnectAll()
|
||||
this.finalizeIfAllConnectionsClosed()
|
||||
}, connectionTimeoutMs)
|
||||
|
||||
this.onConnectionStarted(this)
|
||||
}
|
||||
unreliableSend(message: object | string) {
|
||||
// TODO(paultag): Add in logic to determine the connection state and
|
||||
@ -798,8 +796,6 @@ interface UnreliableSubscription<T extends UnreliableResponses['type']> {
|
||||
callback: (data: Extract<UnreliableResponses, { type: T }>) => void
|
||||
}
|
||||
|
||||
// TODO: Should eventually be replaced with native EventTarget event system,
|
||||
// as it manages events in a more familiar way to other developers.
|
||||
export interface Subscription<T extends ModelTypes> {
|
||||
event: T
|
||||
callback: (
|
||||
@ -827,11 +823,7 @@ export type CommandLog =
|
||||
data: null
|
||||
}
|
||||
|
||||
export enum EngineCommandManagerEvents {
|
||||
EngineAvailable = 'engine-available',
|
||||
}
|
||||
|
||||
export class EngineCommandManager extends EventTarget {
|
||||
export class EngineCommandManager {
|
||||
artifactMap: ArtifactMap = {}
|
||||
lastArtifactMap: ArtifactMap = {}
|
||||
sceneCommandArtifacts: ArtifactMap = {}
|
||||
@ -865,9 +857,10 @@ export class EngineCommandManager extends EventTarget {
|
||||
}
|
||||
} = {} as any
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
callbacksEngineStateConnection: ((state: EngineConnectionState) => void)[] =
|
||||
[]
|
||||
|
||||
constructor() {
|
||||
this.engineConnection = undefined
|
||||
;(async () => {
|
||||
// circular dependency needs one to be lazy loaded
|
||||
@ -908,17 +901,12 @@ export class EngineCommandManager extends EventTarget {
|
||||
this.engineConnection = new EngineConnection({
|
||||
url,
|
||||
token,
|
||||
})
|
||||
|
||||
this.dispatchEvent(
|
||||
new CustomEvent(EngineCommandManagerEvents.EngineAvailable, {
|
||||
detail: this.engineConnection,
|
||||
})
|
||||
)
|
||||
|
||||
this.engineConnection.addEventListener(
|
||||
EngineConnectionEvents.Opened,
|
||||
() => {
|
||||
onConnectionStateChange: (state: EngineConnectionState) => {
|
||||
for (let cb of this.callbacksEngineStateConnection) {
|
||||
cb(state)
|
||||
}
|
||||
},
|
||||
onEngineConnectionOpen: () => {
|
||||
// Make the axis gizmo.
|
||||
// We do this after the connection opened to avoid a race condition.
|
||||
// Connected opened is the last thing that happens when the stream
|
||||
@ -953,98 +941,78 @@ export class EngineCommandManager extends EventTarget {
|
||||
setIsStreamReady(true)
|
||||
executeCode(undefined, true)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
this.engineConnection.addEventListener(
|
||||
EngineConnectionEvents.Closed,
|
||||
() => {
|
||||
},
|
||||
onClose: () => {
|
||||
setIsStreamReady(false)
|
||||
}
|
||||
)
|
||||
},
|
||||
onConnectionStarted: (engineConnection) => {
|
||||
engineConnection?.pc?.addEventListener('datachannel', (event) => {
|
||||
let unreliableDataChannel = event.channel
|
||||
|
||||
this.engineConnection.addEventListener(
|
||||
EngineConnectionEvents.ConnectionStarted,
|
||||
(({ detail: engineConnection }: CustomEvent) => {
|
||||
engineConnection?.pc?.addEventListener(
|
||||
'datachannel',
|
||||
(event: RTCDataChannelEvent) => {
|
||||
let unreliableDataChannel = event.channel
|
||||
|
||||
unreliableDataChannel.addEventListener(
|
||||
'message',
|
||||
(event: MessageEvent) => {
|
||||
const result: UnreliableResponses = JSON.parse(event.data)
|
||||
Object.values(
|
||||
this.unreliableSubscriptions[result.type] || {}
|
||||
).forEach(
|
||||
// TODO: There is only one response that uses the unreliable channel atm,
|
||||
// highlight_set_entity, if there are more it's likely they will all have the same
|
||||
// sequence logic, but I'm not sure if we use a single global sequence or a sequence
|
||||
// per unreliable subscription.
|
||||
(callback) => {
|
||||
if (
|
||||
result?.data?.sequence &&
|
||||
result?.data.sequence > this.inSequence &&
|
||||
result.type === 'highlight_set_entity'
|
||||
) {
|
||||
this.inSequence = result.data.sequence
|
||||
callback(result)
|
||||
}
|
||||
}
|
||||
)
|
||||
unreliableDataChannel.addEventListener('message', (event) => {
|
||||
const result: UnreliableResponses = JSON.parse(event.data)
|
||||
Object.values(
|
||||
this.unreliableSubscriptions[result.type] || {}
|
||||
).forEach(
|
||||
// TODO: There is only one response that uses the unreliable channel atm,
|
||||
// highlight_set_entity, if there are more it's likely they will all have the same
|
||||
// sequence logic, but I'm not sure if we use a single global sequence or a sequence
|
||||
// per unreliable subscription.
|
||||
(callback) => {
|
||||
if (
|
||||
result?.data?.sequence &&
|
||||
result?.data.sequence > this.inSequence &&
|
||||
result.type === 'highlight_set_entity'
|
||||
) {
|
||||
this.inSequence = result.data.sequence
|
||||
callback(result)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
// When the EngineConnection starts a connection, we want to register
|
||||
// callbacks into the WebSocket/PeerConnection.
|
||||
engineConnection.websocket?.addEventListener(
|
||||
'message',
|
||||
(event: MessageEvent) => {
|
||||
if (event.data instanceof ArrayBuffer) {
|
||||
// If the data is an ArrayBuffer, it's the result of an export command,
|
||||
// because in all other cases we send JSON strings. But in the case of
|
||||
// export we send a binary blob.
|
||||
// Pass this to our export function.
|
||||
void exportSave(event.data)
|
||||
} else {
|
||||
const message: Models['WebSocketResponse_type'] = JSON.parse(
|
||||
event.data
|
||||
)
|
||||
if (
|
||||
message.success &&
|
||||
message.resp.type === 'modeling' &&
|
||||
message.request_id
|
||||
) {
|
||||
this.handleModelingCommand(message.resp, message.request_id)
|
||||
} else if (
|
||||
!message.success &&
|
||||
message.request_id &&
|
||||
this.artifactMap[message.request_id]
|
||||
) {
|
||||
this.handleFailedModelingCommand(message)
|
||||
}
|
||||
engineConnection.websocket?.addEventListener('message', (event) => {
|
||||
if (event.data instanceof ArrayBuffer) {
|
||||
// If the data is an ArrayBuffer, it's the result of an export command,
|
||||
// because in all other cases we send JSON strings. But in the case of
|
||||
// export we send a binary blob.
|
||||
// Pass this to our export function.
|
||||
void exportSave(event.data)
|
||||
} else {
|
||||
const message: Models['WebSocketResponse_type'] = JSON.parse(
|
||||
event.data
|
||||
)
|
||||
if (
|
||||
message.success &&
|
||||
message.resp.type === 'modeling' &&
|
||||
message.request_id
|
||||
) {
|
||||
this.handleModelingCommand(message.resp, message.request_id)
|
||||
} else if (
|
||||
!message.success &&
|
||||
message.request_id &&
|
||||
this.artifactMap[message.request_id]
|
||||
) {
|
||||
this.handleFailedModelingCommand(message)
|
||||
}
|
||||
}
|
||||
)
|
||||
}) as EventListener
|
||||
)
|
||||
})
|
||||
},
|
||||
onNewTrack: ({ mediaStream }) => {
|
||||
console.log('received track', mediaStream)
|
||||
|
||||
this.engineConnection.addEventListener(EngineConnectionEvents.NewTrack, (({
|
||||
detail: { mediaStream },
|
||||
}: CustomEvent) => {
|
||||
console.log('received track', mediaStream)
|
||||
mediaStream.getVideoTracks()[0].addEventListener('mute', () => {
|
||||
console.log('peer is not sending video to us')
|
||||
// this.engineConnection?.close()
|
||||
// this.engineConnection?.connect()
|
||||
})
|
||||
|
||||
mediaStream.getVideoTracks()[0].addEventListener('mute', () => {
|
||||
console.log('peer is not sending video to us')
|
||||
// this.engineConnection?.close()
|
||||
// this.engineConnection?.connect()
|
||||
})
|
||||
|
||||
setMediaStream(mediaStream)
|
||||
}) as EventListener)
|
||||
setMediaStream(mediaStream)
|
||||
},
|
||||
})
|
||||
|
||||
this.engineConnection?.connect()
|
||||
}
|
||||
@ -1234,6 +1202,9 @@ export class EngineCommandManager extends EventTarget {
|
||||
) {
|
||||
delete this.unreliableSubscriptions[event][id]
|
||||
}
|
||||
onConnectionStateChange(callback: (state: EngineConnectionState) => void) {
|
||||
this.callbacksEngineStateConnection.push(callback)
|
||||
}
|
||||
endSession() {
|
||||
// TODO: instead of sending a single command with `object_ids: Object.keys(this.artifactMap)`
|
||||
// we need to loop over them each individually because if the engine doesn't recognise a single
|
||||
|
@ -149,7 +149,7 @@ export const lineTo: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTagWithTo('default'),
|
||||
addTag: addTag(),
|
||||
}
|
||||
|
||||
export const line: SketchLineHelper = {
|
||||
@ -240,7 +240,7 @@ export const line: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTagWithTo('default'),
|
||||
addTag: addTag(),
|
||||
}
|
||||
|
||||
export const xLineTo: SketchLineHelper = {
|
||||
@ -288,7 +288,7 @@ export const xLineTo: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTagWithTo('default'),
|
||||
addTag: addTag(),
|
||||
}
|
||||
|
||||
export const yLineTo: SketchLineHelper = {
|
||||
@ -336,7 +336,7 @@ export const yLineTo: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTagWithTo('default'),
|
||||
addTag: addTag(),
|
||||
}
|
||||
|
||||
export const xLine: SketchLineHelper = {
|
||||
@ -386,7 +386,7 @@ export const xLine: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTagWithTo('length'),
|
||||
addTag: addTag(),
|
||||
}
|
||||
|
||||
export const yLine: SketchLineHelper = {
|
||||
@ -430,7 +430,7 @@ export const yLine: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTagWithTo('length'),
|
||||
addTag: addTag(),
|
||||
}
|
||||
|
||||
export const tangentialArcTo: SketchLineHelper = {
|
||||
@ -510,7 +510,7 @@ export const tangentialArcTo: SketchLineHelper = {
|
||||
}
|
||||
},
|
||||
// TODO copy-paste from angledLine
|
||||
addTag: addTagWithTo('angleLength'),
|
||||
addTag: addTag(),
|
||||
}
|
||||
export const angledLine: SketchLineHelper = {
|
||||
add: ({
|
||||
@ -576,7 +576,7 @@ export const angledLine: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTagWithTo('angleLength'),
|
||||
addTag: addTag(),
|
||||
}
|
||||
|
||||
export const angledLineOfXLength: SketchLineHelper = {
|
||||
@ -649,7 +649,7 @@ export const angledLineOfXLength: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTagWithTo('angleLength'),
|
||||
addTag: addTag(),
|
||||
}
|
||||
|
||||
export const angledLineOfYLength: SketchLineHelper = {
|
||||
@ -723,7 +723,7 @@ export const angledLineOfYLength: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTagWithTo('angleLength'),
|
||||
addTag: addTag(),
|
||||
}
|
||||
|
||||
export const angledLineToX: SketchLineHelper = {
|
||||
@ -792,7 +792,7 @@ export const angledLineToX: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTagWithTo('angleTo'),
|
||||
addTag: addTag(),
|
||||
}
|
||||
|
||||
export const angledLineToY: SketchLineHelper = {
|
||||
@ -862,7 +862,7 @@ export const angledLineToY: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTagWithTo('angleTo'),
|
||||
addTag: addTag(),
|
||||
}
|
||||
|
||||
export const angledLineThatIntersects: SketchLineHelper = {
|
||||
@ -951,7 +951,7 @@ export const angledLineThatIntersects: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTagWithTo('angleTo'), // TODO might be wrong
|
||||
addTag: addTag(), // TODO might be wrong
|
||||
}
|
||||
|
||||
export const updateStartProfileAtArgs: SketchLineHelper['updateArgs'] = ({
|
||||
@ -1174,29 +1174,31 @@ function isAngleLiteral(lineArugement: Value): boolean {
|
||||
|
||||
type addTagFn = (a: ModifyAstBase) => { modifiedAst: Program; tag: string }
|
||||
|
||||
function addTagWithTo(
|
||||
argType: 'angleLength' | 'angleTo' | 'default' | 'length'
|
||||
): addTagFn {
|
||||
function addTag(): addTagFn {
|
||||
return ({ node, pathToNode }) => {
|
||||
let tagName = findUniqueName(node, 'seg', 2)
|
||||
const _node = { ...node }
|
||||
const { node: callExpression } = getNodeFromPath<CallExpression>(
|
||||
const { node: primaryCallExp } = getNodeFromPath<CallExpression>(
|
||||
_node,
|
||||
pathToNode
|
||||
pathToNode,
|
||||
'CallExpression'
|
||||
)
|
||||
const tagArg = callExpression.arguments?.[2]
|
||||
if (tagArg) {
|
||||
// Tag is always 3rd expression now, using arg index feels brittle
|
||||
// but we can come up with a better way to identify tag later.
|
||||
const thirdArg = primaryCallExp.arguments?.[2]
|
||||
const tagLiteral =
|
||||
thirdArg || (createLiteral(findUniqueName(_node, 'seg', 2)) as Literal)
|
||||
const isTagExisting = !!thirdArg
|
||||
if (!isTagExisting) {
|
||||
primaryCallExp.arguments[2] = tagLiteral
|
||||
}
|
||||
if ('value' in tagLiteral) {
|
||||
// Now TypeScript knows tagLiteral has a value property
|
||||
return {
|
||||
modifiedAst: _node,
|
||||
tag: String(tagArg),
|
||||
tag: String(tagLiteral.value),
|
||||
}
|
||||
} else {
|
||||
callExpression.arguments[2] = createLiteral(tagName)
|
||||
|
||||
return {
|
||||
modifiedAst: _node,
|
||||
tag: tagName,
|
||||
}
|
||||
throw new Error('Unable to assign tag without value')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
23
src/wasm-lib/Cargo.lock
generated
23
src/wasm-lib/Cargo.lock
generated
@ -1471,6 +1471,7 @@ dependencies = [
|
||||
name = "grackle"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"image",
|
||||
"kcl-lib",
|
||||
"kittycad",
|
||||
"kittycad-execution-plan",
|
||||
@ -1482,6 +1483,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"twenty-twenty",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
@ -2007,7 +2009,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "kittycad-execution-plan"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#4dfeb5c9ce2cc3fb853dd14cf948a922f3724ef4"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#494225aaac06fab77c4822e7dc48738ecca35392"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"insta",
|
||||
@ -2027,7 +2029,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "kittycad-execution-plan-macros"
|
||||
version = "0.1.9"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#4dfeb5c9ce2cc3fb853dd14cf948a922f3724ef4"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#494225aaac06fab77c4822e7dc48738ecca35392"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -2037,7 +2039,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "kittycad-execution-plan-traits"
|
||||
version = "0.1.13"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#4dfeb5c9ce2cc3fb853dd14cf948a922f3724ef4"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#494225aaac06fab77c4822e7dc48738ecca35392"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"thiserror",
|
||||
@ -2046,8 +2048,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kittycad-modeling-cmds"
|
||||
version = "0.1.30"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#4dfeb5c9ce2cc3fb853dd14cf948a922f3724ef4"
|
||||
version = "0.1.32"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#494225aaac06fab77c4822e7dc48738ecca35392"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@ -2075,7 +2077,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "kittycad-modeling-cmds-macros"
|
||||
version = "0.1.2"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#4dfeb5c9ce2cc3fb853dd14cf948a922f3724ef4"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#494225aaac06fab77c4822e7dc48738ecca35392"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -2085,11 +2087,12 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "kittycad-modeling-session"
|
||||
version = "0.1.1"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#4dfeb5c9ce2cc3fb853dd14cf948a922f3724ef4"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#494225aaac06fab77c4822e7dc48738ecca35392"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"kittycad",
|
||||
"kittycad-modeling-cmds",
|
||||
"lsystem",
|
||||
"reqwest",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
@ -2187,6 +2190,12 @@ dependencies = [
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lsystem"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23c47210f2a9f5ae2073e7b847026e3233bcb012aa6845201c69c26481762a81"
|
||||
|
||||
[[package]]
|
||||
name = "matchit"
|
||||
version = "0.7.3"
|
||||
|
@ -6,6 +6,7 @@ description = "A new executor for KCL which compiles to Execution Plans"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
image = { version = "0.24.7", default-features = false, features = ["png"] }
|
||||
kcl-lib = { path = "../kcl" }
|
||||
kittycad = { workspace = true }
|
||||
kittycad-execution-plan = { workspace = true }
|
||||
@ -15,6 +16,7 @@ kittycad-modeling-cmds = { workspace = true }
|
||||
kittycad-modeling-session = { workspace = true }
|
||||
thiserror = "1.0.57"
|
||||
tokio = { version = "1.36.0", features = ["macros", "rt"] }
|
||||
twenty-twenty = "0.7.0"
|
||||
uuid = "1.7"
|
||||
|
||||
[dev-dependencies]
|
||||
|
BIN
src/wasm-lib/grackle/fixtures/cube_lineTo.png
Normal file
BIN
src/wasm-lib/grackle/fixtures/cube_lineTo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 80 KiB |
BIN
src/wasm-lib/grackle/fixtures/cube_xyLine.png
Normal file
BIN
src/wasm-lib/grackle/fixtures/cube_xyLine.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 81 KiB |
@ -113,6 +113,26 @@ impl BindingScope {
|
||||
"lineTo".into(),
|
||||
EpBinding::from(KclFunction::LineTo(native_functions::sketch::LineTo)),
|
||||
),
|
||||
(
|
||||
"line".into(),
|
||||
EpBinding::from(KclFunction::Line(native_functions::sketch::Line)),
|
||||
),
|
||||
(
|
||||
"xLineTo".into(),
|
||||
EpBinding::from(KclFunction::XLineTo(native_functions::sketch::XLineTo)),
|
||||
),
|
||||
(
|
||||
"xLine".into(),
|
||||
EpBinding::from(KclFunction::XLine(native_functions::sketch::XLine)),
|
||||
),
|
||||
(
|
||||
"yLineTo".into(),
|
||||
EpBinding::from(KclFunction::YLineTo(native_functions::sketch::YLineTo)),
|
||||
),
|
||||
(
|
||||
"yLine".into(),
|
||||
EpBinding::from(KclFunction::YLine(native_functions::sketch::YLine)),
|
||||
),
|
||||
(
|
||||
"extrude".into(),
|
||||
EpBinding::from(KclFunction::Extrude(native_functions::sketch::Extrude)),
|
||||
|
@ -76,7 +76,7 @@ impl From<ExecutionFailed> for Error {
|
||||
) -> Self {
|
||||
Self::Execution {
|
||||
error,
|
||||
instruction,
|
||||
instruction: instruction.expect("no instruction"),
|
||||
instruction_index,
|
||||
}
|
||||
}
|
||||
|
@ -262,6 +262,11 @@ impl Planner {
|
||||
KclFunction::StartSketchAt(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Extrude(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::LineTo(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Line(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::XLineTo(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::XLine(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::YLineTo(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::YLine(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Add(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Close(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::UserDefined(f) => {
|
||||
@ -631,6 +636,11 @@ enum KclFunction {
|
||||
Id(native_functions::Id),
|
||||
StartSketchAt(native_functions::sketch::StartSketchAt),
|
||||
LineTo(native_functions::sketch::LineTo),
|
||||
Line(native_functions::sketch::Line),
|
||||
XLineTo(native_functions::sketch::XLineTo),
|
||||
XLine(native_functions::sketch::XLine),
|
||||
YLineTo(native_functions::sketch::YLineTo),
|
||||
YLine(native_functions::sketch::YLine),
|
||||
Add(native_functions::Add),
|
||||
UserDefined(UserDefinedFunction),
|
||||
Extrude(native_functions::sketch::Extrude),
|
||||
|
@ -3,4 +3,4 @@
|
||||
pub mod helpers;
|
||||
pub mod stdlib_functions;
|
||||
|
||||
pub use stdlib_functions::{Close, Extrude, LineTo, StartSketchAt};
|
||||
pub use stdlib_functions::{Close, Extrude, Line, LineTo, StartSketchAt, XLine, XLineTo, YLine, YLineTo};
|
||||
|
@ -139,7 +139,7 @@ pub fn sequence_binding(
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract a 2D point from an argument to a Cabble.
|
||||
/// Extract a 2D point from an argument to a KCL Function.
|
||||
pub fn arg_point2d(
|
||||
arg: EpBinding,
|
||||
fn_name: &'static str,
|
||||
@ -148,7 +148,7 @@ pub fn arg_point2d(
|
||||
arg_number: usize,
|
||||
) -> Result<Address, CompileError> {
|
||||
let expected = "2D point (array with length 2)";
|
||||
let elements = sequence_binding(arg, "startSketchAt", "an array of length 2", arg_number)?;
|
||||
let elements = sequence_binding(arg, fn_name, "an array of length 2", arg_number)?;
|
||||
if elements.len() != 2 {
|
||||
return Err(CompileError::ArgWrongType {
|
||||
fn_name,
|
||||
@ -165,12 +165,12 @@ pub fn arg_point2d(
|
||||
let start_z = start + 2;
|
||||
instructions.extend([
|
||||
Instruction::Copy {
|
||||
source: single_binding(elements[0].clone(), "startSketchAt", "number", arg_number)?,
|
||||
source: single_binding(elements[0].clone(), fn_name, "number", arg_number)?,
|
||||
destination: Destination::Address(start_x),
|
||||
length: 1,
|
||||
},
|
||||
Instruction::Copy {
|
||||
source: single_binding(elements[1].clone(), "startSketchAt", "number", arg_number)?,
|
||||
source: single_binding(elements[1].clone(), fn_name, "number", arg_number)?,
|
||||
destination: Destination::Address(start_y),
|
||||
length: 1,
|
||||
},
|
||||
|
@ -1,7 +1,7 @@
|
||||
use kittycad_execution_plan::{
|
||||
api_request::ApiRequest,
|
||||
sketch_types::{self, Axes, BasePath, Plane, SketchGroup},
|
||||
Destination, Instruction,
|
||||
BinaryArithmetic, BinaryOperation, Destination, Instruction, Operand,
|
||||
};
|
||||
use kittycad_execution_plan_traits::{Address, InMemory, Primitive, Value};
|
||||
use kittycad_modeling_cmds::{
|
||||
@ -13,6 +13,22 @@ use uuid::Uuid;
|
||||
use super::helpers::{arg_point2d, no_arg_api_call, sg_binding, single_binding, stack_api_call};
|
||||
use crate::{binding_scope::EpBinding, error::CompileError, native_functions::Callable, EvalPlan};
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum At {
|
||||
RelativeXY,
|
||||
AbsoluteXY,
|
||||
RelativeX,
|
||||
AbsoluteX,
|
||||
RelativeY,
|
||||
AbsoluteY,
|
||||
}
|
||||
|
||||
impl At {
|
||||
pub fn is_relative(&self) -> bool {
|
||||
*self == At::RelativeX || *self == At::RelativeY || *self == At::RelativeXY
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
pub struct Close;
|
||||
@ -140,25 +156,124 @@ impl Callable for LineTo {
|
||||
&self,
|
||||
ctx: &mut crate::native_functions::Context<'_>,
|
||||
args: Vec<EpBinding>,
|
||||
) -> Result<EvalPlan, CompileError> {
|
||||
LineBare::call(ctx, "lineTo", args, LineBareOptions { at: At::AbsoluteXY })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
pub struct Line;
|
||||
|
||||
impl Callable for Line {
|
||||
fn call(
|
||||
&self,
|
||||
ctx: &mut crate::native_functions::Context<'_>,
|
||||
args: Vec<EpBinding>,
|
||||
) -> Result<EvalPlan, CompileError> {
|
||||
LineBare::call(ctx, "line", args, LineBareOptions { at: At::RelativeXY })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
pub struct XLineTo;
|
||||
|
||||
impl Callable for XLineTo {
|
||||
fn call(
|
||||
&self,
|
||||
ctx: &mut crate::native_functions::Context<'_>,
|
||||
args: Vec<EpBinding>,
|
||||
) -> Result<EvalPlan, CompileError> {
|
||||
LineBare::call(ctx, "xLineTo", args, LineBareOptions { at: At::AbsoluteX })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
pub struct XLine;
|
||||
|
||||
impl Callable for XLine {
|
||||
fn call(
|
||||
&self,
|
||||
ctx: &mut crate::native_functions::Context<'_>,
|
||||
args: Vec<EpBinding>,
|
||||
) -> Result<EvalPlan, CompileError> {
|
||||
LineBare::call(ctx, "xLine", args, LineBareOptions { at: At::RelativeX })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
pub struct YLineTo;
|
||||
|
||||
impl Callable for YLineTo {
|
||||
fn call(
|
||||
&self,
|
||||
ctx: &mut crate::native_functions::Context<'_>,
|
||||
args: Vec<EpBinding>,
|
||||
) -> Result<EvalPlan, CompileError> {
|
||||
LineBare::call(ctx, "yLineTo", args, LineBareOptions { at: At::AbsoluteY })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
pub struct YLine;
|
||||
|
||||
impl Callable for YLine {
|
||||
fn call(
|
||||
&self,
|
||||
ctx: &mut crate::native_functions::Context<'_>,
|
||||
args: Vec<EpBinding>,
|
||||
) -> Result<EvalPlan, CompileError> {
|
||||
LineBare::call(ctx, "yLine", args, LineBareOptions { at: At::RelativeY })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
/// Exposes all the possible arguments the `line` modeling command can take.
|
||||
/// Reduces code for the other line functions needed.
|
||||
/// We do not expose this to the developer since it does not align with
|
||||
/// the documentation (there is no "lineBare").
|
||||
pub struct LineBare;
|
||||
|
||||
/// Used to configure the call to handle different line variants.
|
||||
pub struct LineBareOptions {
|
||||
/// Where to start coordinates at, ex: At::RelativeXY.
|
||||
at: At,
|
||||
}
|
||||
|
||||
impl LineBare {
|
||||
fn call(
|
||||
ctx: &mut crate::native_functions::Context<'_>,
|
||||
fn_name: &'static str,
|
||||
args: Vec<EpBinding>,
|
||||
opts: LineBareOptions,
|
||||
) -> Result<EvalPlan, CompileError> {
|
||||
let mut instructions = Vec::new();
|
||||
let fn_name = "lineTo";
|
||||
// Get both required params.
|
||||
|
||||
let required = 2;
|
||||
|
||||
let mut args_iter = args.into_iter();
|
||||
|
||||
let Some(to) = args_iter.next() else {
|
||||
return Err(CompileError::NotEnoughArgs {
|
||||
fn_name: fn_name.into(),
|
||||
required: 2,
|
||||
actual: 0,
|
||||
required,
|
||||
actual: args_iter.count(),
|
||||
});
|
||||
};
|
||||
|
||||
let Some(sketch_group) = args_iter.next() else {
|
||||
return Err(CompileError::NotEnoughArgs {
|
||||
fn_name: fn_name.into(),
|
||||
required: 2,
|
||||
actual: 1,
|
||||
required,
|
||||
actual: args_iter.count(),
|
||||
});
|
||||
};
|
||||
|
||||
let tag = match args_iter.next() {
|
||||
Some(a) => a,
|
||||
None => {
|
||||
@ -171,26 +286,90 @@ impl Callable for LineTo {
|
||||
EpBinding::Single(empty_string_addr)
|
||||
}
|
||||
};
|
||||
|
||||
// Check the type of required params.
|
||||
let to = arg_point2d(to, fn_name, &mut instructions, ctx, 0)?;
|
||||
// We don't check `to` here because it can take on either a
|
||||
// EpBinding::Sequence or EpBinding::Single.
|
||||
|
||||
let sg = sg_binding(sketch_group, fn_name, "sketch group", 1)?;
|
||||
let tag = single_binding(tag, fn_name, "string tag", 2)?;
|
||||
let id = Uuid::new_v4();
|
||||
|
||||
// Start of the path segment (which is a straight line).
|
||||
let length_of_3d_point = Point3d::<f64>::default().into_parts().len();
|
||||
let start_of_line = ctx.next_address.offset_by(1);
|
||||
|
||||
// Reserve space for the line's end, and the `relative: bool` field.
|
||||
ctx.next_address.offset_by(length_of_3d_point + 1);
|
||||
let new_sg_index = ctx.assign_sketch_group();
|
||||
|
||||
// Copy based on the options.
|
||||
match opts {
|
||||
LineBareOptions { at: At::AbsoluteXY, .. } | LineBareOptions { at: At::RelativeXY, .. } => {
|
||||
// Push the `to` 2D point onto the stack.
|
||||
let EpBinding::Sequence { elements, length_at: _ } = to.clone() else {
|
||||
return Err(CompileError::InvalidOperand("Must pass a list of length 2"));
|
||||
};
|
||||
let &[EpBinding::Single(el0), EpBinding::Single(el1)] = elements.as_slice() else {
|
||||
return Err(CompileError::InvalidOperand("Must pass a sequence here."));
|
||||
};
|
||||
instructions.extend([
|
||||
Instruction::Copy {
|
||||
// X
|
||||
source: el0,
|
||||
length: 1,
|
||||
destination: Destination::StackPush,
|
||||
},
|
||||
Instruction::Copy {
|
||||
// Y
|
||||
source: el1,
|
||||
length: 1,
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
Instruction::StackExtend { data: vec![0.0.into()] }, // Z
|
||||
]);
|
||||
}
|
||||
LineBareOptions { at: At::AbsoluteX, .. } | LineBareOptions { at: At::RelativeX, .. } => {
|
||||
let EpBinding::Single(addr) = to else {
|
||||
return Err(CompileError::InvalidOperand("Must pass a single value here."));
|
||||
};
|
||||
instructions.extend([
|
||||
Instruction::Copy {
|
||||
// X
|
||||
source: addr,
|
||||
length: 1,
|
||||
destination: Destination::StackPush,
|
||||
},
|
||||
Instruction::StackExtend {
|
||||
data: vec![Primitive::from(0.0)],
|
||||
}, // Y
|
||||
Instruction::StackExtend {
|
||||
data: vec![Primitive::from(0.0)],
|
||||
}, // Z
|
||||
]);
|
||||
}
|
||||
LineBareOptions { at: At::AbsoluteY, .. } | LineBareOptions { at: At::RelativeY, .. } => {
|
||||
let EpBinding::Single(addr) = to else {
|
||||
return Err(CompileError::InvalidOperand("Must pass a single value here."));
|
||||
};
|
||||
instructions.extend([
|
||||
Instruction::StackPush {
|
||||
data: vec![Primitive::from(0.0)],
|
||||
}, // X
|
||||
Instruction::Copy {
|
||||
// Y
|
||||
source: addr,
|
||||
length: 1,
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
Instruction::StackExtend {
|
||||
data: vec![Primitive::from(0.0)],
|
||||
}, // Z
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
instructions.extend([
|
||||
// Push the `to` 2D point onto the stack.
|
||||
Instruction::Copy {
|
||||
source: to,
|
||||
length: 2,
|
||||
destination: Destination::StackPush,
|
||||
},
|
||||
// Make it a 3D point.
|
||||
Instruction::StackExtend { data: vec![0.0.into()] },
|
||||
// Append the new path segment to memory.
|
||||
// First comes its tag.
|
||||
Instruction::SetPrimitive {
|
||||
@ -204,7 +383,7 @@ impl Callable for LineTo {
|
||||
// Then its `relative` field.
|
||||
Instruction::SetPrimitive {
|
||||
address: start_of_line + 1 + length_of_3d_point,
|
||||
value: false.into(),
|
||||
value: opts.at.is_relative().into(),
|
||||
},
|
||||
// Push the path ID onto the stack.
|
||||
Instruction::SketchGroupCopyFrom {
|
||||
@ -231,16 +410,159 @@ impl Callable for LineTo {
|
||||
data: vec![Primitive::from("ToPoint".to_owned())],
|
||||
},
|
||||
// `BasePath::from` point.
|
||||
// Place them in the secondary stack to prepare ToPoint structure.
|
||||
Instruction::SketchGroupGetLastPoint {
|
||||
source: sg,
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
// `BasePath::to` point.
|
||||
Instruction::Copy {
|
||||
source: start_of_line + 1,
|
||||
length: 2,
|
||||
destination: Destination::StackExtend,
|
||||
]);
|
||||
|
||||
// Reserve space for the segment last point
|
||||
let to_point_from = ctx.next_address.offset_by(2);
|
||||
|
||||
instructions.extend([
|
||||
// Copy to the primary stack as well to be worked with.
|
||||
Instruction::SketchGroupGetLastPoint {
|
||||
source: sg,
|
||||
destination: Destination::Address(to_point_from),
|
||||
},
|
||||
]);
|
||||
|
||||
// `BasePath::to` point.
|
||||
|
||||
// The copy here depends on the incoming `to` data.
|
||||
// Sometimes it's a list, sometimes it's single datum.
|
||||
// And the relative/not relative matters. When relative, we need to
|
||||
// copy coords from `from` into the new `to` coord that don't change.
|
||||
// At least everything else can be built up from these "primitives".
|
||||
if let EpBinding::Sequence { elements, length_at: _ } = to.clone() {
|
||||
if let &[EpBinding::Single(el0), EpBinding::Single(el1)] = elements.as_slice() {
|
||||
match opts {
|
||||
// ToPoint { from: { x1, y1 }, to: { x1 + x2, y1 + y2 } }
|
||||
LineBareOptions { at: At::RelativeXY, .. } => {
|
||||
instructions.extend([
|
||||
Instruction::BinaryArithmetic {
|
||||
arithmetic: BinaryArithmetic {
|
||||
operation: BinaryOperation::Add,
|
||||
operand0: Operand::Reference(to_point_from + 0),
|
||||
operand1: Operand::Reference(el0),
|
||||
},
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
Instruction::BinaryArithmetic {
|
||||
arithmetic: BinaryArithmetic {
|
||||
operation: BinaryOperation::Add,
|
||||
operand0: Operand::Reference(to_point_from + 1),
|
||||
operand1: Operand::Reference(el1),
|
||||
},
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
]);
|
||||
}
|
||||
// ToPoint { from: { x1, y1 }, to: { x2, y2 } }
|
||||
LineBareOptions { at: At::AbsoluteXY, .. } => {
|
||||
// Otherwise just directly copy the new points.
|
||||
instructions.extend([
|
||||
Instruction::Copy {
|
||||
source: el0,
|
||||
length: 1,
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
Instruction::Copy {
|
||||
source: el1,
|
||||
length: 1,
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
]);
|
||||
}
|
||||
_ => {
|
||||
return Err(CompileError::InvalidOperand(
|
||||
"A Sequence with At::...X or At::...Y is not valid here. Must be At::...XY.",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let EpBinding::Single(addr) = to {
|
||||
match opts {
|
||||
// ToPoint { from: { x1, y1 }, to: { x1 + x2, y1 } }
|
||||
LineBareOptions { at: At::RelativeX } => {
|
||||
instructions.extend([
|
||||
Instruction::BinaryArithmetic {
|
||||
arithmetic: BinaryArithmetic {
|
||||
operation: BinaryOperation::Add,
|
||||
operand0: Operand::Reference(to_point_from + 0),
|
||||
operand1: Operand::Reference(addr),
|
||||
},
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
Instruction::Copy {
|
||||
source: to_point_from + 1,
|
||||
length: 1,
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
]);
|
||||
}
|
||||
// ToPoint { from: { x1, y1 }, to: { x2, y1 } }
|
||||
LineBareOptions { at: At::AbsoluteX } => {
|
||||
instructions.extend([
|
||||
Instruction::Copy {
|
||||
source: addr,
|
||||
length: 1,
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
Instruction::Copy {
|
||||
source: to_point_from + 1,
|
||||
length: 1,
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
]);
|
||||
}
|
||||
// ToPoint { from: { x1, y1 }, to: { x1, y1 + y2 } }
|
||||
LineBareOptions { at: At::RelativeY } => {
|
||||
instructions.extend([
|
||||
Instruction::Copy {
|
||||
source: to_point_from + 0,
|
||||
length: 1,
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
Instruction::BinaryArithmetic {
|
||||
arithmetic: BinaryArithmetic {
|
||||
operation: BinaryOperation::Add,
|
||||
operand0: Operand::Reference(to_point_from + 1),
|
||||
operand1: Operand::Reference(addr),
|
||||
},
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
]);
|
||||
}
|
||||
// ToPoint { from: { x1, y1 }, to: { x1, y2 } }
|
||||
LineBareOptions { at: At::AbsoluteY } => {
|
||||
instructions.extend([
|
||||
Instruction::Copy {
|
||||
source: to_point_from + 0,
|
||||
length: 1,
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
Instruction::Copy {
|
||||
source: addr,
|
||||
length: 1,
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
]);
|
||||
}
|
||||
_ => {
|
||||
return Err(CompileError::InvalidOperand(
|
||||
"A Single binding with At::...XY is not valid here.",
|
||||
));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(CompileError::InvalidOperand(
|
||||
"Must be a sequence or single value binding.",
|
||||
));
|
||||
}
|
||||
|
||||
instructions.extend([
|
||||
// `BasePath::name` string.
|
||||
Instruction::Copy {
|
||||
source: tag,
|
||||
|
@ -1048,14 +1048,10 @@ fn store_object_with_array_property() {
|
||||
|
||||
/// Write the program's plan to the KCVM debugger's normal input file.
|
||||
#[allow(unused)]
|
||||
fn kcvm_dbg(kcl_program: &str) {
|
||||
fn kcvm_dbg(kcl_program: &str, path: &str) {
|
||||
let (plan, _scope, _) = must_plan(kcl_program);
|
||||
let plan_json = serde_json::to_string_pretty(&plan).unwrap();
|
||||
std::fs::write(
|
||||
"/Users/adamchalmers/kc-repos/modeling-api/execution-plan-debugger/test_input.json",
|
||||
plan_json,
|
||||
)
|
||||
.unwrap();
|
||||
std::fs::write(path, plan_json).unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@ -1069,8 +1065,6 @@ async fn stdlib_cube_partial() {
|
||||
|> close(%)
|
||||
|> extrude(100.0, %)
|
||||
"#;
|
||||
let (_plan, _scope, last_address) = must_plan(program);
|
||||
assert_eq!(last_address, Address::ZERO + 66);
|
||||
let ast = kcl_lib::parser::Parser::new(kcl_lib::token::lexer(program))
|
||||
.ast()
|
||||
.unwrap();
|
||||
@ -1113,23 +1107,115 @@ async fn stdlib_cube_partial() {
|
||||
},
|
||||
]
|
||||
);
|
||||
// use kittycad_modeling_cmds::{each_cmd, ok_response::OkModelingCmdResponse, ImageFormat};
|
||||
// let out = client
|
||||
// .unwrap()
|
||||
// .run_command(
|
||||
// uuid::Uuid::new_v4().into(),
|
||||
// each_cmd::TakeSnapshot {
|
||||
// format: ImageFormat::Png,
|
||||
// },
|
||||
// )
|
||||
// .await
|
||||
// .unwrap();
|
||||
// let out = match out {
|
||||
// OkModelingCmdResponse::TakeSnapshot(b) => b,
|
||||
// other => panic!("wrong output: {other:?}"),
|
||||
// };
|
||||
// let out: Vec<u8> = out.contents.into();
|
||||
// std::fs::write("image.png", out).unwrap();
|
||||
use kittycad_modeling_cmds::{each_cmd, ok_response::OkModelingCmdResponse, ImageFormat};
|
||||
let out = client
|
||||
.unwrap()
|
||||
.run_command(
|
||||
uuid::Uuid::new_v4().into(),
|
||||
kittycad_modeling_cmds::ModelingCmd::from(each_cmd::TakeSnapshot {
|
||||
format: ImageFormat::Png,
|
||||
}),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let out = match out {
|
||||
OkModelingCmdResponse::TakeSnapshot(kittycad_modeling_cmds::output::TakeSnapshot { contents: b }) => b,
|
||||
other => panic!("wrong output: {other:?}"),
|
||||
};
|
||||
|
||||
use image::io::Reader as ImageReader;
|
||||
let img = ImageReader::new(std::io::Cursor::new(out))
|
||||
.with_guessed_format()
|
||||
.unwrap()
|
||||
.decode()
|
||||
.unwrap();
|
||||
twenty_twenty::assert_image("fixtures/cube_lineTo.png", &img, 0.9999);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn stdlib_cube_xline_yline() {
|
||||
let program = r#"
|
||||
let cube = startSketchAt([0.0, 0.0], "adam")
|
||||
|> xLine(210.0, %, "side0")
|
||||
|> yLine(210.0, %, "side1")
|
||||
|> xLine(-210.0, %, "side2")
|
||||
|> yLine(-210.0, %, "side3")
|
||||
|> close(%)
|
||||
|> extrude(100.0, %)
|
||||
"#;
|
||||
kcvm_dbg(
|
||||
program,
|
||||
"/home/lee/Code/Zoo/modeling-api/execution-plan-debugger/cube_xyline.json",
|
||||
);
|
||||
let (_plan, _scope, _last_address) = must_plan(program);
|
||||
|
||||
let ast = kcl_lib::parser::Parser::new(kcl_lib::token::lexer(program))
|
||||
.ast()
|
||||
.unwrap();
|
||||
let mut client = Some(test_client().await);
|
||||
let mem = match crate::execute(ast, &mut client).await {
|
||||
Ok(mem) => mem,
|
||||
Err(e) => panic!("{e}"),
|
||||
};
|
||||
let sg = &mem.sketch_groups.last().unwrap();
|
||||
assert_eq!(
|
||||
sg.path_rest,
|
||||
vec![
|
||||
sketch_types::PathSegment::ToPoint {
|
||||
base: sketch_types::BasePath {
|
||||
from: Point2d { x: 0.0, y: 0.0 },
|
||||
to: Point2d { x: 210.0, y: 0.0 },
|
||||
name: "side0".into(),
|
||||
}
|
||||
},
|
||||
sketch_types::PathSegment::ToPoint {
|
||||
base: sketch_types::BasePath {
|
||||
from: Point2d { x: 210.0, y: 0.0 },
|
||||
to: Point2d { x: 210.0, y: 210.0 },
|
||||
name: "side1".into(),
|
||||
}
|
||||
},
|
||||
sketch_types::PathSegment::ToPoint {
|
||||
base: sketch_types::BasePath {
|
||||
from: Point2d { x: 210.0, y: 210.0 },
|
||||
to: Point2d { x: 0.0, y: 210.0 },
|
||||
name: "side2".into(),
|
||||
}
|
||||
},
|
||||
sketch_types::PathSegment::ToPoint {
|
||||
base: sketch_types::BasePath {
|
||||
from: Point2d { x: 0.0, y: 210.0 },
|
||||
to: Point2d { x: 0.0, y: 0.0 },
|
||||
name: "side3".into(),
|
||||
}
|
||||
},
|
||||
]
|
||||
);
|
||||
use kittycad_modeling_cmds::{each_cmd, ok_response::OkModelingCmdResponse, ImageFormat};
|
||||
let out = client
|
||||
.unwrap()
|
||||
.run_command(
|
||||
uuid::Uuid::new_v4().into(),
|
||||
kittycad_modeling_cmds::ModelingCmd::from(each_cmd::TakeSnapshot {
|
||||
format: ImageFormat::Png,
|
||||
}),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let out = match out {
|
||||
OkModelingCmdResponse::TakeSnapshot(kittycad_modeling_cmds::output::TakeSnapshot { contents: b }) => b,
|
||||
other => panic!("wrong output: {other:?}"),
|
||||
};
|
||||
|
||||
use image::io::Reader as ImageReader;
|
||||
let img = ImageReader::new(std::io::Cursor::new(out))
|
||||
.with_guessed_format()
|
||||
.unwrap()
|
||||
.decode()
|
||||
.unwrap();
|
||||
twenty_twenty::assert_image("fixtures/cube_xyLine.png", &img, 0.9999);
|
||||
}
|
||||
|
||||
async fn test_client() -> Session {
|
||||
|
218
src/wasm-lib/kcl/fuzz/Cargo.lock
generated
218
src/wasm-lib/kcl/fuzz/Cargo.lock
generated
@ -7,6 +7,10 @@ name = "Inflector"
|
||||
version = "0.11.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
@ -45,10 +49,25 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.80"
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
]
|
||||
@ -92,7 +111,7 @@ checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -103,7 +122,7 @@ checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -268,12 +287,17 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.29"
|
||||
version = "0.4.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d87d9d13be47a5b7c3907137f1290b0459a7f80efb26be8c52afb11963bccb02"
|
||||
checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
"windows-targets 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -320,6 +344,21 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
@ -368,7 +407,7 @@ checksum = "377af281d8f23663862a7c84623bc5dcf7f8c44b13c7496a590bdc157f941a43"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
@ -380,10 +419,11 @@ checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946"
|
||||
|
||||
[[package]]
|
||||
name = "derive-docs"
|
||||
version = "0.1.6"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "834580a8bd697658876ed8c9f7727e49f01d34f5b859ca921ac5b99ffc6adf77"
|
||||
checksum = "b4e18a04fe569a325dd50743821f2605057ff5c4b48e60512270b4406907825b"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"convert_case",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
@ -391,7 +431,7 @@ dependencies = [
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_tokenstream",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -521,7 +561,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -592,7 +632,7 @@ dependencies = [
|
||||
"inflections",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -739,6 +779,29 @@ dependencies = [
|
||||
"tokio-rustls 0.24.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.4.0"
|
||||
@ -807,22 +870,23 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.68"
|
||||
version = "0.3.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee"
|
||||
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kcl-lib"
|
||||
version = "0.1.42"
|
||||
version = "0.1.46"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"approx",
|
||||
"async-recursion",
|
||||
"async-trait",
|
||||
"bson",
|
||||
"chrono",
|
||||
"dashmap",
|
||||
"databake",
|
||||
"derive-docs",
|
||||
@ -833,12 +897,14 @@ dependencies = [
|
||||
"kittycad-execution-plan-macros",
|
||||
"kittycad-execution-plan-traits",
|
||||
"lazy_static",
|
||||
"mime_guess",
|
||||
"parse-display 0.9.0",
|
||||
"reqwest",
|
||||
"ropey",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-tungstenite",
|
||||
@ -849,6 +915,7 @@ dependencies = [
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"winnow",
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -861,9 +928,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kittycad"
|
||||
version = "0.2.54"
|
||||
version = "0.2.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13958174d876353f429ea8230dc92fe86f164819cea2e51bbf22e01a4c2a496e"
|
||||
checksum = "f8aa5906d0730bd90f6b3331fe57c04951d00743169a29ee96408767b4060605"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -877,6 +944,7 @@ dependencies = [
|
||||
"http 0.2.9",
|
||||
"itertools",
|
||||
"log",
|
||||
"mime_guess",
|
||||
"parse-display 0.8.2",
|
||||
"phonenumber",
|
||||
"rand",
|
||||
@ -899,14 +967,13 @@ source = "git+https://github.com/KittyCAD/modeling-api?branch=main#1e6ef9601686c
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kittycad-execution-plan-traits"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3ec8efd57b59697eb140b63c0ffe7db44fdfe5a55f14e45513411eba2280ba5"
|
||||
version = "0.1.13"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#494225aaac06fab77c4822e7dc48738ecca35392"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"thiserror",
|
||||
@ -1028,9 +1095,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.10"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
|
||||
checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi",
|
||||
@ -1171,7 +1238,7 @@ dependencies = [
|
||||
"regex",
|
||||
"regex-syntax 0.7.5",
|
||||
"structmeta 0.2.0",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1185,7 +1252,7 @@ dependencies = [
|
||||
"regex",
|
||||
"regex-syntax 0.8.2",
|
||||
"structmeta 0.3.0",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1232,7 +1299,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1404,9 +1471,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.11.24"
|
||||
version = "0.11.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251"
|
||||
checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
|
||||
dependencies = [
|
||||
"base64 0.21.3",
|
||||
"bytes",
|
||||
@ -1692,7 +1759,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1726,7 +1793,7 @@ checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1738,7 +1805,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1776,6 +1843,17 @@ dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.1"
|
||||
@ -1847,7 +1925,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"structmeta-derive 0.2.0",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1859,7 +1937,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"structmeta-derive 0.3.0",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1870,7 +1948,7 @@ checksum = "a60bcaff7397072dca0017d1db428e30d5002e00b6847703e2e42005c95fbe00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1881,7 +1959,7 @@ checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1925,9 +2003,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.50"
|
||||
version = "2.0.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb"
|
||||
checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1948,7 +2026,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2004,7 +2082,7 @@ checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2077,7 +2155,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2183,7 +2261,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2212,7 +2290,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2250,7 +2328,7 @@ dependencies = [
|
||||
"Inflector",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
@ -2382,9 +2460,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.91"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f"
|
||||
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
@ -2392,24 +2470,24 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.91"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b"
|
||||
checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.41"
|
||||
version = "0.4.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97"
|
||||
checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
@ -2419,9 +2497,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.91"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed"
|
||||
checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
@ -2429,22 +2507,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.91"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
|
||||
checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.50",
|
||||
"syn 2.0.53",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.91"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838"
|
||||
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-streams"
|
||||
@ -2461,9 +2539,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.68"
|
||||
version = "0.3.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446"
|
||||
checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
@ -2506,6 +2584,15 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
@ -2680,3 +2767,14 @@ name = "zeroize"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"crc32fast",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
Reference in New Issue
Block a user