{"id":18031761,"url":"https://github.com/dagronf/dsfvaluestream","last_synced_at":"2025-10-19T13:02:31.570Z","repository":{"id":149491979,"uuid":"340294156","full_name":"dagronf/DSFValueStream","owner":"dagronf","description":"Generate a stream of values over time","archived":false,"fork":false,"pushed_at":"2021-02-19T08:06:35.000Z","size":10,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-10T06:25:12.765Z","etag":null,"topics":["combine","random","stream-processing","swift"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dagronf.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-02-19T07:43:00.000Z","updated_at":"2021-03-23T21:39:03.000Z","dependencies_parsed_at":"2023-05-01T05:19:27.570Z","dependency_job_id":null,"html_url":"https://github.com/dagronf/DSFValueStream","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dagronf%2FDSFValueStream","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dagronf%2FDSFValueStream/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dagronf%2FDSFValueStream/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dagronf%2FDSFValueStream/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dagronf","download_url":"https://codeload.github.com/dagronf/DSFValueStream/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247256072,"owners_count":20909240,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["combine","random","stream-processing","swift"],"created_at":"2024-10-30T10:10:42.365Z","updated_at":"2025-10-19T13:02:31.501Z","avatar_url":"https://github.com/dagronf.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# DSFValueStream\n\nGenerate a stream of values\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/v/tag/dagronf/DSFValueStream\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/macOS-10.12+-red\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/iOS-12.0+-blue\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/tvOS-12.0+-orange\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/SwiftUI-1.0+-green\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/macCatalyst-1.0+-purple\" /\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Swift-5.0-orange.svg\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/License-MIT-lightgrey\" /\u003e\n    \u003ca href=\"https://swift.org/package-manager\"\u003e\n        \u003cimg src=\"https://img.shields.io/badge/spm-compatible-brightgreen.svg?style=flat\" alt=\"Swift Package Manager\" /\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\n## Why\n\nI had some tests and some demo projects that needed controllable streams of 'random' values of different types.\n\nI wrote these class to try to abstract and centralize the generation logic.  I was also keen to spend some more time playing with Combine.\n\n## TL;DR Show me something!\n\n```swift\n\n// Create a timed generator that emits a random Int value in the range 0 ... 100 every 10 seconds\nvar intValueGenerator = DSFTimedValueGenerator(\n   generator: DSFValueSourceType.Int(0 ... 100))\n)\n\n// Start the int timer and do something with the stream\nself.intValueGenerator.start(interval: 10) { (value) in\n   Swift.print(\"new integer value is \\(value)\")\n}\n\n/////\n\n// Create a gated generator that emits a random word whenever it is triggered\nlet wordStream = DSFGatedValueStream(\n   DSFValueSourceType.ArraySource(values: [\"Sphinx\",\"of\",\"black\",\"quartz\",\"judge\",\"my\",\"vow\"],\n                                  type: .random)\n)\nwordStream.actionBlock = { value in\n   Swift.print(value)\n}\n...\n\n// Trigger the stream's action block with a new value\nwordStream.trigger()\n\n\n```\n\n\n## Overview\n\nThis library has two main concepts\n\n### A source generates a value\n\nA source generates a single value in response to a call.  This value is entirely dependent on the source - it might be purely random, or maybe iterative over an array of stored values.\n\nThere are a number of built-in source types\n\n* A random source generates a random value within a specified range.\n* An incremental source increments its internal value every time it emits a value.\n\n1. Random Double value (`DSFValueSourceType.DoubleSource`)\n2. Random Int value (`DSFValueSourceType.IntSource`)\n3. Random Bool value (`DSFValueSourceType.BoolSource`)\n4. Random CGFloat value (`DSFValueSourceType.CGFloatSource`)\n5. Random Array member value (`DSFValueSourceType.ArraySource\u003cSOME_TYPE\u003e`)\n6. Incremental Array member value (`DSFValueSourceType.ArraySource\u003cSOME_TYPE\u003e`)\n7. Incremental CGFloat values along a sine wave (`DSFValueSourceType.SineWaveSource`)\n\nIt is quite straight forward to write your own source if needed.\n\n### A generator or publisher uses a source to generate a stream of values\n\nThe generator is provided a source which is then used to generate a stream of values. Currently there are two types of generator.\n\n1. A timed generator which emits a new value on a scheduled interval.\n2. A gated generator which emits a new value when the generator is triggered.\n\n## Generators\n\n### Timed\n\nA value generator that emits a new value on a time interval\n\n#### DSFTimedValueGenerator\n\n```swift\nvar doubleValueGenerator = DSFTimedValueGenerator(\n   generator: DSFValueSourceType.DoubleSource(-100 ... 100)\n)\n\nvar intValueGenerator = DSFTimedValueGenerator(\n   generator: DSFValueSourceType.Int(0 ... 100)\n)\n\nfunc startGenerating() {\n   // Print a random value between -100 and 100 every second\n   self.doubleValueGenerator.start(interval: 1) { (value) in\n      Swift.print(\"new double value is \\(value)\")\n   }\n\n   self.intValueGenerator.start(interval: 10) { (value) in\n      Swift.print(\"new integer value is \\(value)\")\n   }\n}\n```\n\n#### DSFTimedValuePublisher (Combine)\n\n```swift\nlet randomIntegerPublisher = DSFTimedValuePublisher(DSFValueSourceType.IntSource())\n\n// Start the publisher generating values\nrandomIntegerPublisher.start(interval: 0.2)\n\n// Hook a subscriber up to the publisher\ncancellable = randomIntegerPublisher.publisher\n   .sink { value in\n      Swift.print(\"Combine = \\(value)\")\n   }\n```\n\n### Gated\n\nA gated generator emits a new value from the generated whenever it is triggered.\n\n#### DSFGatedValueGenerator\n\n```swift\nlet generator = DSFGatedValueGenerator(\n   DSFValueSourceType.ArraySource(values: values, type: .increment))\n   \ngenerator.actionBlock = { value in\n   Swift.print(\"newValue is \\(value)\")\n}\n\n...\n\ngenerator.gate()           // generate a single value\ngenerator.gate(count: 10)  // generate 10 values\n```\n\n### DSFGatedValuePublisher (Combine)\n\n```swift\nlet randomIntegerPublisher = DSFGatedValuePublisher(DSFValueSourceType.IntSource())\n\n// Hook a subscriber up to the publisher\ncancellable = randomIntegerPublisher.publisher\n   .sink { value in\n      Swift.print(\"Combine = \\(value)\")\n   }\n   \n   ...\n   \nrandomIntegerPublisher.gate()\n```\n## License\n\n```\nMIT License\n\nCopyright (c) 2021 Darren Ford\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdagronf%2Fdsfvaluestream","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdagronf%2Fdsfvaluestream","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdagronf%2Fdsfvaluestream/lists"}