Skip to content

Commit

Permalink
Merge pull request #10 from x0k/rust
Browse files Browse the repository at this point in the history
Rust
  • Loading branch information
x0k authored Jun 30, 2024
2 parents f550a0d + 605769e commit 449f2f1
Show file tree
Hide file tree
Showing 73 changed files with 1,107 additions and 31 deletions.
1 change: 1 addition & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
use flake
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*.wasm filter=lfs diff=lfs merge=lfs -text
*.rlib filter=lfs diff=lfs merge=lfs -text
*.so filter=lfs diff=lfs merge=lfs -text
6 changes: 0 additions & 6 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,6 @@ jobs:
node-version: 20
cache: pnpm

- uses: actions/setup-go@v5
with:
go-version-file: 'packages/testing-go/go/go.mod'
cache-dependency-path: |
packages/testing-go/go/go.sum
- name: Install dependencies
run: pnpm install

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pnpm-debug.log*
# environment variables
.env
.env.production
.direnv

# macOS-specific files
.DS_Store
Expand Down
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[submodule "packages/testing-rust/rust"]
path = packages/testing-rust/rust
url = https://github.com/bjorn3/rust
branch = compile_rustc_for_wasm15
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,21 @@
# Programming Patterns Practice

## Development

Clone the repository:

```
git clone https://github.com/x0k/ppp.git
git submodule update --init
````
The artifacts saved in the repository must be created in the nix development environment.
```console
nix develop
mk a/build
```

## See also

- Simple build automation tool [mk](https://github.com/x0k/mk)
2 changes: 1 addition & 1 deletion apps/ppp/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default defineConfig({
external: ["sharp"],
},
},
assetsInclude: ["**/*.wasm", "**/*.zip"],
assetsInclude: ["**/*.wasm", "**/*.zip", "**/*.rlib", "**/*.so"],
},
markdown: {
shikiConfig: {
Expand Down
3 changes: 2 additions & 1 deletion apps/ppp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
"testing-javascript": "workspace:*",
"testing-php": "workspace:*",
"testing-python": "workspace:*",
"testing-typescript": "workspace:*"
"testing-typescript": "workspace:*",
"testing-rust": "workspace:*"
},
"devDependencies": {
"@iconify-json/lucide": "^1.1.191",
Expand Down
1 change: 1 addition & 0 deletions apps/ppp/src/adapters/monaco.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export const MONACO_LANGUAGE_ID: Record<Language, string> = {
[Language.JavaScript]: "javascript",
[Language.Python]: "python",
[Language.Go]: "go",
[Language.Rust]: "rust",
};
2 changes: 2 additions & 0 deletions apps/ppp/src/adapters/workers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import TsWorkerDescription from "./ts-worker-description.svelte";
import PhpWorkerDescription from "./php-worker-description.svelte";
import PyWorkerDescription from "./python-worker-description.svelte";
import GoWorkerDescription from "./go-worker-description.svelte";
import RustWorkerDescription from "./rust-worker-description.svelte";

export const WORKER_DESCRIPTIONS: Record<
Language,
Expand All @@ -17,4 +18,5 @@ export const WORKER_DESCRIPTIONS: Record<
[Language.PHP]: PhpWorkerDescription,
[Language.Python]: PyWorkerDescription,
[Language.Go]: GoWorkerDescription,
[Language.Rust]: RustWorkerDescription,
};
38 changes: 38 additions & 0 deletions apps/ppp/src/adapters/workers/rust-worker-description.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<script lang="ts">
import { version } from "testing-rust/version";
</script>

<p>
Rust {version}
</p>

<p>
Your code is interpreted by <a
href="https://github.com/rust-lang/miri"
class="link"
target="_blank">Miri</a
> (compiled to WebAssembly) in a web worker environment.
</p>

<p>Anything not supported by Miri or WASM is unsupported.</p>

<p>
This solution is based on <a
class="link"
href="https://github.com/bjorn3"
target="_blank">bjorn3</a
>
work on
<a
class="link"
target="_blank"
href="https://github.com/rust-lang/miri/issues/722#issuecomment-1960849880"
>porting Rust to WebAssembly</a
>
and
<a
href="https://github.com/bjorn3/browser_wasi_shim"
class="link"
target="_blank">browser WASI shim</a
>.
</p>
1 change: 1 addition & 0 deletions apps/ppp/src/components/editor/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ export const LANG_ICONS: Record<Language, string> = {
[Language.TypeScript]: "simple-icons:typescript",
[Language.Go]: "simple-icons:go",
[Language.PHP]: "simple-icons:php",
[Language.Rust]: "simple-icons:rust",
};
2 changes: 2 additions & 0 deletions apps/ppp/src/components/svelte-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
PhpWorker,
PyWorker,
TsWorker,
RustWorker,
} from "@/lib/workers";
import { Language } from "@/shared/languages";
import Editor, {
Expand All @@ -26,6 +27,7 @@ export const LANG_WORKERS: Record<Language, new () => Worker> = {
[Language.Python]: PyWorker,
[Language.TypeScript]: TsWorker,
[Language.JavaScript]: JsWorker,
[Language.Rust]: RustWorker,
};

export function mountEditor<L extends Language, I, O>(
Expand Down
5 changes: 5 additions & 0 deletions apps/ppp/src/content/design-patterns/factory/editor.astro
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const { contentId } = Astro.props;
import { phpCode, phpFactory } from "./php";
import { pyCode, pyFactory } from "./python";
import { goCode, goFactory } from "./go";
import { rustCode, rustFactory } from './rust'

mountEditor(testsData, {
[Language.JavaScript]: {
Expand All @@ -40,5 +41,9 @@ const { contentId } = Astro.props;
initialValue: goCode,
factory: goFactory,
},
[Language.Rust]: {
initialValue: rustCode,
factory: rustFactory,
}
});
</script>
2 changes: 0 additions & 2 deletions apps/ppp/src/content/design-patterns/factory/php/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import type { UniversalFactory } from "testing/actor";
import type { UniversalFactoryData } from "@/lib/workers/php";

import type { Input, Output } from "../tests-data";

// Const enum import is allowed
import type { PaymentSystemType } from "../reference";

export const factory: UniversalFactory<
Expand Down
14 changes: 14 additions & 0 deletions apps/ppp/src/content/design-patterns/factory/rust/code.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
enum PaymentSystemType {
PayPal,
WebMoney,
CatBank,
}






fn payment(tp: PaymentSystemType, base: isize, amount: isize) -> isize {

}
31 changes: 31 additions & 0 deletions apps/ppp/src/content/design-patterns/factory/rust/factory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Only type imports are allowed
import type { UniversalFactory } from "testing/actor";

import type { RustUniversalFactoryData } from "@/lib/workers/rust";

import type { Input, Output } from "../tests-data";
import type { PaymentSystemType } from "../reference";

export const factory: UniversalFactory<
Input,
Output,
RustUniversalFactoryData<Input, Output>
> = ({ makeTestRunnerFactory }) => {
const RUST_PAYMENT_SYSTEM_TYPES: Record<PaymentSystemType, string> = {
paypal: "PaymentSystemType::PayPal",
webmoney: "PaymentSystemType::WebMoney",
"cat-bank": "PaymentSystemType::CatBank",
};
return makeTestRunnerFactory(
({ paymentSystem, amount, base }) =>
`let str = payment(${RUST_PAYMENT_SYSTEM_TYPES[paymentSystem]}, ${base}, ${amount}).to_string();
let output_content = str.as_bytes();`,
(result) => {
const r = parseInt(result, 10);
if (isNaN(r)) {
throw new Error(`Invalid result type: ${result}, expected number`);
}
return r;
}
);
};
2 changes: 2 additions & 0 deletions apps/ppp/src/content/design-patterns/factory/rust/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as rustCode } from "./code.rs?raw";
export { factory as rustFactory } from "./factory";
1 change: 1 addition & 0 deletions apps/ppp/src/lib/workers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export { default as TsWorker } from "./ts?worker";
export { default as PhpWorker } from "./php?worker";
export { default as PyWorker } from "./python?worker";
export { default as GoWorker } from "./go?worker";
export { default as RustWorker } from "./rust?worker";
77 changes: 77 additions & 0 deletions apps/ppp/src/lib/workers/rust.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import type { TestRunnerFactory } from "testing";
import { startTestRunnerActor } from "testing/actor";
import { RustTestRunner, wasiRuntimeFactory } from "testing-rust";

// @ts-expect-error .wasm is an asset
import miriWasmUrl from "testing-rust/miri.wasm";
import { COLOR } from "libs/logger";
import type { Context } from "libs/context";

const libsUrls = import.meta.glob("/node_modules/testing-rust/dist/lib/*", {
eager: true,
import: "default",
}) as Record<string, string>;

export interface RustUniversalFactoryData<I, O> {
RustTestRunner: typeof RustTestRunner;
wasiRuntimeFactory: typeof wasiRuntimeFactory;
makeTestRunnerFactory: (
generateOutputContentCode: (input: I) => string,
transformResult: (result: string) => O
) => TestRunnerFactory<I, O>;
}

// TODO: manual cache for large assets
function loadLibs(ctx: Context) {
return Promise.all(
Object.entries(libsUrls).map(async ([lib, url]) => {
const response = await fetch(url, {
signal: ctx.signal,
cache: "force-cache",
});
const buffer = await response.arrayBuffer();
return [lib.slice(36), buffer] as [string, ArrayBuffer];
})
);
}

startTestRunnerActor<
unknown,
unknown,
RustUniversalFactoryData<unknown, unknown>
>((universalFactory) =>
universalFactory({
RustTestRunner,
wasiRuntimeFactory,
makeTestRunnerFactory: (generateOutputContentCode, transformResult) => {
class TestRunner extends RustTestRunner<unknown, unknown> {
protected override generateOutputContentCode(input: unknown): string {
return generateOutputContentCode(input);
}
protected override transformResult(data: string): unknown {
return transformResult(data);
}
}
return async (ctx, { code, out }) =>
new TestRunner(
code,
wasiRuntimeFactory(
out,
{
write(text) {
out.write(`${COLOR.ERROR}${text}${COLOR.RESET}`);
},
writeln(text) {
out.writeln(`${COLOR.ERROR}${text}${COLOR.RESET}`);
},
},
await loadLibs(ctx)
),
await WebAssembly.compileStreaming(
fetch(miriWasmUrl, { signal: ctx.signal, cache: "force-cache" })
),
"case_output"
);
},
})
);
2 changes: 2 additions & 0 deletions apps/ppp/src/shared/languages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export enum Language {
TypeScript = "typescript",
JavaScript = "javascript",
Go = "go",
Rust = "rust",
}

export const LANGUAGE_TITLE: Record<Language, string> = {
Expand All @@ -12,4 +13,5 @@ export const LANGUAGE_TITLE: Record<Language, string> = {
[Language.Python]: "Python",
[Language.JavaScript]: "JavaScript",
[Language.Go]: "Go",
[Language.Rust]: "Rust",
};
62 changes: 62 additions & 0 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 449f2f1

Please sign in to comment.