Compare commits
1 Commits
batch-take
...
achalmers/
Author | SHA1 | Date | |
---|---|---|---|
e1f1051fe0 |
@ -1,3 +1,3 @@
|
||||
[codespell]
|
||||
ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo,absolutey
|
||||
ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo
|
||||
skip: **/target,node_modules,build,**/Cargo.lock
|
||||
|
50
.github/workflows/cargo-build.yml
vendored
Normal file
50
.github/workflows/cargo-build.yml
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
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,6 +9,12 @@ 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
|
||||
|
36
.github/workflows/check-exampleKcl.yml
vendored
36
.github/workflows/check-exampleKcl.yml
vendored
@ -1,36 +0,0 @@
|
||||
name: Check Onboarding KCL
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
paths:
|
||||
- 'src/lib/exampleKcl.ts'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
comment:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Comment on PR
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
const message = '`src/lib/exampleKcl.ts` has been updated in this PR, please review and update the `src/routes/onboarding`, if needed.';
|
||||
const issue_number = context.payload.pull_request.number;
|
||||
const owner = context.repo.owner;
|
||||
const repo = context.repo.repo;
|
||||
|
||||
// Post a comment on the PR
|
||||
await github.rest.issues.createComment({
|
||||
owner,
|
||||
repo,
|
||||
issue_number,
|
||||
body: message,
|
||||
});
|
Binary file not shown.
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "untitled-app",
|
||||
"version": "0.16.0",
|
||||
"version": "0.15.6",
|
||||
"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#6db4320e98a4278d605dd05d4d87e1433939a7cd"
|
||||
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#d95a1b382f512a0be748e7a89e0f8fc4278010e2"
|
||||
dependencies = [
|
||||
"log",
|
||||
"serde",
|
||||
|
@ -7,7 +7,7 @@
|
||||
},
|
||||
"package": {
|
||||
"productName": "zoo-modeling-app",
|
||||
"version": "0.16.0"
|
||||
"version": "0.15.6"
|
||||
},
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
|
@ -59,7 +59,6 @@ const router = createBrowserRouter([
|
||||
{
|
||||
loader: fileLoader,
|
||||
id: paths.FILE,
|
||||
path: paths.FILE + '/:id',
|
||||
element: (
|
||||
<Auth>
|
||||
<FileMachineProvider>
|
||||
@ -75,11 +74,8 @@ 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.Ok]
|
||||
NETWORK_HEALTH_TEXT[NetworkHealthState.Issue]
|
||||
)
|
||||
})
|
||||
|
||||
|
@ -6,7 +6,8 @@ import {
|
||||
ConnectingTypeGroup,
|
||||
DisconnectingType,
|
||||
engineCommandManager,
|
||||
EngineConnectionState,
|
||||
EngineCommandManagerEvents,
|
||||
EngineConnectionEvents,
|
||||
EngineConnectionStateType,
|
||||
ErrorType,
|
||||
initialConnectingTypeGroupState,
|
||||
@ -81,37 +82,35 @@ const overallConnectionStateIcon: Record<
|
||||
}
|
||||
|
||||
export function useNetworkStatus() {
|
||||
const [steps, setSteps] = useState(initialConnectingTypeGroupState)
|
||||
const [steps, setSteps] = useState(
|
||||
structuredClone(initialConnectingTypeGroupState)
|
||||
)
|
||||
const [internetConnected, setInternetConnected] = useState<boolean>(true)
|
||||
const [overallState, setOverallState] = useState<NetworkHealthState>(
|
||||
NetworkHealthState.Ok
|
||||
NetworkHealthState.Disconnected
|
||||
)
|
||||
const [pingPongHealth, setPingPongHealth] = useState<'OK' | 'BAD'>('BAD')
|
||||
const [hasCopied, setHasCopied] = useState<boolean>(false)
|
||||
|
||||
const [error, setError] = useState<ErrorType | undefined>(undefined)
|
||||
|
||||
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 hasIssue = (i: [ConnectingType, boolean | undefined]) =>
|
||||
i[1] === undefined ? i[1] : !i[1]
|
||||
|
||||
const hasIssues: boolean =
|
||||
issues[ConnectingTypeGroup.WebSocket] ||
|
||||
issues[ConnectingTypeGroup.ICE] ||
|
||||
issues[ConnectingTypeGroup.WebRTC]
|
||||
const [issues, setIssues] = useState<
|
||||
Record<ConnectingTypeGroup, boolean | undefined>
|
||||
>({
|
||||
[ConnectingTypeGroup.WebSocket]: undefined,
|
||||
[ConnectingTypeGroup.ICE]: undefined,
|
||||
[ConnectingTypeGroup.WebRTC]: undefined,
|
||||
})
|
||||
|
||||
const [hasIssues, setHasIssues] = useState<boolean | undefined>(undefined)
|
||||
useEffect(() => {
|
||||
setOverallState(
|
||||
!internetConnected
|
||||
? NetworkHealthState.Disconnected
|
||||
: hasIssues
|
||||
: hasIssues || hasIssues === undefined
|
||||
? NetworkHealthState.Issue
|
||||
: NetworkHealthState.Ok
|
||||
)
|
||||
@ -134,19 +133,59 @@ export function useNetworkStatus() {
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
engineCommandManager.onConnectionStateChange(
|
||||
(engineConnectionState: EngineConnectionState) => {
|
||||
let hasSetAStep = false
|
||||
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)
|
||||
|
||||
if (
|
||||
engineConnectionState.type === EngineConnectionStateType.Connecting
|
||||
) {
|
||||
const groups = Object.values(steps)
|
||||
const groups = Object.values(nextSteps)
|
||||
for (let group of groups) {
|
||||
for (let step of group) {
|
||||
if (step[0] !== engineConnectionState.value.type) continue
|
||||
step[1] = true
|
||||
hasSetAStep = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -154,7 +193,7 @@ export function useNetworkStatus() {
|
||||
if (
|
||||
engineConnectionState.type === EngineConnectionStateType.Disconnecting
|
||||
) {
|
||||
const groups = Object.values(steps)
|
||||
const groups = Object.values(nextSteps)
|
||||
for (let group of groups) {
|
||||
for (let step of group) {
|
||||
if (
|
||||
@ -165,7 +204,6 @@ export function useNetworkStatus() {
|
||||
?.type === step[0]
|
||||
) {
|
||||
step[1] = false
|
||||
hasSetAStep = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -176,11 +214,50 @@ export function useNetworkStatus() {
|
||||
}
|
||||
}
|
||||
|
||||
if (hasSetAStep) {
|
||||
setSteps(steps)
|
||||
// Reset the state of all steps if we have disconnected.
|
||||
if (
|
||||
engineConnectionState.type === EngineConnectionStateType.Disconnected
|
||||
) {
|
||||
return structuredClone(initialConnectingTypeGroupState)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
@ -192,6 +269,7 @@ export function useNetworkStatus() {
|
||||
error,
|
||||
setHasCopied,
|
||||
hasCopied,
|
||||
pingPongHealth,
|
||||
}
|
||||
}
|
||||
|
||||
@ -256,18 +334,18 @@ export const NetworkHealthIndicator = () => {
|
||||
size="lg"
|
||||
icon={
|
||||
hasIssueToIcon[
|
||||
issues[name as ConnectingTypeGroup].toString()
|
||||
String(issues[name as ConnectingTypeGroup])
|
||||
]
|
||||
}
|
||||
iconClassName={
|
||||
hasIssueToIconColors[
|
||||
issues[name as ConnectingTypeGroup].toString()
|
||||
String(issues[name as ConnectingTypeGroup])
|
||||
].icon
|
||||
}
|
||||
bgClassName={
|
||||
'rounded-sm ' +
|
||||
hasIssueToIconColors[
|
||||
issues[name as ConnectingTypeGroup].toString()
|
||||
String(issues[name as ConnectingTypeGroup])
|
||||
].bg
|
||||
}
|
||||
/>
|
||||
|
@ -32,6 +32,7 @@ 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, VITE_KC_CONNECTION_TIMEOUT_MS } from 'env'
|
||||
import { VITE_KC_API_WS_MODELING_URL } from 'env'
|
||||
import { Models } from '@kittycad/lib'
|
||||
import { exportSave } from 'lib/exportSave'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
@ -8,6 +8,9 @@ import { sceneInfra } from 'clientSideScene/sceneInfra'
|
||||
|
||||
let lastMessage = ''
|
||||
|
||||
// TODO(paultag): This ought to be tweakable.
|
||||
const pingIntervalMs = 10000
|
||||
|
||||
interface CommandInfo {
|
||||
commandType: CommandTypes
|
||||
range: SourceRange
|
||||
@ -37,11 +40,6 @@ 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".
|
||||
@ -158,10 +156,28 @@ 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 {
|
||||
class EngineConnection extends EventTarget {
|
||||
websocket?: WebSocket
|
||||
pc?: RTCPeerConnection
|
||||
unreliableDataChannel?: RTCDataChannel
|
||||
@ -195,7 +211,12 @@ class EngineConnection {
|
||||
}
|
||||
}
|
||||
this._state = next
|
||||
this.onConnectionStateChange(this._state)
|
||||
|
||||
this.dispatchEvent(
|
||||
new CustomEvent(EngineConnectionEvents.ConnectionStateChanged, {
|
||||
detail: this._state,
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
private failedConnTimeout: Timeout | null
|
||||
@ -203,74 +224,39 @@ class EngineConnection {
|
||||
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>
|
||||
|
||||
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
|
||||
}) {
|
||||
private pingPongSpan: { ping?: Date; pong?: Date }
|
||||
|
||||
constructor({ url, token }: { url: string; token?: string }) {
|
||||
super()
|
||||
|
||||
this.url = url
|
||||
this.token = token
|
||||
this.failedConnTimeout = null
|
||||
this.onConnectionStateChange = onConnectionStateChange
|
||||
this.onEngineConnectionOpen = onEngineConnectionOpen
|
||||
this.onConnectionStarted = onConnectionStarted
|
||||
|
||||
this.onClose = onClose
|
||||
this.onNewTrack = onNewTrack
|
||||
|
||||
// TODO(paultag): This ought to be tweakable.
|
||||
const pingIntervalMs = 10000
|
||||
this.pingPongSpan = { ping: undefined, pong: undefined }
|
||||
|
||||
// Without an interval ping, our connection will timeout.
|
||||
let pingInterval = setInterval(() => {
|
||||
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:
|
||||
clearInterval(pingInterval)
|
||||
// Reconnect if we have disconnected.
|
||||
if (!this.isConnecting()) this.connect()
|
||||
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() {
|
||||
@ -352,7 +338,11 @@ class EngineConnection {
|
||||
// dance is it safest to connect the video tracks / stream
|
||||
case 'connected':
|
||||
// Let the browser attach to the video stream now
|
||||
this.onNewTrack({ conn: this, mediaStream: this.mediaStream! })
|
||||
this.dispatchEvent(
|
||||
new CustomEvent(EngineConnectionEvents.NewTrack, {
|
||||
detail: { conn: this, mediaStream: this.mediaStream! },
|
||||
})
|
||||
)
|
||||
break
|
||||
case 'failed':
|
||||
this.disconnectAll()
|
||||
@ -468,7 +458,9 @@ class EngineConnection {
|
||||
// Everything is now connected.
|
||||
this.state = { type: EngineConnectionStateType.ConnectionEstablished }
|
||||
|
||||
this.onEngineConnectionOpen(this)
|
||||
this.dispatchEvent(
|
||||
new CustomEvent(EngineConnectionEvents.Opened, { detail: this })
|
||||
)
|
||||
})
|
||||
|
||||
this.unreliableDataChannel.addEventListener('close', (event) => {
|
||||
@ -510,6 +502,10 @@ class EngineConnection {
|
||||
},
|
||||
}
|
||||
|
||||
// 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.
|
||||
@ -575,12 +571,34 @@ 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
|
||||
|
||||
@ -727,27 +745,11 @@ failed cmd type was ${artifactThatFailed?.commandType}`
|
||||
}
|
||||
})
|
||||
|
||||
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)
|
||||
this.dispatchEvent(
|
||||
new CustomEvent(EngineConnectionEvents.ConnectionStarted, {
|
||||
detail: this,
|
||||
})
|
||||
)
|
||||
}
|
||||
unreliableSend(message: object | string) {
|
||||
// TODO(paultag): Add in logic to determine the connection state and
|
||||
@ -796,6 +798,8 @@ 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: (
|
||||
@ -823,7 +827,11 @@ export type CommandLog =
|
||||
data: null
|
||||
}
|
||||
|
||||
export class EngineCommandManager {
|
||||
export enum EngineCommandManagerEvents {
|
||||
EngineAvailable = 'engine-available',
|
||||
}
|
||||
|
||||
export class EngineCommandManager extends EventTarget {
|
||||
artifactMap: ArtifactMap = {}
|
||||
lastArtifactMap: ArtifactMap = {}
|
||||
sceneCommandArtifacts: ArtifactMap = {}
|
||||
@ -857,10 +865,9 @@ export class EngineCommandManager {
|
||||
}
|
||||
} = {} as any
|
||||
|
||||
callbacksEngineStateConnection: ((state: EngineConnectionState) => void)[] =
|
||||
[]
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
|
||||
this.engineConnection = undefined
|
||||
;(async () => {
|
||||
// circular dependency needs one to be lazy loaded
|
||||
@ -901,12 +908,17 @@ export class EngineCommandManager {
|
||||
this.engineConnection = new EngineConnection({
|
||||
url,
|
||||
token,
|
||||
onConnectionStateChange: (state: EngineConnectionState) => {
|
||||
for (let cb of this.callbacksEngineStateConnection) {
|
||||
cb(state)
|
||||
}
|
||||
},
|
||||
onEngineConnectionOpen: () => {
|
||||
})
|
||||
|
||||
this.dispatchEvent(
|
||||
new CustomEvent(EngineCommandManagerEvents.EngineAvailable, {
|
||||
detail: this.engineConnection,
|
||||
})
|
||||
)
|
||||
|
||||
this.engineConnection.addEventListener(
|
||||
EngineConnectionEvents.Opened,
|
||||
() => {
|
||||
// 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
|
||||
@ -941,78 +953,98 @@ export class EngineCommandManager {
|
||||
setIsStreamReady(true)
|
||||
executeCode(undefined, true)
|
||||
})
|
||||
},
|
||||
onClose: () => {
|
||||
setIsStreamReady(false)
|
||||
},
|
||||
onConnectionStarted: (engineConnection) => {
|
||||
engineConnection?.pc?.addEventListener('datachannel', (event) => {
|
||||
let unreliableDataChannel = event.channel
|
||||
}
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
this.engineConnection.addEventListener(
|
||||
EngineConnectionEvents.Closed,
|
||||
() => {
|
||||
setIsStreamReady(false)
|
||||
}
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
// When the EngineConnection starts a connection, we want to register
|
||||
// callbacks into the WebSocket/PeerConnection.
|
||||
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)
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
onNewTrack: ({ mediaStream }) => {
|
||||
console.log('received track', mediaStream)
|
||||
)
|
||||
}) as EventListener
|
||||
)
|
||||
|
||||
mediaStream.getVideoTracks()[0].addEventListener('mute', () => {
|
||||
console.log('peer is not sending video to us')
|
||||
// this.engineConnection?.close()
|
||||
// this.engineConnection?.connect()
|
||||
})
|
||||
this.engineConnection.addEventListener(EngineConnectionEvents.NewTrack, (({
|
||||
detail: { mediaStream },
|
||||
}: CustomEvent) => {
|
||||
console.log('received track', mediaStream)
|
||||
|
||||
setMediaStream(mediaStream)
|
||||
},
|
||||
})
|
||||
mediaStream.getVideoTracks()[0].addEventListener('mute', () => {
|
||||
console.log('peer is not sending video to us')
|
||||
// this.engineConnection?.close()
|
||||
// this.engineConnection?.connect()
|
||||
})
|
||||
|
||||
setMediaStream(mediaStream)
|
||||
}) as EventListener)
|
||||
|
||||
this.engineConnection?.connect()
|
||||
}
|
||||
@ -1202,9 +1234,6 @@ export class EngineCommandManager {
|
||||
) {
|
||||
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: addTag(),
|
||||
addTag: addTagWithTo('default'),
|
||||
}
|
||||
|
||||
export const line: SketchLineHelper = {
|
||||
@ -240,7 +240,7 @@ export const line: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTag(),
|
||||
addTag: addTagWithTo('default'),
|
||||
}
|
||||
|
||||
export const xLineTo: SketchLineHelper = {
|
||||
@ -288,7 +288,7 @@ export const xLineTo: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTag(),
|
||||
addTag: addTagWithTo('default'),
|
||||
}
|
||||
|
||||
export const yLineTo: SketchLineHelper = {
|
||||
@ -336,7 +336,7 @@ export const yLineTo: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTag(),
|
||||
addTag: addTagWithTo('default'),
|
||||
}
|
||||
|
||||
export const xLine: SketchLineHelper = {
|
||||
@ -386,7 +386,7 @@ export const xLine: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTag(),
|
||||
addTag: addTagWithTo('length'),
|
||||
}
|
||||
|
||||
export const yLine: SketchLineHelper = {
|
||||
@ -430,7 +430,7 @@ export const yLine: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTag(),
|
||||
addTag: addTagWithTo('length'),
|
||||
}
|
||||
|
||||
export const tangentialArcTo: SketchLineHelper = {
|
||||
@ -510,7 +510,7 @@ export const tangentialArcTo: SketchLineHelper = {
|
||||
}
|
||||
},
|
||||
// TODO copy-paste from angledLine
|
||||
addTag: addTag(),
|
||||
addTag: addTagWithTo('angleLength'),
|
||||
}
|
||||
export const angledLine: SketchLineHelper = {
|
||||
add: ({
|
||||
@ -576,7 +576,7 @@ export const angledLine: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTag(),
|
||||
addTag: addTagWithTo('angleLength'),
|
||||
}
|
||||
|
||||
export const angledLineOfXLength: SketchLineHelper = {
|
||||
@ -649,7 +649,7 @@ export const angledLineOfXLength: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTag(),
|
||||
addTag: addTagWithTo('angleLength'),
|
||||
}
|
||||
|
||||
export const angledLineOfYLength: SketchLineHelper = {
|
||||
@ -723,7 +723,7 @@ export const angledLineOfYLength: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTag(),
|
||||
addTag: addTagWithTo('angleLength'),
|
||||
}
|
||||
|
||||
export const angledLineToX: SketchLineHelper = {
|
||||
@ -792,7 +792,7 @@ export const angledLineToX: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTag(),
|
||||
addTag: addTagWithTo('angleTo'),
|
||||
}
|
||||
|
||||
export const angledLineToY: SketchLineHelper = {
|
||||
@ -862,7 +862,7 @@ export const angledLineToY: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTag(),
|
||||
addTag: addTagWithTo('angleTo'),
|
||||
}
|
||||
|
||||
export const angledLineThatIntersects: SketchLineHelper = {
|
||||
@ -951,7 +951,7 @@ export const angledLineThatIntersects: SketchLineHelper = {
|
||||
pathToNode,
|
||||
}
|
||||
},
|
||||
addTag: addTag(), // TODO might be wrong
|
||||
addTag: addTagWithTo('angleTo'), // TODO might be wrong
|
||||
}
|
||||
|
||||
export const updateStartProfileAtArgs: SketchLineHelper['updateArgs'] = ({
|
||||
@ -1174,31 +1174,29 @@ function isAngleLiteral(lineArugement: Value): boolean {
|
||||
|
||||
type addTagFn = (a: ModifyAstBase) => { modifiedAst: Program; tag: string }
|
||||
|
||||
function addTag(): addTagFn {
|
||||
function addTagWithTo(
|
||||
argType: 'angleLength' | 'angleTo' | 'default' | 'length'
|
||||
): addTagFn {
|
||||
return ({ node, pathToNode }) => {
|
||||
let tagName = findUniqueName(node, 'seg', 2)
|
||||
const _node = { ...node }
|
||||
const { node: primaryCallExp } = getNodeFromPath<CallExpression>(
|
||||
const { node: callExpression } = getNodeFromPath<CallExpression>(
|
||||
_node,
|
||||
pathToNode,
|
||||
'CallExpression'
|
||||
pathToNode
|
||||
)
|
||||
// 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
|
||||
const tagArg = callExpression.arguments?.[2]
|
||||
if (tagArg) {
|
||||
return {
|
||||
modifiedAst: _node,
|
||||
tag: String(tagLiteral.value),
|
||||
tag: String(tagArg),
|
||||
}
|
||||
} else {
|
||||
throw new Error('Unable to assign tag without value')
|
||||
callExpression.arguments[2] = createLiteral(tagName)
|
||||
|
||||
return {
|
||||
modifiedAst: _node,
|
||||
tag: tagName,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
1168
src/wasm-lib/Cargo.lock
generated
1168
src/wasm-lib/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -59,7 +59,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.dependencies]
|
||||
kittycad = { path = "../../../kittycad.rs/kittycad", default-features = false, features = ["js", "requests"] }
|
||||
kittycad = { version = "0.2.60", default-features = false, features = ["js", "requests"] }
|
||||
kittycad-execution-plan = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
|
||||
kittycad-execution-plan-macros = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
|
||||
kittycad-execution-plan-traits = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
|
||||
|
@ -6,7 +6,6 @@ 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 }
|
||||
@ -16,7 +15,6 @@ 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]
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 80 KiB |
Binary file not shown.
Before Width: | Height: | Size: 81 KiB |
@ -2,16 +2,13 @@ use std::collections::HashMap;
|
||||
|
||||
use kcl_lib::ast::types::{LiteralIdentifier, LiteralValue};
|
||||
|
||||
use kittycad_execution_plan::constants;
|
||||
use kittycad_execution_plan_traits::Primitive;
|
||||
|
||||
use super::{native_functions, Address};
|
||||
use crate::{CompileError, KclFunction};
|
||||
|
||||
/// KCL values which can be written to KCEP memory.
|
||||
/// This is recursive. For example, the bound value might be an array, which itself contains bound values.
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
pub enum EpBinding {
|
||||
/// A KCL value which gets stored in a particular address in KCEP memory.
|
||||
Single(Address),
|
||||
@ -26,8 +23,6 @@ pub enum EpBinding {
|
||||
properties: HashMap<String, EpBinding>,
|
||||
},
|
||||
/// Not associated with a KCEP address.
|
||||
Constant(Primitive),
|
||||
/// Not associated with a KCEP address.
|
||||
Function(KclFunction),
|
||||
/// SketchGroups have their own storage.
|
||||
SketchGroup { index: usize },
|
||||
@ -57,13 +52,11 @@ impl EpBinding {
|
||||
EpBinding::SketchGroup { .. } => Err(CompileError::CannotIndex),
|
||||
EpBinding::Single(_) => Err(CompileError::CannotIndex),
|
||||
EpBinding::Function(_) => Err(CompileError::CannotIndex),
|
||||
EpBinding::Constant(_) => Err(CompileError::CannotIndex),
|
||||
},
|
||||
// Objects can be indexed by string properties.
|
||||
LiteralValue::String(property) => match self {
|
||||
EpBinding::Single(_) => Err(CompileError::NoProperties),
|
||||
EpBinding::Function(_) => Err(CompileError::NoProperties),
|
||||
EpBinding::Constant(_) => Err(CompileError::CannotIndex),
|
||||
EpBinding::SketchGroup { .. } => Err(CompileError::NoProperties),
|
||||
EpBinding::Sequence { .. } => Err(CompileError::ArrayDoesNotHaveProperties),
|
||||
EpBinding::Map {
|
||||
@ -110,58 +103,8 @@ impl BindingScope {
|
||||
// TODO: Actually put the stdlib prelude in here,
|
||||
// things like `startSketchAt` and `line`.
|
||||
ep_bindings: HashMap::from([
|
||||
("E".into(), EpBinding::Constant(constants::E)),
|
||||
("PI".into(), EpBinding::Constant(constants::PI)),
|
||||
("id".into(), EpBinding::from(KclFunction::Id(native_functions::Id))),
|
||||
("abs".into(), EpBinding::from(KclFunction::Abs(native_functions::Abs))),
|
||||
(
|
||||
"acos".into(),
|
||||
EpBinding::from(KclFunction::Acos(native_functions::Acos)),
|
||||
),
|
||||
(
|
||||
"asin".into(),
|
||||
EpBinding::from(KclFunction::Asin(native_functions::Asin)),
|
||||
),
|
||||
(
|
||||
"atan".into(),
|
||||
EpBinding::from(KclFunction::Atan(native_functions::Atan)),
|
||||
),
|
||||
(
|
||||
"ceil".into(),
|
||||
EpBinding::from(KclFunction::Ceil(native_functions::Ceil)),
|
||||
),
|
||||
("cos".into(), EpBinding::from(KclFunction::Cos(native_functions::Cos))),
|
||||
(
|
||||
"floor".into(),
|
||||
EpBinding::from(KclFunction::Floor(native_functions::Floor)),
|
||||
),
|
||||
("ln".into(), EpBinding::from(KclFunction::Ln(native_functions::Ln))),
|
||||
(
|
||||
"log10".into(),
|
||||
EpBinding::from(KclFunction::Log10(native_functions::Log10)),
|
||||
),
|
||||
(
|
||||
"log2".into(),
|
||||
EpBinding::from(KclFunction::Log2(native_functions::Log2)),
|
||||
),
|
||||
("sin".into(), EpBinding::from(KclFunction::Sin(native_functions::Sin))),
|
||||
(
|
||||
"sqrt".into(),
|
||||
EpBinding::from(KclFunction::Sqrt(native_functions::Sqrt)),
|
||||
),
|
||||
("tan".into(), EpBinding::from(KclFunction::Tan(native_functions::Tan))),
|
||||
(
|
||||
"toDegrees".into(),
|
||||
EpBinding::from(KclFunction::ToDegrees(native_functions::ToDegrees)),
|
||||
),
|
||||
(
|
||||
"toRadians".into(),
|
||||
EpBinding::from(KclFunction::ToRadians(native_functions::ToRadians)),
|
||||
),
|
||||
("add".into(), EpBinding::from(KclFunction::Add(native_functions::Add))),
|
||||
("log".into(), EpBinding::from(KclFunction::Log(native_functions::Log))),
|
||||
("max".into(), EpBinding::from(KclFunction::Max(native_functions::Max))),
|
||||
("min".into(), EpBinding::from(KclFunction::Min(native_functions::Min))),
|
||||
(
|
||||
"startSketchAt".into(),
|
||||
EpBinding::from(KclFunction::StartSketchAt(native_functions::sketch::StartSketchAt)),
|
||||
@ -170,26 +113,6 @@ 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)),
|
||||
|
@ -61,7 +61,7 @@ pub enum Error {
|
||||
#[error("Failed on instruction {instruction_index}:\n{error}\n\nInstruction contents were {instruction:#?}")]
|
||||
Execution {
|
||||
error: ExecutionError,
|
||||
instruction: Instruction,
|
||||
instruction: Option<Instruction>,
|
||||
instruction_index: usize,
|
||||
},
|
||||
}
|
||||
@ -76,7 +76,7 @@ impl From<ExecutionFailed> for Error {
|
||||
) -> Self {
|
||||
Self::Execution {
|
||||
error,
|
||||
instruction: instruction.expect("no instruction"),
|
||||
instruction,
|
||||
instruction_index,
|
||||
}
|
||||
}
|
||||
|
@ -259,32 +259,9 @@ impl Planner {
|
||||
binding,
|
||||
} = match callee {
|
||||
KclFunction::Id(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Abs(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Acos(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Asin(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Atan(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Ceil(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Cos(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Floor(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Ln(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Log10(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Log2(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Sin(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Sqrt(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Tan(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::ToDegrees(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::ToRadians(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Log(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Max(f) => f.call(&mut ctx, args)?,
|
||||
KclFunction::Min(f) => f.call(&mut ctx, args)?,
|
||||
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) => {
|
||||
@ -652,32 +629,9 @@ impl Eq for UserDefinedFunction {}
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
enum KclFunction {
|
||||
Id(native_functions::Id),
|
||||
Abs(native_functions::Abs),
|
||||
Acos(native_functions::Acos),
|
||||
Asin(native_functions::Asin),
|
||||
Atan(native_functions::Atan),
|
||||
Ceil(native_functions::Ceil),
|
||||
Cos(native_functions::Cos),
|
||||
Floor(native_functions::Floor),
|
||||
Ln(native_functions::Ln),
|
||||
Log10(native_functions::Log10),
|
||||
Log2(native_functions::Log2),
|
||||
Sin(native_functions::Sin),
|
||||
Sqrt(native_functions::Sqrt),
|
||||
Tan(native_functions::Tan),
|
||||
ToDegrees(native_functions::ToDegrees),
|
||||
ToRadians(native_functions::ToRadians),
|
||||
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),
|
||||
Log(native_functions::Log),
|
||||
Max(native_functions::Max),
|
||||
Min(native_functions::Min),
|
||||
UserDefined(UserDefinedFunction),
|
||||
Extrude(native_functions::sketch::Extrude),
|
||||
Close(native_functions::sketch::Close),
|
||||
|
@ -2,15 +2,18 @@
|
||||
//! This includes some of the stdlib, e.g. `startSketchAt`.
|
||||
//! But some other stdlib functions will be written in KCL.
|
||||
|
||||
use kittycad_execution_plan::{
|
||||
BinaryArithmetic, BinaryOperation, Destination, Instruction, Operand, UnaryArithmetic, UnaryOperation,
|
||||
};
|
||||
use kittycad_execution_plan::{BinaryArithmetic, Destination, Instruction};
|
||||
use kittycad_execution_plan_traits::Address;
|
||||
|
||||
use crate::{CompileError, EpBinding, EvalPlan};
|
||||
|
||||
pub mod sketch;
|
||||
|
||||
/// The identity function. Always returns its first input.
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
pub struct Id;
|
||||
|
||||
pub trait Callable {
|
||||
fn call(&self, ctx: &mut Context<'_>, args: Vec<EpBinding>) -> Result<EvalPlan, CompileError>;
|
||||
}
|
||||
@ -29,65 +32,6 @@ impl<'a> Context<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Unary operator macro to quickly create new bindings.
|
||||
macro_rules! define_unary {
|
||||
() => {};
|
||||
($h:ident$( $r:ident)*) => {
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
pub struct $h;
|
||||
|
||||
impl Callable for $h {
|
||||
fn call(&self, ctx: &mut Context<'_>, mut args: Vec<EpBinding>) -> Result<EvalPlan, CompileError> {
|
||||
if args.len() > 1 {
|
||||
return Err(CompileError::TooManyArgs {
|
||||
fn_name: "$h".into(),
|
||||
maximum: 1,
|
||||
actual: args.len(),
|
||||
});
|
||||
}
|
||||
|
||||
let not_enough_args = CompileError::NotEnoughArgs {
|
||||
fn_name: "$h".into(),
|
||||
required: 1,
|
||||
actual: args.len(),
|
||||
};
|
||||
|
||||
let EpBinding::Single(arg0) = args.pop().ok_or(not_enough_args.clone())? else {
|
||||
return Err(CompileError::InvalidOperand("A single value binding is expected"));
|
||||
};
|
||||
|
||||
let destination = ctx.next_address.offset_by(1);
|
||||
let instructions = vec![
|
||||
Instruction::UnaryArithmetic {
|
||||
arithmetic: UnaryArithmetic {
|
||||
operation: UnaryOperation::$h,
|
||||
operand: Operand::Reference(arg0)
|
||||
},
|
||||
destination: Destination::Address(destination)
|
||||
}
|
||||
];
|
||||
|
||||
Ok(EvalPlan {
|
||||
instructions,
|
||||
binding: EpBinding::Single(destination),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
define_unary!($($r)*);
|
||||
};
|
||||
}
|
||||
|
||||
define_unary!(Abs Acos Asin Atan Ceil Cos Floor Ln Log10 Log2 Sin Sqrt Tan ToDegrees ToRadians);
|
||||
|
||||
/// The identity function. Always returns its first input.
|
||||
/// Implemented purely on the KCL side so it doesn't need to be in the
|
||||
/// define_unary! macro above.
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
pub struct Id;
|
||||
|
||||
impl Callable for Id {
|
||||
fn call(&self, _: &mut Context<'_>, args: Vec<EpBinding>) -> Result<EvalPlan, CompileError> {
|
||||
if args.len() > 1 {
|
||||
@ -112,53 +56,44 @@ impl Callable for Id {
|
||||
}
|
||||
}
|
||||
|
||||
/// Binary operator macro to quickly create new bindings.
|
||||
macro_rules! define_binary {
|
||||
() => {};
|
||||
($h:ident$( $r:ident)*) => {
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
pub struct $h;
|
||||
/// A test function that adds two numbers.
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(Eq, PartialEq))]
|
||||
pub struct Add;
|
||||
|
||||
impl Callable for $h {
|
||||
fn call(&self, ctx: &mut Context<'_>, mut args: Vec<EpBinding>) -> Result<EvalPlan, CompileError> {
|
||||
let len = args.len();
|
||||
if len > 2 {
|
||||
return Err(CompileError::TooManyArgs {
|
||||
fn_name: "$h".into(),
|
||||
maximum: 2,
|
||||
actual: len,
|
||||
});
|
||||
}
|
||||
let not_enough_args = CompileError::NotEnoughArgs {
|
||||
fn_name: "$h".into(),
|
||||
required: 2,
|
||||
actual: len,
|
||||
};
|
||||
const ERR: &str = "cannot use composite values (e.g. array) as arguments to $h";
|
||||
let EpBinding::Single(arg1) = args.pop().ok_or(not_enough_args.clone())? else {
|
||||
return Err(CompileError::InvalidOperand(ERR));
|
||||
};
|
||||
let EpBinding::Single(arg0) = args.pop().ok_or(not_enough_args)? else {
|
||||
return Err(CompileError::InvalidOperand(ERR));
|
||||
};
|
||||
let destination = ctx.next_address.offset_by(1);
|
||||
Ok(EvalPlan {
|
||||
instructions: vec![Instruction::BinaryArithmetic {
|
||||
arithmetic: BinaryArithmetic {
|
||||
operation: BinaryOperation::$h,
|
||||
operand0: Operand::Reference(arg0),
|
||||
operand1: Operand::Reference(arg1),
|
||||
},
|
||||
destination: Destination::Address(destination),
|
||||
}],
|
||||
binding: EpBinding::Single(destination),
|
||||
})
|
||||
impl Callable for Add {
|
||||
fn call(&self, ctx: &mut Context<'_>, mut args: Vec<EpBinding>) -> Result<EvalPlan, CompileError> {
|
||||
let len = args.len();
|
||||
if len > 2 {
|
||||
return Err(CompileError::TooManyArgs {
|
||||
fn_name: "add".into(),
|
||||
maximum: 2,
|
||||
actual: len,
|
||||
});
|
||||
}
|
||||
let not_enough_args = CompileError::NotEnoughArgs {
|
||||
fn_name: "add".into(),
|
||||
required: 2,
|
||||
actual: len,
|
||||
};
|
||||
const ERR: &str = "cannot use composite values (e.g. array) as arguments to Add";
|
||||
let EpBinding::Single(arg1) = args.pop().ok_or(not_enough_args.clone())? else {
|
||||
return Err(CompileError::InvalidOperand(ERR));
|
||||
};
|
||||
let EpBinding::Single(arg0) = args.pop().ok_or(not_enough_args)? else {
|
||||
return Err(CompileError::InvalidOperand(ERR));
|
||||
};
|
||||
let destination = ctx.next_address.offset_by(1);
|
||||
Ok(EvalPlan {
|
||||
instructions: vec![Instruction::BinaryArithmetic {
|
||||
arithmetic: BinaryArithmetic {
|
||||
operation: kittycad_execution_plan::BinaryOperation::Add,
|
||||
operand0: kittycad_execution_plan::Operand::Reference(arg0),
|
||||
operand1: kittycad_execution_plan::Operand::Reference(arg1),
|
||||
},
|
||||
destination: Destination::Address(destination),
|
||||
}],
|
||||
binding: EpBinding::Single(destination),
|
||||
})
|
||||
}
|
||||
|
||||
define_binary!($($r)*);
|
||||
};
|
||||
}
|
||||
|
||||
define_binary!(Add Log Max Min);
|
||||
|
@ -3,4 +3,4 @@
|
||||
pub mod helpers;
|
||||
pub mod stdlib_functions;
|
||||
|
||||
pub use stdlib_functions::{Close, Extrude, Line, LineTo, StartSketchAt, XLine, XLineTo, YLine, YLineTo};
|
||||
pub use stdlib_functions::{Close, Extrude, LineTo, StartSketchAt};
|
||||
|
@ -67,12 +67,6 @@ pub fn sg_binding(
|
||||
actual: "function".to_owned(),
|
||||
arg_number,
|
||||
}),
|
||||
EpBinding::Constant(_) => Err(CompileError::ArgWrongType {
|
||||
fn_name,
|
||||
expected,
|
||||
actual: "constant".to_owned(),
|
||||
arg_number,
|
||||
}),
|
||||
}
|
||||
}
|
||||
pub fn single_binding(
|
||||
@ -107,12 +101,6 @@ pub fn single_binding(
|
||||
actual: "function".to_owned(),
|
||||
arg_number,
|
||||
}),
|
||||
EpBinding::Constant(_) => Err(CompileError::ArgWrongType {
|
||||
fn_name,
|
||||
expected,
|
||||
actual: "constant".to_owned(),
|
||||
arg_number,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -148,16 +136,10 @@ pub fn sequence_binding(
|
||||
actual: "function".to_owned(),
|
||||
arg_number,
|
||||
}),
|
||||
EpBinding::Constant(_) => Err(CompileError::ArgWrongType {
|
||||
fn_name,
|
||||
expected,
|
||||
actual: "constant".to_owned(),
|
||||
arg_number,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract a 2D point from an argument to a KCL Function.
|
||||
/// Extract a 2D point from an argument to a Cabble.
|
||||
pub fn arg_point2d(
|
||||
arg: EpBinding,
|
||||
fn_name: &'static str,
|
||||
@ -166,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, fn_name, "an array of length 2", arg_number)?;
|
||||
let elements = sequence_binding(arg, "startSketchAt", "an array of length 2", arg_number)?;
|
||||
if elements.len() != 2 {
|
||||
return Err(CompileError::ArgWrongType {
|
||||
fn_name,
|
||||
@ -183,12 +165,12 @@ pub fn arg_point2d(
|
||||
let start_z = start + 2;
|
||||
instructions.extend([
|
||||
Instruction::Copy {
|
||||
source: single_binding(elements[0].clone(), fn_name, "number", arg_number)?,
|
||||
source: single_binding(elements[0].clone(), "startSketchAt", "number", arg_number)?,
|
||||
destination: Destination::Address(start_x),
|
||||
length: 1,
|
||||
},
|
||||
Instruction::Copy {
|
||||
source: single_binding(elements[1].clone(), fn_name, "number", arg_number)?,
|
||||
source: single_binding(elements[1].clone(), "startSketchAt", "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},
|
||||
BinaryArithmetic, BinaryOperation, Destination, Instruction, Operand,
|
||||
Destination, Instruction,
|
||||
};
|
||||
use kittycad_execution_plan_traits::{Address, InMemory, Primitive, Value};
|
||||
use kittycad_modeling_cmds::{
|
||||
@ -13,22 +13,6 @@ 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;
|
||||
@ -156,124 +140,25 @@ 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 required = 2;
|
||||
|
||||
let fn_name = "lineTo";
|
||||
// Get both required params.
|
||||
let mut args_iter = args.into_iter();
|
||||
|
||||
let Some(to) = args_iter.next() else {
|
||||
return Err(CompileError::NotEnoughArgs {
|
||||
fn_name: fn_name.into(),
|
||||
required,
|
||||
actual: args_iter.count(),
|
||||
required: 2,
|
||||
actual: 0,
|
||||
});
|
||||
};
|
||||
|
||||
let Some(sketch_group) = args_iter.next() else {
|
||||
return Err(CompileError::NotEnoughArgs {
|
||||
fn_name: fn_name.into(),
|
||||
required,
|
||||
actual: args_iter.count(),
|
||||
required: 2,
|
||||
actual: 1,
|
||||
});
|
||||
};
|
||||
|
||||
let tag = match args_iter.next() {
|
||||
Some(a) => a,
|
||||
None => {
|
||||
@ -286,90 +171,26 @@ impl LineBare {
|
||||
EpBinding::Single(empty_string_addr)
|
||||
}
|
||||
};
|
||||
|
||||
// Check the type of required params.
|
||||
// We don't check `to` here because it can take on either a
|
||||
// EpBinding::Sequence or EpBinding::Single.
|
||||
|
||||
let to = arg_point2d(to, fn_name, &mut instructions, ctx, 0)?;
|
||||
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 {
|
||||
@ -383,7 +204,7 @@ impl LineBare {
|
||||
// Then its `relative` field.
|
||||
Instruction::SetPrimitive {
|
||||
address: start_of_line + 1 + length_of_3d_point,
|
||||
value: opts.at.is_relative().into(),
|
||||
value: false.into(),
|
||||
},
|
||||
// Push the path ID onto the stack.
|
||||
Instruction::SketchGroupCopyFrom {
|
||||
@ -410,159 +231,16 @@ impl LineBare {
|
||||
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,
|
||||
},
|
||||
]);
|
||||
|
||||
// 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.
|
||||
Instruction::Copy {
|
||||
source: start_of_line + 1,
|
||||
length: 2,
|
||||
destination: Destination::StackExtend,
|
||||
},
|
||||
]);
|
||||
|
||||
// `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,
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::{collections::HashMap, env};
|
||||
|
||||
use ep::{constants, sketch_types, Destination, UnaryArithmetic};
|
||||
use ept::{ListHeader, ObjectHeader, Primitive};
|
||||
use ep::{sketch_types, Destination, UnaryArithmetic};
|
||||
use ept::{ListHeader, ObjectHeader};
|
||||
use kittycad_modeling_cmds::shared::Point2d;
|
||||
use kittycad_modeling_session::SessionBuilder;
|
||||
use pretty_assertions::assert_eq;
|
||||
@ -1048,10 +1048,42 @@ 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, path: &str) {
|
||||
fn kcvm_dbg(kcl_program: &str) {
|
||||
let (plan, _scope, _) = must_plan(kcl_program);
|
||||
let plan_json = serde_json::to_string_pretty(&plan).unwrap();
|
||||
std::fs::write(path, plan_json).unwrap();
|
||||
std::fs::write(
|
||||
"/Users/adamchalmers/kc-repos/modeling-api/execution-plan-debugger/test_input.json",
|
||||
plan_json,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn paul_qr_test() {
|
||||
let program = include_str!("../testdata/paul_qr.kcl");
|
||||
let ast = kcl_lib::parser::Parser::new(kcl_lib::token::lexer(program))
|
||||
.ast()
|
||||
.unwrap();
|
||||
let mut client = Some(test_client().await);
|
||||
crate::execute(ast, &mut client).await.unwrap();
|
||||
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,
|
||||
}
|
||||
.into(),
|
||||
)
|
||||
.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("paul_qr_code.png", out).unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@ -1065,6 +1097,8 @@ 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();
|
||||
@ -1107,115 +1141,23 @@ 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(),
|
||||
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);
|
||||
// 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();
|
||||
}
|
||||
|
||||
async fn test_client() -> Session {
|
||||
@ -1414,31 +1356,3 @@ fn mod_and_pow() {
|
||||
]
|
||||
);
|
||||
}
|
||||
#[tokio::test]
|
||||
async fn cos_sin_pi() {
|
||||
let program = "
|
||||
let x = cos(45.0)*10
|
||||
let y = sin(45.0)*10
|
||||
let z = PI
|
||||
";
|
||||
let (_plan, scope, _) = must_plan(program);
|
||||
let Some(EpBinding::Single(x)) = scope.get("x") else {
|
||||
panic!("Unexpected binding for variable 'x': {:?}", scope.get("x"));
|
||||
};
|
||||
let Some(EpBinding::Single(y)) = scope.get("y") else {
|
||||
panic!("Unexpected binding for variable 'y': {:?}", scope.get("y"));
|
||||
};
|
||||
let Some(EpBinding::Constant(z)) = scope.get("z") else {
|
||||
panic!("Unexpected binding for variable 'z': {:?}", scope.get("z"));
|
||||
};
|
||||
let ast = kcl_lib::parser::Parser::new(kcl_lib::token::lexer(program))
|
||||
.ast()
|
||||
.unwrap();
|
||||
let mem = crate::execute(ast, &mut None).await.unwrap();
|
||||
use ept::ReadMemory;
|
||||
assert_eq!(*mem.get(x).unwrap(), Primitive::from(5.253219888177298));
|
||||
assert_eq!(*mem.get(y).unwrap(), Primitive::from(8.509035245341185));
|
||||
|
||||
// Constants don't live in memory.
|
||||
assert_eq!(*z, constants::PI);
|
||||
}
|
||||
|
2655
src/wasm-lib/grackle/testdata/paul_qr.kcl
vendored
Normal file
2655
src/wasm-lib/grackle/testdata/paul_qr.kcl
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -14,7 +14,6 @@ keywords = ["kcl", "KittyCAD", "CAD"]
|
||||
anyhow = { version = "1.0.81", features = ["backtrace"] }
|
||||
async-recursion = "1.0.5"
|
||||
async-trait = "0.1.77"
|
||||
boxcar = "0.2.4"
|
||||
chrono = "0.4.35"
|
||||
clap = { version = "4.5.2", features = ["cargo", "derive", "env", "unicode"], optional = true }
|
||||
dashmap = "5.5.3"
|
||||
|
216
src/wasm-lib/kcl/fuzz/Cargo.lock
generated
216
src/wasm-lib/kcl/fuzz/Cargo.lock
generated
@ -7,10 +7,6 @@ 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"
|
||||
@ -48,26 +44,11 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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"
|
||||
version = "1.0.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247"
|
||||
checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
]
|
||||
@ -111,7 +92,7 @@ checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.53",
|
||||
"syn 2.0.50",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -122,7 +103,7 @@ checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.53",
|
||||
"syn 2.0.50",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -287,17 +268,12 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.35"
|
||||
version = "0.4.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a"
|
||||
checksum = "d87d9d13be47a5b7c3907137f1290b0459a7f80efb26be8c52afb11963bccb02"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
"windows-targets 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -344,21 +320,6 @@ 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"
|
||||
@ -407,7 +368,7 @@ checksum = "377af281d8f23663862a7c84623bc5dcf7f8c44b13c7496a590bdc157f941a43"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.53",
|
||||
"syn 2.0.50",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
@ -419,11 +380,10 @@ checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946"
|
||||
|
||||
[[package]]
|
||||
name = "derive-docs"
|
||||
version = "0.1.11"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4e18a04fe569a325dd50743821f2605057ff5c4b48e60512270b4406907825b"
|
||||
checksum = "834580a8bd697658876ed8c9f7727e49f01d34f5b859ca921ac5b99ffc6adf77"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"convert_case",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
@ -431,7 +391,7 @@ dependencies = [
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_tokenstream",
|
||||
"syn 2.0.53",
|
||||
"syn 2.0.50",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -561,7 +521,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.53",
|
||||
"syn 2.0.50",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -632,7 +592,7 @@ dependencies = [
|
||||
"inflections",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.53",
|
||||
"syn 2.0.50",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -779,29 +739,6 @@ 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"
|
||||
@ -870,23 +807,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.69"
|
||||
version = "0.3.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
|
||||
checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kcl-lib"
|
||||
version = "0.1.46"
|
||||
version = "0.1.42"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"approx",
|
||||
"async-recursion",
|
||||
"async-trait",
|
||||
"bson",
|
||||
"chrono",
|
||||
"dashmap",
|
||||
"databake",
|
||||
"derive-docs",
|
||||
@ -897,14 +833,12 @@ 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",
|
||||
@ -915,7 +849,6 @@ dependencies = [
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"winnow",
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -928,9 +861,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kittycad"
|
||||
version = "0.2.60"
|
||||
version = "0.2.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8aa5906d0730bd90f6b3331fe57c04951d00743169a29ee96408767b4060605"
|
||||
checksum = "13958174d876353f429ea8230dc92fe86f164819cea2e51bbf22e01a4c2a496e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -944,7 +877,6 @@ dependencies = [
|
||||
"http 0.2.9",
|
||||
"itertools",
|
||||
"log",
|
||||
"mime_guess",
|
||||
"parse-display 0.8.2",
|
||||
"phonenumber",
|
||||
"rand",
|
||||
@ -967,13 +899,14 @@ source = "git+https://github.com/KittyCAD/modeling-api?branch=main#1e6ef9601686c
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.53",
|
||||
"syn 2.0.50",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kittycad-execution-plan-traits"
|
||||
version = "0.1.13"
|
||||
source = "git+https://github.com/KittyCAD/modeling-api?branch=main#494225aaac06fab77c4822e7dc48738ecca35392"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3ec8efd57b59697eb140b63c0ffe7db44fdfe5a55f14e45513411eba2280ba5"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"thiserror",
|
||||
@ -1095,9 +1028,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.11"
|
||||
version = "0.8.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
|
||||
checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi",
|
||||
@ -1238,7 +1171,7 @@ dependencies = [
|
||||
"regex",
|
||||
"regex-syntax 0.7.5",
|
||||
"structmeta 0.2.0",
|
||||
"syn 2.0.53",
|
||||
"syn 2.0.50",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1252,7 +1185,7 @@ dependencies = [
|
||||
"regex",
|
||||
"regex-syntax 0.8.2",
|
||||
"structmeta 0.3.0",
|
||||
"syn 2.0.53",
|
||||
"syn 2.0.50",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1299,7 +1232,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.53",
|
||||
"syn 2.0.50",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1471,9 +1404,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.11.27"
|
||||
version = "0.11.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
|
||||
checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251"
|
||||
dependencies = [
|
||||
"base64 0.21.3",
|
||||
"bytes",
|
||||
@ -1759,7 +1692,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.53",
|
||||
"syn 2.0.50",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1793,7 +1726,7 @@ checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.53",
|
||||
"syn 2.0.50",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1805,7 +1738,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"syn 2.0.53",
|
||||
"syn 2.0.50",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1843,17 +1776,6 @@ 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"
|
||||
@ -1925,7 +1847,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"structmeta-derive 0.2.0",
|
||||
"syn 2.0.53",
|
||||
"syn 2.0.50",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1937,7 +1859,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"structmeta-derive 0.3.0",
|
||||
"syn 2.0.53",
|
||||
"syn 2.0.50",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1948,7 +1870,7 @@ checksum = "a60bcaff7397072dca0017d1db428e30d5002e00b6847703e2e42005c95fbe00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.53",
|
||||
"syn 2.0.50",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1959,7 +1881,7 @@ checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.53",
|
||||
"syn 2.0.50",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2003,9 +1925,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.53"
|
||||
version = "2.0.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032"
|
||||
checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -2026,7 +1948,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.53",
|
||||
"syn 2.0.50",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2082,7 +2004,7 @@ checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.53",
|
||||
"syn 2.0.50",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2155,7 +2077,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.53",
|
||||
"syn 2.0.50",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2261,7 +2183,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.53",
|
||||
"syn 2.0.50",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2290,7 +2212,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.53",
|
||||
"syn 2.0.50",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2328,7 +2250,7 @@ dependencies = [
|
||||
"Inflector",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.53",
|
||||
"syn 2.0.50",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
@ -2460,9 +2382,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.92"
|
||||
version = "0.2.91"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
|
||||
checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
@ -2470,24 +2392,24 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.92"
|
||||
version = "0.2.91"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
|
||||
checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.53",
|
||||
"syn 2.0.50",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.42"
|
||||
version = "0.4.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0"
|
||||
checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
@ -2497,9 +2419,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.92"
|
||||
version = "0.2.91"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
|
||||
checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
@ -2507,22 +2429,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.92"
|
||||
version = "0.2.91"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
||||
checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.53",
|
||||
"syn 2.0.50",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.92"
|
||||
version = "0.2.91"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
|
||||
checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-streams"
|
||||
@ -2539,9 +2461,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.69"
|
||||
version = "0.3.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
|
||||
checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
@ -2584,15 +2506,6 @@ 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"
|
||||
@ -2767,14 +2680,3 @@ 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",
|
||||
]
|
||||
|
@ -75,7 +75,6 @@ pub async fn modify_ast_for_sketch(
|
||||
// Let's get the path info.
|
||||
let resp = engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
SourceRange::default(),
|
||||
ModelingCmd::PathGetInfo { path_id: sketch_id },
|
||||
@ -100,7 +99,6 @@ pub async fn modify_ast_for_sketch(
|
||||
for segment in &path_info.segments {
|
||||
if let Some(command_id) = &segment.command_id {
|
||||
let h = engine.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
SourceRange::default(),
|
||||
ModelingCmd::CurveGetControlPoints { curve_id: *command_id },
|
||||
|
@ -29,7 +29,6 @@ pub struct EngineConnection {
|
||||
responses: Arc<DashMap<uuid::Uuid, WebSocketResponse>>,
|
||||
tcp_read_handle: Arc<TcpReadHandle>,
|
||||
socket_health: Arc<Mutex<SocketHealth>>,
|
||||
batch: Arc<Mutex<Vec<WebSocketRequest>>>,
|
||||
}
|
||||
|
||||
pub struct TcpRead {
|
||||
@ -155,136 +154,27 @@ impl EngineConnection {
|
||||
}),
|
||||
responses,
|
||||
socket_health,
|
||||
batch: Arc::new(Mutex::new(Vec::new())),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn is_cmd_with_return_values(cmd: &kittycad::types::ModelingCmd) -> bool {
|
||||
let (kittycad::types::ModelingCmd::Export { .. }
|
||||
| kittycad::types::ModelingCmd::Extrude { .. }
|
||||
| kittycad::types::ModelingCmd::SketchModeDisable { .. }
|
||||
| kittycad::types::ModelingCmd::ObjectBringToFront { .. }
|
||||
| kittycad::types::ModelingCmd::SelectWithPoint { .. }
|
||||
| kittycad::types::ModelingCmd::HighlightSetEntity { .. }
|
||||
| kittycad::types::ModelingCmd::EntityGetChildUuid { .. }
|
||||
| kittycad::types::ModelingCmd::EntityGetNumChildren { .. }
|
||||
| kittycad::types::ModelingCmd::EntityGetParentId { .. }
|
||||
| kittycad::types::ModelingCmd::EntityGetAllChildUuids { .. }
|
||||
| kittycad::types::ModelingCmd::CameraDragMove { .. }
|
||||
| kittycad::types::ModelingCmd::CameraDragEnd { .. }
|
||||
| kittycad::types::ModelingCmd::DefaultCameraGetSettings { .. }
|
||||
| kittycad::types::ModelingCmd::DefaultCameraZoom { .. }
|
||||
| kittycad::types::ModelingCmd::SelectGet { .. }
|
||||
| kittycad::types::ModelingCmd::Solid3DGetAllEdgeFaces { .. }
|
||||
| kittycad::types::ModelingCmd::Solid3DGetAllOppositeEdges { .. }
|
||||
| kittycad::types::ModelingCmd::Solid3DGetOppositeEdge { .. }
|
||||
| kittycad::types::ModelingCmd::Solid3DGetNextAdjacentEdge { .. }
|
||||
| kittycad::types::ModelingCmd::Solid3DGetPrevAdjacentEdge { .. }
|
||||
| kittycad::types::ModelingCmd::GetEntityType { .. }
|
||||
| kittycad::types::ModelingCmd::CurveGetControlPoints { .. }
|
||||
| kittycad::types::ModelingCmd::CurveGetType { .. }
|
||||
| kittycad::types::ModelingCmd::MouseClick { .. }
|
||||
| kittycad::types::ModelingCmd::TakeSnapshot { .. }
|
||||
| kittycad::types::ModelingCmd::PathGetInfo { .. }
|
||||
| kittycad::types::ModelingCmd::PathGetCurveUuidsForVertices { .. }
|
||||
| kittycad::types::ModelingCmd::PathGetVertexUuids { .. }
|
||||
| kittycad::types::ModelingCmd::CurveGetEndPoints { .. }
|
||||
| kittycad::types::ModelingCmd::FaceIsPlanar { .. }
|
||||
| kittycad::types::ModelingCmd::FaceGetPosition { .. }
|
||||
| kittycad::types::ModelingCmd::FaceGetGradient { .. }
|
||||
| kittycad::types::ModelingCmd::PlaneIntersectAndProject { .. }
|
||||
| kittycad::types::ModelingCmd::ImportFiles { .. }
|
||||
| kittycad::types::ModelingCmd::Mass { .. }
|
||||
| kittycad::types::ModelingCmd::Volume { .. }
|
||||
| kittycad::types::ModelingCmd::Density { .. }
|
||||
| kittycad::types::ModelingCmd::SurfaceArea { .. }
|
||||
| kittycad::types::ModelingCmd::CenterOfMass { .. }
|
||||
| kittycad::types::ModelingCmd::GetSketchModePlane { .. }
|
||||
| kittycad::types::ModelingCmd::EntityGetDistance { .. }
|
||||
| kittycad::types::ModelingCmd::EntityLinearPattern { .. }
|
||||
| kittycad::types::ModelingCmd::EntityCircularPattern { .. }
|
||||
| kittycad::types::ModelingCmd::Solid3DGetExtrusionFaceInfo { .. }) = cmd
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl EngineManager for EngineConnection {
|
||||
async fn send_modeling_cmd(
|
||||
&self,
|
||||
flush_batch: bool,
|
||||
id: uuid::Uuid,
|
||||
source_range: crate::executor::SourceRange,
|
||||
cmd: kittycad::types::ModelingCmd,
|
||||
) -> Result<OkWebSocketResponseData, KclError> {
|
||||
let req = WebSocketRequest::ModelingCmdReq {
|
||||
cmd: cmd.clone(),
|
||||
cmd_id: id,
|
||||
};
|
||||
|
||||
println!("req {:?}", req);
|
||||
|
||||
if !flush_batch {
|
||||
self.batch.lock().unwrap().push(req);
|
||||
}
|
||||
|
||||
// If the batch only has this one command that expects a return value,
|
||||
// fire it right away, or if we want to flush batch queue.
|
||||
let is_sending = (is_cmd_with_return_values(&cmd) && self.batch.lock().unwrap().len() == 1)
|
||||
|| flush_batch
|
||||
|| is_cmd_with_return_values(&cmd);
|
||||
|
||||
// Return a fake modeling_request empty response.
|
||||
if !is_sending {
|
||||
println!("fake {:?}", cmd);
|
||||
return Ok(OkWebSocketResponseData::Modeling {
|
||||
modeling_response: kittycad::types::OkModelingCmdResponse::Empty {}
|
||||
});
|
||||
}
|
||||
|
||||
let batched_requests =
|
||||
WebSocketRequest::ModelingCmdBatchReq {
|
||||
requests: self.batch.lock().unwrap().iter().fold(vec![], |mut acc, val| {
|
||||
let WebSocketRequest::ModelingCmdReq { cmd, cmd_id } = val else { return acc; };
|
||||
acc.push(kittycad::types::ModelingCmdReq {
|
||||
cmd: cmd.clone(),
|
||||
cmd_id: *cmd_id,
|
||||
});
|
||||
acc
|
||||
}),
|
||||
batch_id: uuid::Uuid::new_v4()
|
||||
};
|
||||
|
||||
let final_req = if self.batch.lock().unwrap().len() == 1 {
|
||||
self.batch.lock().unwrap().get(0).unwrap().clone()
|
||||
} else {
|
||||
batched_requests
|
||||
};
|
||||
|
||||
// Throw away the old batch queue.
|
||||
self.batch.lock().unwrap().clear();
|
||||
|
||||
println!("final req {:?}", final_req);
|
||||
|
||||
// We pop off the responses to cleanup our mappings.
|
||||
let id_final = match final_req {
|
||||
WebSocketRequest::ModelingCmdBatchReq { requests: _, batch_id } => batch_id,
|
||||
WebSocketRequest::ModelingCmdReq { cmd: _, cmd_id } => cmd_id,
|
||||
_ => panic!("should not be possible"),
|
||||
};
|
||||
|
||||
let (tx, rx) = oneshot::channel();
|
||||
|
||||
// Send the request to the engine, via the actor.
|
||||
self.engine_req_tx
|
||||
.send(ToEngineReq {
|
||||
req: final_req.clone(),
|
||||
req: WebSocketRequest::ModelingCmdReq {
|
||||
cmd: cmd.clone(),
|
||||
cmd_id: id,
|
||||
},
|
||||
request_sent: tx,
|
||||
})
|
||||
.await
|
||||
@ -310,7 +200,6 @@ impl EngineManager for EngineConnection {
|
||||
})
|
||||
})?;
|
||||
|
||||
|
||||
// Wait for the response.
|
||||
let current_time = std::time::Instant::now();
|
||||
while current_time.elapsed().as_secs() < 60 {
|
||||
@ -322,9 +211,8 @@ impl EngineManager for EngineConnection {
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((_, resp)) = self.responses.remove(&id_final) {
|
||||
println!("RESP {:?}", resp);
|
||||
// We pop off the responses to cleanup our mappings.
|
||||
if let Some((_, resp)) = self.responses.remove(&id) {
|
||||
return if let Some(data) = &resp.resp {
|
||||
Ok(data.clone())
|
||||
} else {
|
||||
@ -337,7 +225,7 @@ impl EngineManager for EngineConnection {
|
||||
}
|
||||
|
||||
Err(KclError::Engine(KclErrorDetails {
|
||||
message: format!("Modeling command timed out `{}`", id_final),
|
||||
message: format!("Modeling command timed out `{}`", id),
|
||||
source_ranges: vec![source_range],
|
||||
}))
|
||||
}
|
||||
|
@ -19,7 +19,6 @@ impl EngineConnection {
|
||||
impl crate::engine::EngineManager for EngineConnection {
|
||||
async fn send_modeling_cmd(
|
||||
&self,
|
||||
_flush_batch: bool,
|
||||
_id: uuid::Uuid,
|
||||
_source_range: crate::executor::SourceRange,
|
||||
_cmd: kittycad::types::ModelingCmd,
|
||||
|
@ -13,7 +13,6 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
|
||||
/// Send a modeling command and wait for the response message.
|
||||
async fn send_modeling_cmd(
|
||||
&self,
|
||||
flush_batch: bool,
|
||||
id: uuid::Uuid,
|
||||
source_range: crate::executor::SourceRange,
|
||||
cmd: kittycad::types::ModelingCmd,
|
||||
|
@ -1008,7 +1008,6 @@ pub async fn execute(
|
||||
// Before we even start executing the program, set the units.
|
||||
ctx.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::SetSceneUnits {
|
||||
@ -1220,17 +1219,6 @@ pub async fn execute(
|
||||
}
|
||||
}
|
||||
|
||||
// Fire the batch since we've reached the end.
|
||||
// ctx.engine
|
||||
// .send_modeling_cmd(
|
||||
// true,
|
||||
// uuid::Uuid::new_v4(),
|
||||
// SourceRange::default(),
|
||||
// // This is ignored when flush_batch is true.
|
||||
// kittycad::types::ModelingCmd::EditModeExit {},
|
||||
// )
|
||||
// .await?;
|
||||
|
||||
Ok(memory.clone())
|
||||
}
|
||||
|
||||
|
@ -206,7 +206,7 @@ impl Args {
|
||||
id: uuid::Uuid,
|
||||
cmd: kittycad::types::ModelingCmd,
|
||||
) -> Result<OkWebSocketResponseData, KclError> {
|
||||
self.ctx.engine.send_modeling_cmd(false, id, self.source_range, cmd).await
|
||||
self.ctx.engine.send_modeling_cmd(id, self.source_range, cmd).await
|
||||
}
|
||||
|
||||
fn make_user_val_from_json(&self, j: serde_json::Value) -> Result<MemoryItem, KclError> {
|
||||
|
@ -21,9 +21,9 @@ async fn execute_and_snapshot(code: &str, units: kittycad::types::UnitLength) ->
|
||||
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
|
||||
|
||||
// Create the client.
|
||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
// uncomment to use a local server
|
||||
client.set_base_url("http://localhost:8080/");
|
||||
//client.set_base_url("http://system76-pc:8080/");
|
||||
|
||||
let ws = client
|
||||
.modeling()
|
||||
@ -45,7 +45,6 @@ async fn execute_and_snapshot(code: &str, units: kittycad::types::UnitLength) ->
|
||||
|
||||
ctx.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
kcl_lib::executor::SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::DefaultCameraLookAt {
|
||||
@ -61,7 +60,6 @@ async fn execute_and_snapshot(code: &str, units: kittycad::types::UnitLength) ->
|
||||
let resp = ctx
|
||||
.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
kcl_lib::executor::SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::TakeSnapshot {
|
||||
|
@ -49,7 +49,6 @@ async fn setup(code: &str, name: &str) -> Result<(ExecutorContext, Program, uuid
|
||||
let plane_id = uuid::Uuid::new_v4();
|
||||
ctx.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
plane_id,
|
||||
SourceRange::default(),
|
||||
ModelingCmd::MakePlane {
|
||||
@ -68,7 +67,6 @@ async fn setup(code: &str, name: &str) -> Result<(ExecutorContext, Program, uuid
|
||||
// You can however get path info without sketch mode.
|
||||
ctx.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
SourceRange::default(),
|
||||
ModelingCmd::SketchModeEnable {
|
||||
@ -84,7 +82,6 @@ async fn setup(code: &str, name: &str) -> Result<(ExecutorContext, Program, uuid
|
||||
// We can't get control points of an existing sketch without being in edit mode.
|
||||
ctx.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
SourceRange::default(),
|
||||
ModelingCmd::EditModeEnter { target: sketch_id },
|
||||
|
Reference in New Issue
Block a user